Files
2026-01-23 17:03:45 +08:00

1206 lines
34 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004-2009, University in Hagen, Faculty of Mathematics
and Computer Science, Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
1 MPoints.h
*/
#pragma once
#include <memory>
#include "MObjects.h"
#include "Algebras/CRel/Ints.h"
#include "DefTimes.h"
#include "IPoints.h"
#include "MPointsData.h"
#include "Grid.h"
#include "MBools.h"
#include <chrono>
namespace ColumnMovingAlgebra
{
/*
1.1 Declaration of the class ~MPoints~
~MPoints~ represents a moving point attribute array.
*/
class MPoints : public MObjects
{
public:
/*
1.1.1 Constructors
The following constructor signatures are required by the crel algebra for all
attribute arrays.
*/
MPoints();
MPoints(CRelAlgebra::Reader& source);
MPoints(CRelAlgebra::Reader& source, uint64_t rowsCount);
MPoints(const MPoints &array,
const CRelAlgebra::SharedArray<const uint64_t> &filter);
/*
1.1.2 Destructor
*/
virtual ~MPoints() { }
/*
1.1.3 CRel Algebra Interface
the following functions are required by the crel algebra for all attribute
arrays.
~Filter~ returns a duplicate of this attribut array with the speficied filter.
*/
virtual AttrArray* Filter(CRelAlgebra::SharedArray<const uint64_t>
filter) const;
/*
~GetCount~ returns the number of entries in the attribut array.
*/
virtual uint64_t GetCount() const;
/*
~GetSize~ returns the amount of space needed to save this attribut array
to persistant storage.
*/
virtual uint64_t GetSize() const;
/*
~GetAttribute~ converts the moving point
in ~row~ to an MPoint as defined in the temporal algebra for row oriented
relations and returns it.
*/
virtual Attribute *GetAttribute(uint64_t row, bool clone = true) const;
/*
~Save~ saves this attribut array
to persistant storage.
*/
virtual void Save(CRelAlgebra::Writer &target,
bool includeHeader = true) const;
/*
~Append~ adds the moving point at index ~row~ of the attribut array ~array~
*/
virtual void Append(const CRelAlgebra::AttrArray & array, uint64_t row);
/*
or adds the row orientied MPoint ~value~
*/
virtual void Append(Attribute & value);
/*
~Remove~ removes the last added moving point
*/
virtual void Remove();
/*
~Clear~ removes all moving points
*/
virtual void Clear();
/*
~IsDefined~ returns true, iff the moving point with index ~row~ has any units
*/
virtual bool IsDefined(uint64_t row) const;
/*
~Compare~ compares the moving point at index ~rowA~ with the moving point
at index ~rowB~ in ~arrayB~
*/
virtual int Compare(uint64_t rowA, const AttrArray& arrayB,
uint64_t rowB) const;
/*
~Compare~ compares the moving point at index ~rowA~ with the row oriented
attribute ~value~
*/
virtual int Compare(uint64_t row, Attribute &value) const;
/*
~GetHash~ returns a hash value for the moving point at index ~row~
*/
virtual uint64_t GetHash(uint64_t row) const;
/*
1.1.2 Operators
The following functions implement the operators supported by moving points
attribute array. The operators atinstant, atperiods, passes and at are
implemented in two versions for moving point attribute arrays with and
without a grid index.
~atInstant~ is a timeslice operator and computes an intime for all
moving points in the attribute array and adds them to ~result~
*/
void atInstant(Instant instant, IPoints & result);
void atInstantIndexed(Instant instant, IPoints & result);
/*
~atPeriods~ restricts the moving points to a given set of time
intervals and adds the resulting units to ~result~.
*/
void atPeriods(temporalalgebra::Periods periods, MPoints & result);
void atPeriodsIndexed(temporalalgebra::Periods periods, MPoints & result);
/*
~passes~ adds the indices of all moving points to ~result~, which
ever assume the specified value or intersect the specified region.
*/
void passes(Point & value, CRelAlgebra::LongInts & result);
void passesIndexed(Point & value, CRelAlgebra::LongInts & result);
void passes(Region & value, CRelAlgebra::LongInts & result);
void passesIndexed(Region & value, CRelAlgebra::LongInts & result);
/*
~at~ restricts the all moving points to the specified value or
the specified region. the computed new units are added to ~result~
*/
void at(Point & value, MPoints & result);
void atIndexed(Point & value, MPoints & result);
void at(Region & value, MPoints & result);
void atIndexed(Region & value, MPoints & result);
/*
~addRandomUnits~ adds random units to every moving point
*/
void addRandomUnits(CcInt& size, MPoints & result);
/*
~index~ creates a new moving points attribute array with a grid index.
the index will cover the rectangular region specified by ~xMin~, ~xMax~,
~yMin~ and ~yMax~ and covers the time interval from ~tMin~ to ~tMax~. The
created grid is an infinite grid, so it will also index units which are
not within these boundaries, but this will be ineffective in most cases.
The number of grid cells in each dimension is determined by ~xSplits~,
~ySplits~ and ~tSplits~.
*/
void index(CcReal& xMin, CcReal& xMax, CcInt& xSplits,
CcReal& yMin, CcReal& yMax, CcInt& ySplits,
Instant& tMin, Instant& tMax,
CcInt& tSplits, MPoints & result);
/*
1.1.3 Data access
~addRow~ adds a new moving point to the attribute array
*/
void addRow();
/*
~addUnit~ adds a new unit to the last added moving point
*/
void addUnit(Interval interval, double x0, double y0,
double x1, double y1);
/*
~unitIterator~ returns an iterator over the units of the moving
point with index ~row~
*/
MPointsData::UnitIterator unitIterator(int row);
/*
~getDefTimeLimits~ returns the minimum start and maximum end of all
units of all moving points in this attribute array
*/
void getDefTimeLimits(int64_t &minimum, int64_t &maximum);
/*
1.1.4 Intersection of Definition Time
~defTimeIntersection~ is a helper function for the operator inside.
inside has a moving point operand and a moving region operand and
computes a moving boolean which is set to true respectively false
for all time intervals in which
the moving point is located inside respectively outside the moving region.
To compute this result inside first calls intersection on the two operands.
Then it calls ~defTimeIntersection~ on the moving point operand and uses
the result of intersection as parameter for ~defTimeIntersection~.
This function then performs an intersection on the definition times of
both moving points to calculate the result for inside.
*/
void defTimeIntersection(MPoints &subset, MBools &result);
private:
/*
1.1.5 Attributes
~GridEntry~ represents an entry in the grid index.
*/
struct GridEntry {
int row, unitId;
bool operator==(const GridEntry & b) const;
bool operator< (const GridEntry & b) const;
};
typedef Grid<3, 31, GridEntry> GridIndex;
/*
~mMPointsData~ represents the data of all moving points in this attribute
array.
*/
std::shared_ptr<MPointsData> m_MPointsData;
/*
~mMbr~ is the minimum bounding volume for all moving points in this attribute
array.
*/
GridIndex::Mbr m_Mbr;
/*
~mGridIndex~ represents the grid index of all units of all moving points.
It is set to null if the moving points attribut array has no index.
*/
std::shared_ptr<GridIndex> m_GridIndex;
};
/*
1.2 Implementation of the inline functions for class ~MPoints~
1.2.1 Constructors
The following constructor signatures are required by the crel algebra for all
attribute arrays.
*/
inline MPoints::MPoints() :
m_MPointsData(std::make_shared<MPointsData>())
{
}
inline MPoints::MPoints(CRelAlgebra::Reader& source)
{
m_MPointsData = std::make_shared<MPointsData>(source);
m_DefTimes = std::make_shared<DefTimes>(source);
source.ReadOrThrow(reinterpret_cast<char*>(&m_Mbr), sizeof(m_Mbr));
bool hasGrid;
source.ReadOrThrow(reinterpret_cast<char*>(&hasGrid), sizeof(bool));
if (hasGrid)
m_GridIndex = std::make_shared<GridIndex>(source);
}
inline MPoints::MPoints(CRelAlgebra::Reader& source, uint64_t rowsCount)
{
m_MPointsData = std::make_shared<MPointsData>(source);
m_DefTimes = std::make_shared<DefTimes>(source);
source.ReadOrThrow(reinterpret_cast<char*>(&m_Mbr), sizeof(m_Mbr));
bool hasGrid;
source.ReadOrThrow(reinterpret_cast<char*>(&hasGrid), sizeof(bool));
if (hasGrid)
m_GridIndex = std::make_shared<GridIndex>(source);
}
inline MPoints::MPoints(const MPoints &array,
const CRelAlgebra::SharedArray<const uint64_t> &filter) :
MObjects(array, filter),
m_MPointsData(array.m_MPointsData),
m_Mbr(array.m_Mbr),
m_GridIndex(array.m_GridIndex)
{
}
/*
1.2.2 Data access
~addRow~ adds a new moving point to the attribute array
*/
inline void MPoints::addRow()
{
m_MPointsData->addRow();
m_DefTimes->addRow();
if (m_GridIndex.get() != 0)
m_GridIndex->addRow();
}
/*
~addUnit~ adds a new unit to the last added moving point. The minimum bounding
volume of the attribute array is updated and the new unit is indexed if
the attribute array has a grid index.
*/
inline void MPoints::addUnit(Interval interval, double x0, double y0,
double x1, double y1)
{
GridIndex::Mbr mbr;
mbr.l[0] = std::min(x0, x1);
mbr.h[0] = std::max(x0, x1);
mbr.l[1] = std::min(y0, y1);
mbr.h[1] = std::max(y0, y1);
mbr.l[2] = static_cast<double>(interval.s);
mbr.h[2] = static_cast<double>(interval.e);
if (m_MPointsData->empty())
m_Mbr = mbr;
else
m_Mbr = m_Mbr.unite(mbr);
int unitId;
m_MPointsData->addUnit(interval, x0, y0, x1, y1, unitId);
m_DefTimes->addInterval(interval);
GridEntry e;
e.row = m_MPointsData->rowCount() - 1;
e.unitId = unitId;
if (m_GridIndex.get() != 0)
m_GridIndex->add(mbr, e);
}
/*
~unitIterator~ returns an iterator over the units of the moving
point with index ~row~
*/
inline MPointsData::UnitIterator MPoints::unitIterator(int row)
{
return m_MPointsData->unitIterator(row);
}
/*
~getDefTimeLimits~ returns the minimum start and maximum end of all
units of all moving points in this attribute array
*/
inline void MPoints::getDefTimeLimits(int64_t &minimum, int64_t &maximum)
{
m_DefTimes->getLimits(minimum, maximum);
}
/*
1.2.3 Intersection of Definition Time
~defTimeIntersection~ is a helper function for the operator inside.
inside has a moving point operand and a moving region operand and
computes a moving boolean which is set to true respectively false
for all time intervals in which
the moving point is located inside respectively outside the moving region.
To compute this result inside first calls intersection on the two operands.
Then it calls ~defTimeIntersection~ on the moving point operand and uses
the result of intersection as parameter for ~defTimeIntersection~.
This function then performs an intersection on the definition times of
both moving points to calculate the result for inside.
*/
inline void MPoints::defTimeIntersection(MPoints &subset, MBools &result)
{
checkr(m_DefTimes->rowCount() == subset.m_DefTimes->rowCount(),
"different number of mpoints");
for (int r = 0; r < m_DefTimes->rowCount(); r++) {
result.addMObject();
Interval ai(0,1,true,false), bi(0,1,true,false);
int aii = m_DefTimes->intervalFirst(r);
if (aii < m_DefTimes->intervalAfterLast(r))
ai = m_DefTimes->interval(aii);
int bii = subset.m_DefTimes->intervalFirst(r);
if (bii < subset.m_DefTimes->intervalAfterLast(r))
bi = subset.m_DefTimes->interval(bii);
while (aii < m_DefTimes->intervalAfterLast(r))
{
if (bii >= subset.m_DefTimes->intervalAfterLast(r) ||
ai.e < bi.s || (ai.e == bi.s && !ai.rc && bi.lc))
{
if (ai.s < ai.e || (ai.s == ai.e && ai.lc && ai.rc)) {
BoolUnit u(ai, false);
result.addUnit(u);
}
if (++aii < m_DefTimes->intervalAfterLast(r))
ai = m_DefTimes->interval(aii);
} else {
if (ai.s < bi.s || (ai.s == bi.s && ai.lc && !bi.lc)) {
BoolUnit u(Interval(ai.s, bi.s, ai.lc, !bi.lc), false);
result.addUnit(u);
}
BoolUnit u(bi, true);
result.addUnit(u);
ai.s = bi.e;
ai.lc = !bi.rc;
if (++bii < subset.m_DefTimes->intervalAfterLast(r))
bi = subset.m_DefTimes->interval(bii);
}
}
}
}
/*
1.1.4 Operators
The following functions implement the operators supported by moving points
attribute array. The operators atinstant, atperiods, passes and at are
implemented in two versions for moving point attribute arrays with and
without a grid index.
~atInstant~ is a timeslice operator and computes an intime for all
moving points in the attribute array and adds them to ~result~. The
actual algorithm is implemented in the class MPointsData
*/
inline void MPoints::atInstant(Instant instant, IPoints & result)
{
if (!instant.IsDefined()) {
for (size_t i = 0; i < GetFilter().GetCount(); i++)
result.Append(temporalalgebra::IPoint(0));
return;
}
if (m_GridIndex.get() != 0) {
atInstantIndexed(instant, result);
return;
}
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
MPointsData::Position p;
if (m_MPointsData->position(i, instant.millisecondsToNull(), p))
result.Append(temporalalgebra::IPoint(instant,
Point(true, p.x, p.y)));
else
result.Append(temporalalgebra::IPoint(0));
}
}
/*
~atInstantIndexed~ is the version of atinstant that uses the grid index.
*/
inline void MPoints::atInstantIndexed(Instant instant, IPoints & result)
{
typedef std::map<int, MPointsData::Position> RowMap;
typedef std::pair<int, MPointsData::Position> RowMapPair;
RowMap rows;
//first we construct a search volume
GridIndex::Mbr mbr = m_Mbr;
mbr.l[2] = mbr.h[2] = static_cast<double>(instant.millisecondsToNull());
//then we find all units within that volume with the help of the grid index
//for each unit we check for intersection with the instant
//the results are added to a map because we need them ordered
//by moving point index
for (auto & e : m_GridIndex->selection(mbr)) {
MPointsData::Unit u = m_MPointsData->unit(e.unitId);
if (u.interval.contains(instant.millisecondsToNull()))
rows.insert(RowMapPair(e.row, u.at(instant.millisecondsToNull())));
}
//now we can construct the result
std::map<int, MPointsData::Position>::iterator si = rows.begin();
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
while (si != rows.end() && si->first < i)
si++;
if (si != rows.end() && si->first == i)
result.Append(temporalalgebra::IPoint(instant,
Point(true, si->second.x, si->second.y)));
else
result.Append(temporalalgebra::IPoint(0));
}
}
/*
~atPeriods~ restricts the moving points to a given set of time
intervals and adds the resulting units to ~result~.
*/
inline void MPoints::atPeriods(temporalalgebra::Periods periods,
MPoints & result)
{
if (!periods.IsDefined() || periods.GetNoComponents() == 0) {
for (size_t i = 0; i < GetFilter().GetCount(); i++)
result.addRow();
return;
}
if (m_GridIndex.get() != 0) {
atPeriodsIndexed(periods, result);
return;
}
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
result.addRow();
//we perform a parallel scan on the given time intervals and the
//units of each moving point
temporalalgebra::Interval<Instant> period;
int iPeriod = 0;
bool periodValid = iPeriod < periods.GetNoComponents();
if (periodValid)
periods.Get(iPeriod, period);
temporalalgebra::UPoint upoint;
MPointsData::UnitIterator iUnit = m_MPointsData->unitIterator(i);
bool upointValid = iUnit.hasNext();
if (upointValid) {
MPointsData::Unit u = iUnit.next();
upoint = temporalalgebra::UPoint(u.interval.convert(),
u.x0, u.y0, u.x1, u.y1);
}
while (periodValid && upointValid) {
if (upoint.getTimeInterval().Intersects(period)) {
temporalalgebra::UPoint r;
upoint.AtInterval(period, r);
result.addUnit(r.timeInterval, r.p0.GetX(), r.p0.GetY(),
r.p1.GetX(), r.p1.GetY());
}
int64_t upointEnd = upoint.getTimeInterval().end.millisecondsToNull();
int64_t periodEnd = period.end.millisecondsToNull();
if ( periodEnd < upointEnd ||
(periodEnd == upointEnd && upoint.getTimeInterval().rc))
{
iPeriod++;
periodValid = iPeriod < periods.GetNoComponents();
if (periodValid)
periods.Get(iPeriod, period);
} else {
upointValid = iUnit.hasNext();
if (upointValid) {
MPointsData::Unit u = iUnit.next();
upoint = temporalalgebra::UPoint(u.interval.convert(),
u.x0, u.y0, u.x1, u.y1);
}
}
}
}
}
/*
~atPeriodsIndexed~ is the version of atperiods that uses the grid index.
*/
inline void MPoints::atPeriodsIndexed(temporalalgebra::Periods periods,
MPoints & result)
{
typedef std::map<int64_t, MPointsData::Unit> UnitMap;
typedef std::pair<int64_t, MPointsData::Unit> UnitMapPair;
typedef std::map<int, UnitMap> RowMap;
typedef std::pair<int, UnitMap> RowMapPair;
RowMap rows;
//first we construct a search volume
GridIndex::Mbr mbr = m_Mbr;
Instant instant;
periods.Minimum(instant);
mbr.l[2] = static_cast<double>(instant.millisecondsToNull());
periods.Maximum(instant);
mbr.h[2] = static_cast<double>(instant.millisecondsToNull());
//then we find all units within that volume with the help of the grid index
//for each unit we check for intersection with the periods
//the results are added to a map because we need them ordered
//by moving point index and time
for (auto & e : m_GridIndex->selection(mbr)) {
RowMap::iterator r = rows.find(e.row);
if (r == rows.end())
r = rows.insert(RowMapPair(e.row, UnitMap())).first;
MPointsData::Unit u = m_MPointsData->unit(e.unitId);
temporalalgebra::UPoint upoint(u.interval.convert(),
u.x0, u.y0, u.x1, u.y1);
for (int i = 0; i < periods.GetNoComponents(); i++) {
temporalalgebra::Interval<Instant> interval;
periods.Get(i, interval);
if (upoint.getTimeInterval().Intersects(interval)) {
temporalalgebra::UPoint result;
upoint.AtInterval(interval, result);
MPointsData::Unit unit(result.timeInterval,
result.p0.GetX(), result.p0.GetY(),
result.p1.GetX(), result.p1.GetY());
r->second.insert(UnitMapPair(
result.timeInterval.start.millisecondsToNull(), unit));
}
}
}
//now we can construct the result
RowMap::iterator si = rows.begin();
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
while (si != rows.end() && si->first < i)
si++;
result.addRow();
if (si != rows.end() && si->first == i)
for (auto & ui : si->second) {
MPointsData::Unit u = ui.second;
result.addUnit(u.interval, u.x0, u.y0, u.x1, u.y1);
}
}
}
/*
~passes~ adds the indices of all moving points to ~result~, which
ever assume the specified value.
*/
inline void MPoints::passes(Point & value, CRelAlgebra::LongInts & result)
{
result.Clear();
if (!value.IsDefined())
return;
if (m_GridIndex.get() != 0) {
passesIndexed(value, result);
return;
}
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
bool found = false;
MPointsData::UnitIterator iUnit = m_MPointsData->unitIterator(i);
while (iUnit.hasNext()) {
MPointsData::Unit unit = iUnit.next();
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
if (upoint.Passes(value)) {
found = true;
break;
}
}
if (found)
result.Append(i);
}
}
/*
~passesIndexed~ is the version of passes that uses the grid index.
*/
inline void MPoints::passesIndexed(Point & value,
CRelAlgebra::LongInts & result)
{
typedef std::set<int> Rows;
Rows rows;
//first we construct a search volume
GridIndex::Mbr mbr = m_Mbr;
mbr.l[0] = mbr.h[0] = value.GetX();
mbr.l[1] = mbr.h[1] = value.GetY();
//then we find all units within that volume with the help of the grid index
//for each unit we check for intersection with the value
//the results are added to a map because we need them ordered
//by moving point index
for (auto & e : m_GridIndex->selection(mbr)) {
MPointsData::Unit unit = m_MPointsData->unit(e.unitId);
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
if (upoint.Passes(value))
rows.insert(e.row);
}
//now we can construct the result
Rows::iterator si = rows.begin();
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
while (si != rows.end() && *si < i)
si++;
if (si != rows.end() && *si == i)
result.Append(i);
}
}
/*
~passes~ adds the indices of all moving points to ~result~, which
ever intersect the specified region.
*/
inline void MPoints::passes(Region & value, CRelAlgebra::LongInts & result)
{
result.Clear();
if (!value.IsDefined())
return;
if (m_GridIndex.get() != 0) {
passesIndexed(value, result);
return;
}
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
bool found = false;
MPointsData::UnitIterator iUnit = m_MPointsData->unitIterator(i);
while (iUnit.hasNext()) {
MPointsData::Unit unit = iUnit.next();
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
if (upoint.Passes(value)) {
found = true;
break;
}
}
if (found)
result.Append(i);
}
}
/*
~passesIndexed~ is the version of passes that uses the grid index.
*/
inline void MPoints::passesIndexed(Region & value,
CRelAlgebra::LongInts & result)
{
typedef std::set<int> Rows;
Rows rows;
//first we construct a search volume
GridIndex::Mbr mbr = m_Mbr;
Rectangle<2> rect = value.BoundingBox();
for (int i = 0; i < 2; i++) {
mbr.l[i] = rect.MinD(i);
mbr.h[i] = rect.MaxD(i);
}
//then we find all units within that volume with the help of the grid index
//for each unit we check for intersection with the region
//the results are added to a map because we need them ordered
//by moving point index
for (auto & e : m_GridIndex->selection(mbr)) {
MPointsData::Unit unit = m_MPointsData->unit(e.unitId);
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
if (upoint.Passes(value))
rows.insert(e.row);
}
//now we can construct the result
Rows::iterator si = rows.begin();
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
while (si != rows.end() && *si < i)
si++;
if (si != rows.end() && *si == i)
result.Append(i);
}
}
/*
~at~ restricts the all moving points to the specified value.
the computed new units are added to ~result~
*/
inline void MPoints::at(Point & value, MPoints & result)
{
if (!value.IsDefined()) {
for (size_t i = 0; i < GetFilter().GetCount(); i++)
result.addRow();
return;
}
if (m_GridIndex.get() != 0) {
atIndexed(value, result);
return;
}
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
result.addRow();
MPointsData::UnitIterator iUnit = m_MPointsData->unitIterator(i);
while (iUnit.hasNext()) {
MPointsData::Unit unit = iUnit.next();
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
temporalalgebra::UPoint r;
if (upoint.At(value, r))
result.addUnit(r.timeInterval, r.p0.GetX(), r.p0.GetY(),
r.p1.GetX(), r.p1.GetY());
}
}
}
/*
~atIndexed~ is the version of at that uses the grid index.
*/
inline void MPoints::atIndexed(Point & value, MPoints & result)
{
typedef std::map<int64_t, MPointsData::Unit> UnitMap;
typedef std::pair<int64_t, MPointsData::Unit> UnitMapPair;
typedef std::map<int, UnitMap> RowMap;
typedef std::pair<int, UnitMap> RowMapPair;
RowMap rows;
//first we construct a search volume
GridIndex::Mbr mbr = m_Mbr;
mbr.l[0] = mbr.h[0] = value.GetX();
mbr.l[1] = mbr.h[1] = value.GetY();
//then we find all units within that volume with the help of the grid index
//for each unit we check for intersection with the value
//the results are added to a map because we need them ordered
//by moving point index and time
for (auto & e : m_GridIndex->selection(mbr)) {
MPointsData::Unit unit = m_MPointsData->unit(e.unitId);
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
temporalalgebra::UPoint result;
if (upoint.At(value, result)) {
RowMap::iterator r = rows.find(e.row);
if (r == rows.end())
r = rows.insert(RowMapPair(e.row, UnitMap())).first;
MPointsData::Unit unit(result.timeInterval,
result.p0.GetX(), result.p0.GetY(),
result.p1.GetX(), result.p1.GetY());
r->second.insert(UnitMapPair(unit.interval.s, unit));
}
}
//now we can construct the result
RowMap::iterator si = rows.begin();
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
while (si != rows.end() && si->first < i)
si++;
result.addRow();
if (si != rows.end() && si->first == i) {
for (auto & ui : si->second) {
MPointsData::Unit u = ui.second;
result.addUnit(u.interval, u.x0, u.y0, u.x1, u.y1);
}
}
}
}
/*
~at~ restricts the all moving points to the specified
the specified region. the computed new units are added to ~result~
*/
inline void MPoints::at(Region & value, MPoints & result)
{
if (!value.IsDefined()) {
for (size_t i = 0; i < GetFilter().GetCount(); i++)
result.addRow();
return;
}
if (m_GridIndex.get() != 0) {
atIndexed(value, result);
return;
}
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
result.addRow();
MPointsData::UnitIterator iUnit = m_MPointsData->unitIterator(i);
while (iUnit.hasNext()) {
MPointsData::Unit unit = iUnit.next();
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
std::vector<temporalalgebra::UPoint> r;
upoint.AtRegion(&value, r);
for (auto & ir : r)
result.addUnit(ir.timeInterval,
ir.p0.GetX(), ir.p0.GetY(),
ir.p1.GetX(), ir.p1.GetY());
}
}
}
/*
~atIndexed~ is the version of at that uses the grid index.
*/
inline void MPoints::atIndexed(Region & value, MPoints & result)
{
typedef std::map<int64_t, MPointsData::Unit> UnitMap;
typedef std::pair<int64_t, MPointsData::Unit> UnitMapPair;
typedef std::map<int, UnitMap> RowMap;
typedef std::pair<int, UnitMap> RowMapPair;
RowMap rows;
//first we construct a search volume
GridIndex::Mbr mbr = m_Mbr;
Rectangle<2> rect = value.BoundingBox();
for (int i = 0; i < 2; i++) {
mbr.l[i] = rect.MinD(i);
mbr.h[i] = rect.MaxD(i);
}
//then we find all units within that volume with the help of the grid index
//for each unit we check for intersection with the region
//the results are added to a map because we need them ordered
//by moving point index and time
for (auto & e : m_GridIndex->selection(mbr)) {
MPointsData::Unit unit = m_MPointsData->unit(e.unitId);
temporalalgebra::UPoint upoint(unit.interval.convert(),
unit.x0, unit.y0, unit.x1, unit.y1);
std::vector<temporalalgebra::UPoint> intersection;
upoint.AtRegion(&value, intersection);
if (intersection.size() > 0) {
RowMap::iterator r = rows.find(e.row);
if (r == rows.end())
r = rows.insert(RowMapPair(e.row, UnitMap())).first;
for (auto & upoint : intersection) {
MPointsData::Unit unit(upoint.timeInterval,
upoint.p0.GetX(), upoint.p0.GetY(),
upoint.p1.GetX(), upoint.p1.GetY());
r->second.insert(UnitMapPair(unit.interval.s, unit));
}
}
}
//now we can construct the result
RowMap::iterator si = rows.begin();
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
while (si != rows.end() && si->first < i)
si++;
result.addRow();
if (si != rows.end() && si->first == i) {
for (auto & ui : si->second) {
MPointsData::Unit u = ui.second;
result.addUnit(u.interval, u.x0, u.y0, u.x1, u.y1);
}
}
}
}
/*
~index~ creates a new moving points attribute array with a grid index.
the index will cover the rectangular region specified by ~xMin~, ~xMax~,
~yMin~ and ~yMax~ and covers the time interval from ~tMin~ to ~tMax~. The
created grid is an infinite grid, so it will also index units which are
not within these boundaries, but this will be ineffective in most cases.
The number of grid cells in each dimension is determined by ~xSplits~,
~ySplits~ and ~tSplits~.
*/
inline void MPoints::index(CcReal& xMin, CcReal& xMax, CcInt& xSplits,
CcReal& yMin, CcReal& yMax, CcInt& ySplits,
Instant& tMin, Instant& tMax,
CcInt& tSplits, MPoints & result)
{
GridIndex::IVector splits;
splits.p[0] = xSplits.GetValue();
splits.p[1] = ySplits.GetValue();
splits.p[2] = tSplits.GetValue();
GridIndex::DVector min;
min.s[0] = xMin.GetValue();
min.s[1] = yMin.GetValue();
min.s[2] = static_cast<double>(tMin.millisecondsToNull());
GridIndex::DVector max;
max.s[0] = xMax.GetValue();
max.s[1] = yMax.GetValue();
max.s[2] = static_cast<double>(tMax.millisecondsToNull());
GridIndex::DVector delta = max - min, cellSize;
for (int i = 0; i < 3; i++) {
check(splits.p[i] >= 1, "the number of splits must be greater or equal "
"one.");
cellSize.s[i] = delta.s[i] / std::max(1, splits.p[i]);
}
result.m_GridIndex = std::make_shared<GridIndex>(min, cellSize, splits);
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
result.Append(*this, i);
}
}
/*
~addRandomUnits~ adds random units to every moving point
*/
inline void MPoints::addRandomUnits(CcInt& size, MPoints & result)
{
int64_t t0 = 0;
if (!m_MPointsData->empty()) {
t0 = (static_cast<int64_t>(m_Mbr.h[2] * 1.1) / MILLISECONDS + 1)
* MILLISECONDS;
}
for (auto & iterator : GetFilter()) {
int i = iterator.GetRow();
result.Append(*this, i);
if (!size.IsDefined())
continue;
int units = size.GetIntval();
double p[2], v[2];
int64_t t = t0;
for (int d = 0; d < 2; d++) {
p[d] = static_cast<double>(rand()) / RAND_MAX * 100.0;
v[d] = static_cast<double>(rand()) / RAND_MAX * 1.0;
}
for (int u = 0; u < units; u++) {
int64_t dt = (20 + (rand() % 5)) * MILLISECONDS;
result.addUnit(Interval(t, t + dt, true, false),
p[0], p[1], p[0] + v[0], p[1] + v[1]);
t += dt;
for (int d = 0; d < 2; d++) {
p[d] += v[d];
if (p[d] > 100.0)
v[d] = -static_cast<double>(rand()) / RAND_MAX * 1.0;
if (p[d] < 0.0)
v[d] = static_cast<double>(rand()) / RAND_MAX * 1.0;
}
}
}
}
/*
1.1.5 Implementation of Nested Class GridEntry
*/
inline bool MPoints::GridEntry::operator==(const GridEntry & b) const
{
return row == b.row && unitId == b.unitId;
}
inline bool MPoints::GridEntry::operator< (const GridEntry & b) const
{
if (row < b.row)
return true;
if (row > b.row)
return false;
return unitId < b.unitId;
}
}