/* ---- 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 #include "MObjects.h" #include "Algebras/CRel/Ints.h" #include "DefTimes.h" #include "IPoints.h" #include "MPointsData.h" #include "Grid.h" #include "MBools.h" #include 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 &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 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 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 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()) { } inline MPoints::MPoints(CRelAlgebra::Reader& source) { m_MPointsData = std::make_shared(source); m_DefTimes = std::make_shared(source); source.ReadOrThrow(reinterpret_cast(&m_Mbr), sizeof(m_Mbr)); bool hasGrid; source.ReadOrThrow(reinterpret_cast(&hasGrid), sizeof(bool)); if (hasGrid) m_GridIndex = std::make_shared(source); } inline MPoints::MPoints(CRelAlgebra::Reader& source, uint64_t rowsCount) { m_MPointsData = std::make_shared(source); m_DefTimes = std::make_shared(source); source.ReadOrThrow(reinterpret_cast(&m_Mbr), sizeof(m_Mbr)); bool hasGrid; source.ReadOrThrow(reinterpret_cast(&hasGrid), sizeof(bool)); if (hasGrid) m_GridIndex = std::make_shared(source); } inline MPoints::MPoints(const MPoints &array, const CRelAlgebra::SharedArray &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(interval.s); mbr.h[2] = static_cast(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 RowMap; typedef std::pair RowMapPair; RowMap rows; //first we construct a search volume GridIndex::Mbr mbr = m_Mbr; mbr.l[2] = mbr.h[2] = static_cast(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::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 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 UnitMap; typedef std::pair UnitMapPair; typedef std::map RowMap; typedef std::pair RowMapPair; RowMap rows; //first we construct a search volume GridIndex::Mbr mbr = m_Mbr; Instant instant; periods.Minimum(instant); mbr.l[2] = static_cast(instant.millisecondsToNull()); periods.Maximum(instant); mbr.h[2] = static_cast(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 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 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 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 UnitMap; typedef std::pair UnitMapPair; typedef std::map RowMap; typedef std::pair 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 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 UnitMap; typedef std::pair UnitMapPair; typedef std::map RowMap; typedef std::pair 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 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(tMin.millisecondsToNull()); GridIndex::DVector max; max.s[0] = xMax.GetValue(); max.s[1] = yMax.GetValue(); max.s[2] = static_cast(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(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(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(rand()) / RAND_MAX * 100.0; v[d] = static_cast(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(rand()) / RAND_MAX * 1.0; if (p[d] < 0.0) v[d] = static_cast(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; } }