libspatialindex API Reference  (git-trunk)
MovingRegion.cc
Go to the documentation of this file.
1 /******************************************************************************
2  * Project: libspatialindex - A C++ library for spatial indexing
3  * Author: Marios Hadjieleftheriou, mhadji@gmail.com
4  ******************************************************************************
5  * Copyright (c) 2004, Marios Hadjieleftheriou
6  *
7  * All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26 ******************************************************************************/
27 
28 /*
29  * Does not support degenerate time intervals or shrinking regions.
30 */
31 
32 
33 
34 #include <cstring>
35 #include <cmath>
36 #include <limits>
37 
39 
40 using namespace SpatialIndex;
41 
43  : TimeRegion()
44 {
45 }
46 
48  const double* pLow, const double* pHigh,
49  const double* pVLow, const double* pVHigh,
50  const IInterval& ivT, uint32_t dimension)
51 {
52  initialize(pLow, pHigh, pVLow, pVHigh, ivT.getLowerBound(), ivT.getUpperBound(), dimension);
53 }
54 
56  const double* pLow, const double* pHigh,
57  const double* pVLow, const double* pVHigh,
58  double tStart, double tEnd, uint32_t dimension)
59 {
60  initialize(pLow, pHigh, pVLow, pVHigh, tStart, tEnd, dimension);
61 }
62 
64  const Point& low, const Point& high,
65  const Point& vlow, const Point& vhigh,
66  const IInterval& ivT)
67 {
68  if (low.m_dimension != high.m_dimension || low.m_dimension != vlow.m_dimension || vlow.m_dimension != vhigh.m_dimension)
69  throw Tools::IllegalArgumentException("MovingRegion: arguments have different number of dimensions.");
70 
71  initialize(
72  low.m_pCoords, high.m_pCoords, vlow.m_pCoords, vhigh.m_pCoords,
73  ivT.getLowerBound(), ivT.getUpperBound(), low.m_dimension);
74 }
75 
77  const Point& low, const Point& high,
78  const Point& vlow, const Point& vhigh,
79  double tStart, double tEnd)
80 {
81  if (low.m_dimension != high.m_dimension || low.m_dimension != vlow.m_dimension || vlow.m_dimension != vhigh.m_dimension)
82  throw Tools::IllegalArgumentException("MovingRegion: arguments have different number of dimensions.");
83 
84  initialize(
85  low.m_pCoords, high.m_pCoords, vlow.m_pCoords, vhigh.m_pCoords,
86  tStart, tEnd, low.m_dimension);
87 }
88 
90  const Region& mbr, const Region& vbr, const IInterval& ivT)
91 {
92  if (mbr.m_dimension != vbr.m_dimension)
93  throw Tools::IllegalArgumentException("MovingRegion: arguments have different number of dimensions.");
94 
95  initialize(mbr.m_pLow, mbr.m_pHigh, vbr.m_pLow, vbr.m_pHigh, ivT.getLowerBound(), ivT.getUpperBound(), mbr.m_dimension);
96 }
97 
99  const Region& mbr, const Region& vbr, double tStart, double tEnd)
100 {
101  if (mbr.m_dimension != vbr.m_dimension)
102  throw Tools::IllegalArgumentException("MovingRegion: arguments have different number of dimensions.");
103 
104  initialize(mbr.m_pLow, mbr.m_pHigh, vbr.m_pLow, vbr.m_pHigh, tStart, tEnd, mbr.m_dimension);
105 }
106 
108 {
109  m_startTime = low.m_startTime;
110  m_endTime = high.m_endTime;;
111  m_dimension = low.m_dimension;
112  m_pLow = nullptr; m_pHigh = nullptr;
113  m_pVLow = nullptr; m_pVHigh = nullptr;
114 
115  if (m_endTime <= m_startTime) throw Tools::IllegalArgumentException("MovingRegion: Cannot support degenerate time intervals.");
116 
117  if (low.m_dimension != high.m_dimension) throw Tools::IllegalArgumentException("MovingRegion: arguments have different number of dimensions.");
118 
119  try
120  {
121  m_pLow = new double[m_dimension];
122  m_pHigh = new double[m_dimension];
123  m_pVLow = new double[m_dimension];
124  m_pVHigh = new double[m_dimension];
125 
126  }
127  catch (...)
128  {
129  delete[] m_pLow;
130  delete[] m_pHigh;
131  delete[] m_pVLow;
132  delete[] m_pVHigh;
133  throw;
134  }
135 
136  memcpy(m_pLow, low.m_pCoords, m_dimension * sizeof(double));
137  memcpy(m_pHigh, high.m_pCoords, m_dimension * sizeof(double));
138  memcpy(m_pVLow, low.m_pVCoords, m_dimension * sizeof(double));
139  memcpy(m_pVHigh, high.m_pVCoords, m_dimension * sizeof(double));
140 }
141 
143 {
145  m_endTime = r.m_endTime;
146  m_pLow = nullptr; m_pHigh = nullptr;
147  m_pVLow = nullptr; m_pVHigh = nullptr;
148 
150 
151  try
152  {
153  m_pLow = new double[m_dimension];
154  m_pHigh = new double[m_dimension];
155  m_pVLow = new double[m_dimension];
156  m_pVHigh = new double[m_dimension];
157  }
158  catch (...)
159  {
160  delete[] m_pLow;
161  delete[] m_pHigh;
162  delete[] m_pVLow;
163  delete[] m_pVHigh;
164  throw;
165  }
166 
167  memcpy(m_pLow, r.m_pLow, m_dimension * sizeof(double));
168  memcpy(m_pHigh, r.m_pHigh, m_dimension * sizeof(double));
169  memcpy(m_pVLow, r.m_pVLow, m_dimension * sizeof(double));
170  memcpy(m_pVHigh, r.m_pVHigh, m_dimension * sizeof(double));
171 }
172 
173 void MovingRegion::initialize(
174  const double* pLow, const double* pHigh,
175  const double* pVLow, const double* pVHigh,
176  double tStart, double tEnd, uint32_t dimension)
177 {
178  m_startTime = tStart;
179  m_endTime = tEnd;
180  m_dimension = dimension;
181  m_pLow = nullptr; m_pHigh = nullptr;
182  m_pVLow = nullptr; m_pVHigh = nullptr;
183 
184  if (m_endTime <= m_startTime) throw Tools::IllegalArgumentException("MovingRegion: Cannot support degenerate time intervals.");
185 
186 #ifndef NDEBUG
187  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
188  {
189  if (pLow[cDim] > pHigh[cDim]) throw Tools::IllegalArgumentException("MovingRegion: Low point has larger coordinates than High point.");
190  }
191 #endif
192 
193  try
194  {
195  m_pLow = new double[m_dimension];
196  m_pHigh = new double[m_dimension];
197  m_pVLow = new double[m_dimension];
198  m_pVHigh = new double[m_dimension];
199  }
200  catch (...)
201  {
202  delete[] m_pLow;
203  delete[] m_pHigh;
204  delete[] m_pVLow;
205  delete[] m_pVHigh;
206  throw;
207  }
208 
209  // first store the point coordinates, than the point velocities.
210  memcpy(m_pLow, pLow, m_dimension * sizeof(double));
211  memcpy(m_pHigh, pHigh, m_dimension * sizeof(double));
212  memcpy(m_pVLow, pVLow, m_dimension * sizeof(double));
213  memcpy(m_pVHigh, pVHigh, m_dimension * sizeof(double));
214 }
215 
217 {
218  delete[] m_pVLow;
219  delete[] m_pVHigh;
220 }
221 
223 {
224  if(this != &r)
225  {
227  memcpy(m_pLow, r.m_pLow, m_dimension * sizeof(double));
228  memcpy(m_pHigh, r.m_pHigh, m_dimension * sizeof(double));
229  memcpy(m_pVLow, r.m_pVLow, m_dimension * sizeof(double));
230  memcpy(m_pVHigh, r.m_pVHigh, m_dimension * sizeof(double));
231 
233  m_endTime = r.m_endTime;
234 
235  assert(m_startTime < m_endTime);
236  }
237 
238  return *this;
239 }
240 
242 {
243  if (m_startTime < r.m_startTime - std::numeric_limits<double>::epsilon() ||
244  m_startTime > r.m_startTime + std::numeric_limits<double>::epsilon() ||
245  m_endTime < r.m_endTime - std::numeric_limits<double>::epsilon() ||
246  m_endTime > r.m_endTime + std::numeric_limits<double>::epsilon())
247  return false;
248 
249  for (uint32_t i = 0; i < m_dimension; ++i)
250  {
251  if (
252  m_pLow[i] < r.m_pLow[i] - std::numeric_limits<double>::epsilon() ||
253  m_pLow[i] > r.m_pLow[i] + std::numeric_limits<double>::epsilon() ||
254  m_pHigh[i] < r.m_pHigh[i] - std::numeric_limits<double>::epsilon() ||
255  m_pHigh[i] > r.m_pHigh[i] + std::numeric_limits<double>::epsilon() ||
256  m_pVLow[i] < r.m_pVLow[i] - std::numeric_limits<double>::epsilon() ||
257  m_pVLow[i] > r.m_pVLow[i] + std::numeric_limits<double>::epsilon() ||
258  m_pVHigh[i] < r.m_pVHigh[i] - std::numeric_limits<double>::epsilon() ||
259  m_pVHigh[i] > r.m_pVHigh[i] + std::numeric_limits<double>::epsilon())
260  return false;
261  }
262  return true;
263 }
264 
266 {
267  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
268  {
269  if (m_pVHigh[cDim] < m_pVLow[cDim]) return true;
270  }
271  return false;
272 }
273 
274 // assumes that the region is not moving before and after start and end time.
275 double MovingRegion::getLow(uint32_t d, double t) const
276 {
278 
279  if (t > m_endTime) return m_pLow[d] + m_pVLow[d] * (m_endTime - m_startTime);
280  else if (t < m_startTime) return m_pLow[d];
281  else return m_pLow[d] + m_pVLow[d] * (t - m_startTime);
282 }
283 
284 // assumes that the region is not moving before and after start and end time.
285 double MovingRegion::getHigh(uint32_t d, double t) const
286 {
288 
289  if (t > m_endTime) return m_pHigh[d] + m_pVHigh[d] * (m_endTime - m_startTime);
290  else if (t < m_startTime) return m_pHigh[d];
291  else return m_pHigh[d] + m_pVHigh[d] * (t - m_startTime);
292 }
293 
294 // assuming that the region kept moving.
295 double MovingRegion::getExtrapolatedLow(uint32_t d, double t) const
296 {
298 
299  return m_pLow[d] + m_pVLow[d] * (t - m_startTime);
300 }
301 
302 // assuming that the region kept moving.
303 double MovingRegion::getExtrapolatedHigh(uint32_t d, double t) const
304 {
306 
307  return m_pHigh[d] + m_pVHigh[d] * (t - m_startTime);
308 }
309 
310 double MovingRegion::getVLow(uint32_t d) const
311 {
313 
314  return m_pVLow[d];
315 }
316 
317 double MovingRegion::getVHigh(uint32_t d) const
318 {
320 
321  return m_pVHigh[d];
322 }
323 
325 {
326  Tools::Interval ivOut;
327  return intersectsRegionInTime(r, ivOut);
328 }
329 
330 bool MovingRegion::intersectsRegionInTime(const MovingRegion& r, IInterval& ivOut) const
331 {
332  return intersectsRegionInTime(r, r, ivOut);
333 }
334 
335 // if tmin, tmax are infinity then this will not work correctly (everything will always intersect).
336 // does not work for shrinking regions.
337 // does not work with degenerate time-intervals.
338 //
339 // WARNING: this will return true even if one region completely contains the other, since
340 // their areas do intersect in that case!
341 //
342 // there are various cases here:
343 // 1. one region contains the other.
344 // 2. one boundary of one region is always contained indide the other region, while the other
345 // boundary is not (so no boundaries will ever intersect).
346 // 3. either the upper or lower boundary of one region intersects a boundary of the other.
347 bool MovingRegion::intersectsRegionInTime(const IInterval& ivPeriod, const MovingRegion& r, IInterval& ivOut) const
348 {
349  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("intersectsRegionInTime: MovingRegions have different number of dimensions.");
350 
351  assert(m_startTime < m_endTime);
352  assert(r.m_startTime < r.m_endTime);
353  assert(ivPeriod.getLowerBound() < ivPeriod.getUpperBound());
354  assert(isShrinking() == false && r.isShrinking() == false);
355 
356  // this is needed, since we are assuming below that the two regions have some point of intersection
357  // inside itPeriod.
358  if (containsRegionInTime(ivPeriod, r) || r.containsRegionInTime(ivPeriod, *this))
359  {
360  ivOut = ivPeriod;
361  return true;
362  }
363 
364  double tmin = std::max(m_startTime, r.m_startTime);
365  double tmax = std::min(m_endTime, r.m_endTime);
366 
367  // the regions do not intersect in time.
368  if (tmax <= tmin) return false;
369 
370  tmin = std::max(tmin, ivPeriod.getLowerBound());
371  tmax = std::min(tmax, ivPeriod.getUpperBound());
372 
373  // the regions intersecting interval does not intersect with the given time period.
374  if (tmax <= tmin) return false;
375 
376  assert(tmax < std::numeric_limits<double>::max());
377  assert(tmin > -std::numeric_limits<double>::max());
378 
379  // I use projected low and high because they are faster and it does not matter.
380  // The are also necessary for calculating the intersection point with reference time instant 0.0.
381 
382  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
383  {
384  assert(
385  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
386  tmin >= m_startTime && tmax <= m_endTime &&
387  tmin >= r.m_startTime && tmax <= r.m_endTime);
388 
389  // completely above or bellow in i-th dimension
390  if (
391  (r.getExtrapolatedLow(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) &&
392  r.getExtrapolatedLow(cDim, tmax) >= getExtrapolatedHigh(cDim, tmax)) ||
393  (r.getExtrapolatedHigh(cDim, tmin) < getExtrapolatedLow(cDim, tmin) &&
394  r.getExtrapolatedHigh(cDim, tmax) <= getExtrapolatedLow(cDim, tmax)))
395  return false;
396 
397  // otherwise they intersect inside this interval for sure. Care needs to be taken since
398  // intersection does not necessarily mean that two line segments intersect. It could be
399  // that one line segment is completely above/below another, in which case there is no intersection
400  // point inside tmin, tmax, even though the two region areas do intersect.
401 
402  if (r.getExtrapolatedLow(cDim, tmin) > getExtrapolatedHigh(cDim, tmin)) // r above *this at tmin
403  {
404  tmin = (getExtrapolatedHigh(cDim, 0.0) - r.getExtrapolatedLow(cDim, 0.0)) / (r.getVLow(cDim) - getVHigh(cDim));
405  }
406  else if (r.getExtrapolatedHigh(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) // r below *this at tmin
407  {
408  tmin = (getExtrapolatedLow(cDim, 0.0) - r.getExtrapolatedHigh(cDim, 0.0)) / (r.getVHigh(cDim) - getVLow(cDim));
409  }
410  // else they do not intersect and the boundary might be completely contained in this region.
411 
412  if (r.getExtrapolatedLow(cDim, tmax) > getExtrapolatedHigh(cDim, tmax)) // r above *this at tmax
413  {
414  tmax = (getExtrapolatedHigh(cDim, 0.0) - r.getExtrapolatedLow(cDim, 0.0)) / (r.getVLow(cDim) - getVHigh(cDim));
415  }
416  else if (r.getExtrapolatedHigh(cDim, tmax) < getExtrapolatedLow(cDim, tmax)) // r below *this at tmax
417  {
418  tmax = (getExtrapolatedLow(cDim, 0.0) - r.getExtrapolatedHigh(cDim, 0.0)) / (r.getVHigh(cDim) - getVLow(cDim));
419  }
420  // else they do not intersect and the boundary might be completely contained in this region.
421 
422  assert(tmin <= tmax);
423  }
424 
425  assert(
426  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
427  tmin >= m_startTime && tmax <= m_endTime &&
428  tmin >= r.m_startTime && tmax <= r.m_endTime);
429 
430  ivOut.setBounds(tmin, tmax);
431 
432  return true;
433 }
434 
436 {
437  return containsRegionInTime(r, r);
438 }
439 
440 // does not work for shrinking regions.
441 // works fine for infinite bounds (both tmin and tmax).
442 // does not work with degenerate time-intervals.
443 //
444 // finds if during the intersecting time-interval of r and ivPeriod, r is completely contained in *this.
445 bool MovingRegion::containsRegionInTime(const IInterval& ivPeriod, const MovingRegion& r) const
446 {
447  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("containsRegionInTime: MovingRegions have different number of dimensions.");
448 
449  assert(isShrinking() == false && r.isShrinking() == false);
450 
451  double tmin = std::max(ivPeriod.getLowerBound(), r.m_startTime);
452  double tmax = std::min(ivPeriod.getUpperBound(), r.m_endTime);
453 
454  // it should be contained in time.
455  // it does not make sense if this region is not defined for any part ot [tmin, tmax].
456  if (tmax <= tmin || tmin < m_startTime || tmax > m_endTime) return false;
457 
458  double intersectionTime;
459 
460  // no need to take projected coordinates here, since tmin and tmax are always contained in
461  // the regions intersecting time-intervals.
462  assert(
463  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
464  tmin >= m_startTime && tmax <= m_endTime &&
465  tmin >= r.m_startTime && tmax <= r.m_endTime);
466 
467  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
468  {
469  // it should be contained at start time.
470  if (r.getExtrapolatedHigh(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) ||
471  r.getExtrapolatedLow(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) return false;
472 
473  // this will take care of infinite bounds.
474  if (r.m_pVHigh[cDim] != m_pVHigh[cDim])
475  {
476  intersectionTime = (getExtrapolatedHigh(cDim, 0.0) - r.getExtrapolatedHigh(cDim, 0.0)) / (r.m_pVHigh[cDim] - m_pVHigh[cDim]);
477  // if they intersect during this time-interval, then it is not contained.
478  if (tmin < intersectionTime && intersectionTime < tmax) return false;
479  if (tmin == intersectionTime && r.m_pVHigh[cDim] > m_pVHigh[cDim]) return false;
480  }
481 
482  if (r.m_pVLow[cDim] != m_pVLow[cDim])
483  {
484  intersectionTime = (getExtrapolatedLow(cDim, 0.0) - r.getExtrapolatedLow(cDim, 0.0)) / (r.m_pVLow[cDim] - m_pVLow[cDim]);
485  // if they intersect during this time-interval, then it is not contained.
486  if (tmin < intersectionTime && intersectionTime < tmax) return false;
487  if (tmin == intersectionTime && r.m_pVLow[cDim] < m_pVLow[cDim]) return false;
488  }
489  }
490 
491  return true;
492 }
493 
495 {
496  Tools::Interval ivT(t, r.m_endTime);
497  return containsRegionInTime(ivT, r);
498 }
499 
500 // Returns the area swept by the rectangle in time, in d-dimensional space (without
501 // including the temporal dimension, that is).
502 // This is what Saltenis calls Margin (which is different than what Beckmann proposes,
503 // where he computes only the wireframe -- instead of the surface/volume/etc. -- of the MBR in any dimension).
505 {
506  return getProjectedSurfaceAreaInTime(*this);
507 }
508 
509 double MovingRegion::getProjectedSurfaceAreaInTime(const IInterval& ivI) const
510 {
511  double tmin = std::max(ivI.getLowerBound(), m_startTime);
512  double tmax = std::min(ivI.getUpperBound(), m_endTime);
513 
514  assert(tmin > -std::numeric_limits<double>::max());
515  assert(tmax < std::numeric_limits<double>::max());
516  assert(tmin <= tmax);
517 
518  if (tmin >= tmax - std::numeric_limits<double>::epsilon() &&
519  tmin <= tmax + std::numeric_limits<double>::epsilon())
520  return 0.0;
521 
522  double dx1, dx2, dx3;
523  double dv1, dv2, dv3;
524  double H = tmax - tmin;
525 
526  if (m_dimension == 3)
527  {
528  dx3 = getExtrapolatedHigh(2, tmin) - getExtrapolatedLow(2, tmin);
529  dv3 = getVHigh(2) - getVLow(2);
530  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
531  dv2 = getVHigh(1) - getVLow(1);
532  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
533  dv1 = getVHigh(0) - getVLow(0);
534  return
535  H * (dx1 + dx2 + dx3 + dx1*dx2 + dx1*dx3 + dx2*dx3) +
536  H*H * (dv1 + dv2 + dv3 + dx1*dv2 + dv1*dx2 + dx1*dv3 +
537  dv1*dx3 + dx2*dv3 + dv2*dx3) / 2.0 +
538  H*H*H * (dv1*dv2 + dv1*dv3 + dv2*dv3) / 3.0;
539  }
540  else if (m_dimension == 2)
541  {
542  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
543  dv2 = getVHigh(1) - getVLow(1);
544  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
545  dv1 = getVHigh(0) - getVLow(0);
546  return H * (dx1 + dx2) + H * H * (dv1 + dv2) / 2.0;
547  }
548  else if (m_dimension == 1)
549  {
550  // marioh: why not use the increase of the length of the interval here?
551  return 0.0;
552  }
553  else
554  {
555  throw Tools::IllegalStateException("getProjectedSurfaceAreaInTime: unsupported dimensionality.");
556  }
557 }
558 
560 {
561 
562  return getCenterDistanceInTime(r, r);
563 }
564 
565 double MovingRegion::getCenterDistanceInTime(const IInterval& ivI, const MovingRegion& r) const
566 {
567  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("getCenterDistanceInTime: MovingRegions have different number of dimensions.");
568 
569  assert(m_startTime < m_endTime);
570  assert(r.m_startTime < r.m_endTime);
571  assert(ivI.getLowerBound() < ivI.getUpperBound());
572 
573  double tmin = std::max(m_startTime, r.m_startTime);
574  double tmax = std::min(m_endTime, r.m_endTime);
575 
576  // the regions do not intersect in time.
577  if (tmax <= tmin) return 0.0;
578 
579  tmin = std::max(tmin, ivI.getLowerBound());
580  tmax = std::min(tmax, ivI.getUpperBound());
581 
582  // the regions intersecting interval does not intersect with the given time period.
583  if (tmax <= tmin) return 0.0;
584 
585  assert(tmax < std::numeric_limits<double>::max());
586  assert(tmin > -std::numeric_limits<double>::max());
587 
588  if (tmin >= tmax - std::numeric_limits<double>::epsilon() &&
589  tmin <= tmax + std::numeric_limits<double>::epsilon())
590  return 0.0;
591 
592  double H = tmax - tmin;
593 
594  double* dx = new double[m_dimension];
595  double* dv = new double[m_dimension];
596  double a = 0.0, b = 0.0, c = 0.0, f = 0.0, l = 0.0, m = 0.0, n = 0.0;
597 
598  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
599  {
600  dx[cDim] =
601  (r.getExtrapolatedLow(cDim, tmin) + r.getExtrapolatedHigh(cDim, tmin)) / 2.0 -
602  (getExtrapolatedLow(cDim, tmin) + getExtrapolatedHigh(cDim, tmin)) / 2.0;
603  dv[cDim] =
604  (r.getVLow(cDim) + r.getVHigh(cDim)) / 2.0 -
605  (getVLow(cDim) + getVHigh(cDim)) / 2.0;
606  }
607 
608  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
609  {
610  a += dv[cDim] * dv[cDim];
611  b += 2.0 * dx[cDim] * dv[cDim];
612  c += dx[cDim] * dx[cDim];
613  }
614 
615  delete[] dx;
616  delete[] dv;
617 
618  if (a == 0.0 && c == 0.0) return 0.0;
619  if (a == 0.0) return H * std::sqrt(c);
620  if (c == 0.0) return H * H * std::sqrt(a) / 2.0;
621 
622  f = std::sqrt(a * H * H + b * H + c);
623  l = 2.0 * a * H + b;
624  m = 4.0 * a * c - b * b;
625  n = 2.0 * std::sqrt(a);
626 
627  return (l * f + log(l / n + f) * m / n - b * std::sqrt(c) - std::log(b / n + std::sqrt(c)) * m / n) / (4.0 * a);
628 }
629 
630 // does not work with degenerate time-intervals.
632 {
633  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("intersectsRegionAtTime: MovingRegions have different number of dimensions.");
634 
635  // do they contain the time instant?
636  if (! (m_startTime <= t && t < m_endTime && r.m_startTime <= t && t < r.m_endTime)) return false;
637 
638  // do they intersect at that time instant?
639  for (uint32_t i = 0; i < m_dimension; ++i)
640  {
641  if (getExtrapolatedLow(i, t) > r.getExtrapolatedHigh(i, t) || getExtrapolatedHigh(i, t) < r.getExtrapolatedLow(i, t)) return false;
642  }
643  return true;
644 }
645 
646 // does not work with degenerate time-intervals.
647 bool MovingRegion::containsRegionAtTime(double t, const MovingRegion& r) const
648 {
649  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("containsRegionAtTime: MovingRegions have different number of dimensions.");
650 
651  // do they contain the time instant?
652  if (! (m_startTime <= t && t < m_endTime && r.m_startTime <= t && t < r.m_endTime)) return false;
653 
654  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
655  {
656  if (getExtrapolatedLow(cDim, t) > r.getExtrapolatedLow(cDim, t) || getExtrapolatedHigh(cDim, t) < r.getExtrapolatedHigh(cDim, t)) return false;
657  }
658  return true;
659 }
660 
662 {
663  Tools::Interval ivOut;
664  return intersectsPointInTime(p, ivOut);
665 }
666 
667 bool MovingRegion::intersectsPointInTime(const MovingPoint& p, IInterval& ivOut) const
668 {
669  return intersectsPointInTime(p, p, ivOut);
670 }
671 
672 // if tmin, tmax are infinity then this will not work correctly (everything will always intersect).
673 // does not work for shrinking regions.
674 // does not work with degenerate time-intervals.
675 // FIXME: don't know what happens if tmin is negative infinity.
676 //
677 // WARNING: This will return true even if the region completely contains the point, since
678 // in that case the point trajectory intersects the region area!
679 bool MovingRegion::intersectsPointInTime(const IInterval& ivPeriod, const MovingPoint& p, IInterval& ivOut) const
680 {
681  if (m_dimension != p.m_dimension) throw Tools::IllegalArgumentException("intersectsPointInTime: MovingPoint has different number of dimensions.");
682 
683  assert(m_startTime < m_endTime);
684  assert(p.m_startTime < p.m_endTime);
685  assert(ivPeriod.getLowerBound() < ivPeriod.getUpperBound());
686  assert(isShrinking() == false);
687 
688  if (containsPointInTime(ivPeriod, p))
689  {
690  ivOut = ivPeriod;
691  return true;
692  }
693 
694  double tmin = std::max(m_startTime, p.m_startTime);
695  double tmax = std::min(m_endTime, p.m_endTime);
696 
697  // the shapes do not intersect in time.
698  if (tmax <= tmin) return false;
699 
700  tmin = std::max(tmin, ivPeriod.getLowerBound());
701  tmax = std::min(tmax, ivPeriod.getUpperBound());
702 
703  // the shapes intersecting interval does not intersect with the given time period.
704  if (tmax <= tmin) return false;
705 
706  assert(tmax < std::numeric_limits<double>::max());
707  assert(tmin > -std::numeric_limits<double>::max());
708 
709  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
710  {
711  assert(
712  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
713  tmin >= m_startTime && tmax <= m_endTime &&
714  tmin >= p.m_startTime && tmax <= p.m_endTime);
715 
716  // completely above or bellow in i-th dimension
717  if ((p.getProjectedCoord(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) &&
718  p.getProjectedCoord(cDim, tmax) >= getExtrapolatedHigh(cDim, tmax)) ||
719  (p.getProjectedCoord(cDim, tmin) < getExtrapolatedLow(cDim, tmin) &&
720  p.getProjectedCoord(cDim, tmax) <= getExtrapolatedLow(cDim, tmax)))
721  return false;
722 
723  // otherwise they intersect inside this interval for sure, since we know that the point is not contained,
724  // so there is no need to check for 0 divisors, negative values, etc...
725 
726  // adjust tmin
727  if (p.getProjectedCoord(cDim, tmin) > getExtrapolatedHigh(cDim, tmin)) // p above *this at tmin
728  {
729  tmin = (getExtrapolatedHigh(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVHigh(cDim));
730  }
731  else if (p.getProjectedCoord(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) // p below *this at tmin
732  {
733  tmin = (getExtrapolatedLow(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVLow(cDim));
734  }
735 
736  // adjust tmax
737  if (p.getProjectedCoord(cDim, tmax) > getExtrapolatedHigh(cDim, tmax)) // p above *this at tmax
738  {
739  tmax = (getExtrapolatedHigh(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVHigh(cDim));
740  }
741  else if (p.getProjectedCoord(cDim, tmax) < getExtrapolatedLow(cDim, tmax)) // p below *this at tmax
742  {
743  tmax = (getExtrapolatedLow(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVLow(cDim));
744  }
745 
746  if (tmin > tmax) return false;
747  }
748 
749  ivOut.setBounds(tmin, tmax);
750 
751  return true;
752 }
753 
755 {
756  return containsPointInTime(p, p);
757 }
758 
759 // does not work for shrinking regions.
760 // works fine for infinite bounds (both tmin and tmax).
761 // does not work with degenerate time-intervals.
762 //
763 // finds if during the intersecting time-interval of p and ivPeriod, p is completely contained in *this.
764 bool MovingRegion::containsPointInTime(const IInterval& ivPeriod, const MovingPoint& p) const
765 {
766  if (m_dimension != p.m_dimension) throw Tools::IllegalArgumentException("containsPointInTime: MovingPoint has different number of dimensions.");
767 
768  assert(isShrinking() == false);
769 
770  double tmin = std::max(ivPeriod.getLowerBound(), p.m_startTime);
771  double tmax = std::min(ivPeriod.getUpperBound(), p.m_endTime);
772 
773  // it should be contained in time.
774  if (tmax <= tmin || tmin < m_startTime || tmax > m_endTime) return false;
775 
776  double intersectionTime;
777 
778  assert(
779  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
780  tmin >= m_startTime && tmax <= m_endTime &&
781  tmin >= p.m_startTime && tmax <= p.m_endTime);
782 
783  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
784  {
785  // it should be contained at start time.
786  if (p.getProjectedCoord(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) ||
787  p.getProjectedCoord(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) return false;
788 
789  if (p.m_pVCoords[cDim] != m_pVHigh[cDim])
790  {
791  intersectionTime = (getExtrapolatedHigh(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.m_pVCoords[cDim] - m_pVHigh[cDim]);
792  // if they intersect during this time-interval, then it is not contained.
793  if (tmin < intersectionTime && intersectionTime < tmax) return false;
794  if (tmin == intersectionTime && p.m_pVCoords[cDim] > m_pVHigh[cDim]) return false;
795  }
796 
797  if (p.m_pVCoords[cDim] != m_pVLow[cDim])
798  {
799  intersectionTime = (getExtrapolatedLow(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.m_pVCoords[cDim] - m_pVLow[cDim]);
800  // if they intersect during this time-interval, then it is not contained.
801  if (tmin < intersectionTime && intersectionTime < tmax) return false;
802  if (tmin == intersectionTime && p.m_pVCoords[cDim] < m_pVLow[cDim]) return false;
803  }
804  }
805 
806  return true;
807 }
808 
810 {
811  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("combineRegionInTime: MovingRegions have different number of dimensions.");
812 
813  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
814  {
815  m_pLow[cDim] = std::min(getExtrapolatedLow(cDim, m_startTime), r.getExtrapolatedLow(cDim, m_startTime));
816  m_pHigh[cDim] = std::max(getExtrapolatedHigh(cDim, m_startTime), r.getExtrapolatedHigh(cDim, m_startTime));
817  m_pVLow[cDim] = std::min(m_pVLow[cDim], r.m_pVLow[cDim]);
818  m_pVHigh[cDim] = std::max(m_pVHigh[cDim], r.m_pVHigh[cDim]);
819  }
820 
821  // m_startTime should be modified at the end, since it affects the
822  // calculation of extrapolated coordinates.
823  m_startTime = std::min(m_startTime, r.m_startTime);
824  m_endTime = std::max(m_endTime, r.m_endTime);
825 }
826 
828 {
829  if (m_dimension != in.m_dimension) throw Tools::IllegalArgumentException("getCombinedProjectedRegionInTime: MovingRegions have different number of dimensions.");
830 
831  out = *this;
832  out.combineRegionInTime(in);
833 }
834 
836 {
837  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("combineRegionInTime: MovingRegions have different number of dimensions.");
838 
839  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
840  {
841  m_pLow[cDim] = std::min(getExtrapolatedLow(cDim, t), r.getExtrapolatedLow(cDim, t));
842  m_pHigh[cDim] = std::max(getExtrapolatedHigh(cDim, t), r.getExtrapolatedHigh(cDim, t));
843  m_pVLow[cDim] = std::min(m_pVLow[cDim], r.m_pVLow[cDim]);
844  m_pVHigh[cDim] = std::max(m_pVHigh[cDim], r.m_pVHigh[cDim]);
845  }
846 
847  // m_startTime should be modified at the end, since it affects the
848  // calculation of extrapolated coordinates.
849  m_startTime = t;
850  m_endTime = std::max(m_endTime, r.m_endTime);
851  if (t >= m_endTime) m_endTime = std::numeric_limits<double>::max();
852 }
853 
855 {
856  if (m_dimension != in.m_dimension) throw Tools::IllegalArgumentException("getCombinedProjectedRegionInTime: MovingRegions have different number of dimensions.");
857 
858  out = *this;
859  out.combineRegionAfterTime(t, in);
860 }
861 
863 {
864  return getIntersectingAreaInTime(r, r);
865 }
866 
867 double MovingRegion::getIntersectingAreaInTime(const IInterval& ivI, const MovingRegion& r) const
868 {
869  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("getIntersectingAreaInTime: MovingRegions have different number of dimensions.");
870 
871  assert(m_startTime < m_endTime);
872  assert(r.m_startTime < r.m_endTime);
873  assert(ivI.getLowerBound() < ivI.getUpperBound());
874  assert(isShrinking() == false && r.isShrinking() == false);
875 
876  double tmin = std::max(m_startTime, r.m_startTime);
877  double tmax = std::min(m_endTime, r.m_endTime);
878 
879  // the regions do not intersect in time.
880  if (tmax <= tmin) return 0.0;
881 
882  tmin = std::max(tmin, ivI.getLowerBound());
883  tmax = std::min(tmax, ivI.getUpperBound());
884 
885  // the regions intersecting interval does not intersect with the given time period.
886  if (tmax <= tmin) return 0.0;
887 
888  assert(tmax < std::numeric_limits<double>::max());
889  assert(tmin > -std::numeric_limits<double>::max());
890 
891  Tools::Interval ivIn(tmin, tmax);
892  Tools::Interval ivOut(ivIn);
893 
894  if (! intersectsRegionInTime(ivIn, r, ivOut)) return 0.0;
895 
896  ivIn = ivOut;
897  tmin = ivIn.getLowerBound();
898  tmax = ivIn.getUpperBound();
899  assert(tmin <= tmax);
900 
901  assert(tmin >= ivI.getLowerBound() && tmax <= ivI.getUpperBound());
902 
903  if (containsRegionInTime(ivIn, r))
904  {
905  return r.getAreaInTime(ivIn);
906  }
907  else if (r.containsRegionInTime(ivIn, *this))
908  {
909  return getAreaInTime(ivIn);
910  }
911 
912  MovingRegion x = *this;
913  CrossPoint c;
914  auto ascending = [](CrossPoint& lhs, CrossPoint& rhs) { return lhs.m_t > rhs.m_t; };
915  std::priority_queue < CrossPoint, std::vector<CrossPoint>, decltype(ascending)> pq(ascending);
916 
917  // find points of intersection in all dimensions.
918  for (uint32_t i = 0; i < m_dimension; ++i)
919  {
920  if (getLow(i, tmin) > r.getLow(i, tmin))
921  {
922  x.m_pLow[i] = m_pLow[i];
923  x.m_pVLow[i] = m_pVLow[i];
924 
925  if (getLow(i, tmax) < r.getLow(i, tmax))
926  {
927  c.m_dimension = i;
928  c.m_boundary = 0;
929  c.m_t = (getExtrapolatedLow(i, 0.0) - r.getExtrapolatedLow(i, 0.0)) / (r.getVLow(i) - getVLow(i));
930  assert(c.m_t >= tmin && c.m_t <= tmax);
931  c.m_to = &r;
932  pq.push(c);
933  }
934  }
935  else
936  {
937  x.m_pLow[i] = r.m_pLow[i];
938  x.m_pVLow[i] = r.m_pVLow[i];
939 
940  if (r.getLow(i, tmax) < getLow(i, tmax))
941  {
942  c.m_dimension = i;
943  c.m_boundary = 0;
944  c.m_t = (getExtrapolatedLow(i, 0.0) - r.getExtrapolatedLow(i, 0.0)) / (r.getVLow(i) - getVLow(i));
945  assert(c.m_t >= tmin && c.m_t <= tmax);
946  c.m_to = this;
947  pq.push(c);
948  }
949  }
950 
951  if (getHigh(i, tmin) < r.getHigh(i, tmin))
952  {
953  x.m_pHigh[i] = m_pHigh[i];
954  x.m_pVHigh[i] = m_pVHigh[i];
955 
956  if (getHigh(i, tmax) > r.getHigh(i, tmax))
957  {
958  c.m_dimension = i;
959  c.m_boundary = 1;
960  c.m_t = (getExtrapolatedHigh(i, 0.0) - r.getExtrapolatedHigh(i, 0.0)) / (r.getVHigh(i) - getVHigh(i));
961  assert(c.m_t >= tmin && c.m_t <= tmax);
962  c.m_to = &r;
963  pq.push(c);
964  }
965  }
966  else
967  {
968  x.m_pHigh[i] = r.m_pHigh[i];
969  x.m_pVHigh[i] = r.m_pVHigh[i];
970 
971  if (r.getHigh(i, tmax) > getHigh(i, tmax))
972  {
973  c.m_dimension = i;
974  c.m_boundary = 1;
975  c.m_t = (getExtrapolatedHigh(i, 0.0) - r.getExtrapolatedHigh(i, 0.0)) / (r.getVHigh(i) - getVHigh(i));
976  assert(c.m_t >= tmin && c.m_t <= tmax);
977  c.m_to = this;
978  pq.push(c);
979  }
980  }
981  }
982 
983  // add up the total area of the intersecting pieces.
984  double area = 0.0;
985 #ifndef NDEBUG
986  double _t = -std::numeric_limits<double>::max();
987 #endif
988 
989  while (! pq.empty())
990  {
991  c = pq.top(); pq.pop();
992 #ifndef NDEBUG
993  assert(_t <= c.m_t);
994  _t = c.m_t;
995 #endif
996 
997  // needed in case two consecutive points have the same intersection time.
998  if (c.m_t > tmin) area += x.getAreaInTime(Tools::Interval(tmin, c.m_t));
999 
1000  if (c.m_boundary == 0)
1001  {
1002  x.m_pLow[c.m_dimension] = c.m_to->m_pLow[c.m_dimension];
1004  }
1005  else
1006  {
1009  }
1010 
1011  tmin = c.m_t;
1012  }
1013 
1014  // ... and the last piece
1015  if (tmax > tmin) area += x.getAreaInTime(Tools::Interval(tmin, tmax));
1016 
1017  return area;
1018 }
1019 
1020 //
1021 // IObject interface
1022 //
1024 {
1025  return new MovingRegion(*this);
1026 }
1027 
1028 //
1029 // ISerializable interface
1030 //
1032 {
1033  return (sizeof(uint32_t) + 2 * sizeof(double) + 4 * m_dimension * sizeof(double));
1034 }
1035 
1036 void MovingRegion::loadFromByteArray(const uint8_t* ptr)
1037 {
1038  uint32_t dimension;
1039 
1040  memcpy(&dimension, ptr, sizeof(uint32_t));
1041  ptr += sizeof(uint32_t);
1042  memcpy(&m_startTime, ptr, sizeof(double));
1043  ptr += sizeof(double);
1044  memcpy(&m_endTime, ptr, sizeof(double));
1045  ptr += sizeof(double);
1046 
1047  makeDimension(dimension);
1048  memcpy(m_pLow, ptr, m_dimension * sizeof(double));
1049  ptr += m_dimension * sizeof(double);
1050  memcpy(m_pHigh, ptr, m_dimension * sizeof(double));
1051  ptr += m_dimension * sizeof(double);
1052  memcpy(m_pVLow, ptr, m_dimension * sizeof(double));
1053  ptr += m_dimension * sizeof(double);
1054  memcpy(m_pVHigh, ptr, m_dimension * sizeof(double));
1055  //ptr += m_dimension * sizeof(double);
1056 }
1057 
1058 void MovingRegion::storeToByteArray(uint8_t** data, uint32_t& len)
1059 {
1060  len = getByteArraySize();
1061  *data = new uint8_t[len];
1062  uint8_t* ptr = *data;
1063 
1064  memcpy(ptr, &m_dimension, sizeof(uint32_t));
1065  ptr += sizeof(uint32_t);
1066  memcpy(ptr, &m_startTime, sizeof(double));
1067  ptr += sizeof(double);
1068  memcpy(ptr, &m_endTime, sizeof(double));
1069  ptr += sizeof(double);
1070 
1071  memcpy(ptr, m_pLow, m_dimension * sizeof(double));
1072  ptr += m_dimension * sizeof(double);
1073  memcpy(ptr, m_pHigh, m_dimension * sizeof(double));
1074  ptr += m_dimension * sizeof(double);
1075  memcpy(ptr, m_pVLow, m_dimension * sizeof(double));
1076  ptr += m_dimension * sizeof(double);
1077  memcpy(ptr, m_pVHigh, m_dimension * sizeof(double));
1078  //ptr += m_dimension * sizeof(double);
1079 }
1080 
1081 //
1082 // IEvolvingShape interface
1083 //
1085 {
1087  memcpy(out.m_pLow, m_pVLow, m_dimension * sizeof(double));
1088  memcpy(out.m_pHigh, m_pVHigh, m_dimension * sizeof(double));
1089 }
1090 
1091 void MovingRegion::getMBRAtTime(double t, Region& out) const
1092 {
1094  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
1095  {
1096  out.m_pLow[cDim] = getLow(cDim, t);
1097  out.m_pHigh[cDim] = getHigh(cDim, t);
1098  }
1099 }
1100 
1101 //
1102 // ITimeShape interface
1103 //
1105 {
1106  return getAreaInTime(*this);
1107 }
1108 
1109 // this computes the area/volume/etc. swept by the Region in time.
1110 double MovingRegion::getAreaInTime(const IInterval& ivI) const
1111 {
1112  double tmin = std::max(ivI.getLowerBound(), m_startTime);
1113  double tmax = std::min(ivI.getUpperBound(), m_endTime);
1114 
1115  assert(tmin > -std::numeric_limits<double>::max());
1116  assert(tmax < std::numeric_limits<double>::max());
1117  assert(tmin <= tmax);
1118 
1119  if (tmin >= tmax - std::numeric_limits<double>::epsilon() &&
1120  tmin <= tmax + std::numeric_limits<double>::epsilon())
1121  return 0.0;
1122 
1123  double dx1, dx2, dx3;
1124  double dv1, dv2, dv3;
1125  double H = tmax - tmin;
1126 
1127  if (m_dimension == 3)
1128  {
1129  dx3 = getExtrapolatedHigh(2, tmin) - getExtrapolatedLow(2, tmin);
1130  dv3 = getVHigh(2) - getVLow(2);
1131  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
1132  dv2 = getVHigh(1) - getVLow(1);
1133  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
1134  dv1 = getVHigh(0) - getVLow(0);
1135  return
1136  H * dx1 * dx2 * dx3 + H * H * (dx1 * dx2 * dv3 + (dx1 * dv2 + dv1 * dx2) * dx3) / 2.0 +
1137  H * H * H * ((dx1 * dv2 + dv1 * dx2) * dv3 + dv1 * dv2 * dx3) / 3.0 + H * H * H * H * dv1 * dv2 * dv3 / 4.0;
1138  }
1139  else if (m_dimension == 2)
1140  {
1141  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
1142  dv2 = getVHigh(1) - getVLow(1);
1143  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
1144  dv1 = getVHigh(0) - getVLow(0);
1145  return H * dx1 * dx2 + H * H * (dx1 * dv2 + dv1 * dx2) / 2.0 + H * H * H * dv1 * dv2 / 3.0;
1146  }
1147  else if (m_dimension == 1)
1148  {
1149  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
1150  dv1 = getVHigh(0) - getVLow(0);
1151  return H * dx1 + H * H * dv1 / 2.0;
1152  }
1153  else
1154  {
1155  throw Tools::NotSupportedException("getAreaInTime: unsupported dimensionality.");
1156  }
1157 }
1158 
1160 {
1161  return getIntersectingAreaInTime(r, r);
1162 }
1163 
1164 double MovingRegion::getIntersectingAreaInTime(const IInterval&, const ITimeShape& in) const
1165 {
1166  const MovingRegion* pr = dynamic_cast<const MovingRegion*>(&in);
1167  if (pr != nullptr) return getIntersectingAreaInTime(*pr);
1168 
1169  throw Tools::IllegalStateException("getIntersectingAreaInTime: Not implemented yet!");
1170 }
1171 
1172 void MovingRegion::makeInfinite(uint32_t dimension)
1173 {
1174  makeDimension(dimension);
1175  for (uint32_t cIndex = 0; cIndex < m_dimension; ++cIndex)
1176  {
1177  m_pLow[cIndex] = std::numeric_limits<double>::max();
1178  m_pHigh[cIndex] = -std::numeric_limits<double>::max();
1179  m_pVLow[cIndex] = std::numeric_limits<double>::max();
1180  m_pVHigh[cIndex] = -std::numeric_limits<double>::max();
1181  }
1182 
1183  m_startTime = -std::numeric_limits<double>::max();
1184  m_endTime = std::numeric_limits<double>::max();
1185 }
1186 
1187 void MovingRegion::makeDimension(uint32_t dimension)
1188 {
1189  if (m_dimension != dimension)
1190  {
1191  delete[] m_pLow;
1192  delete[] m_pHigh;
1193  delete[] m_pVLow;
1194  delete[] m_pVHigh;
1195  m_pLow = nullptr; m_pHigh = nullptr;
1196  m_pVLow = nullptr; m_pVHigh = nullptr;
1197 
1198  m_dimension = dimension;
1199  m_pLow = new double[m_dimension];
1200  m_pHigh = new double[m_dimension];
1201  m_pVLow = new double[m_dimension];
1202  m_pVHigh = new double[m_dimension];
1203  }
1204 }
1205 
1206 std::ostream& SpatialIndex::operator<<(std::ostream& os, const MovingRegion& r)
1207 {
1208  uint32_t i;
1209 
1210  os << "Low: ";
1211  for (i = 0; i < r.m_dimension; ++i)
1212  {
1213  os << r.m_pLow[i] << " ";
1214  }
1215 
1216  os << ", High: ";
1217 
1218  for (i = 0; i < r.m_dimension; ++i)
1219  {
1220  os << r.m_pHigh[i] << " ";
1221  }
1222 
1223  os << "VLow: ";
1224  for (i = 0; i < r.m_dimension; ++i)
1225  {
1226  os << r.m_pVLow[i] << " ";
1227  }
1228 
1229  os << ", VHigh: ";
1230 
1231  for (i = 0; i < r.m_dimension; ++i)
1232  {
1233  os << r.m_pVHigh[i] << " ";
1234  }
1235 
1236  os << ", Start: " << r.m_startTime << ", End: " << r.m_endTime;
1237 
1238  return os;
1239 }
double getUpperBound() const override
Definition: Tools.cc:427
virtual MovingRegion & operator=(const MovingRegion &r)
virtual bool intersectsRegionAtTime(double t, const MovingRegion &r) const
double getLowerBound() const override
Definition: Tools.cc:422
virtual double getLow(uint32_t index, double t) const
virtual double getExtrapolatedHigh(uint32_t index, double t) const
void makeDimension(uint32_t dimension) override
virtual bool containsRegionInTime(const MovingRegion &r) const
virtual void makeDimension(uint32_t dimension)
Definition: Region.cc:561
virtual double getExtrapolatedLow(uint32_t index, double t) const
void makeInfinite(uint32_t dimension) override
virtual bool intersectsPointInTime(const MovingPoint &p) const
void storeToByteArray(uint8_t **data, uint32_t &len) override
void getMBRAtTime(double t, Region &out) const override
virtual bool containsPointInTime(const MovingPoint &p) const
virtual bool containsRegionAtTime(double t, const MovingRegion &r) const
virtual double getCenterDistanceInTime(const MovingRegion &r) const
void getVMBR(Region &out) const override
virtual double getProjectedSurfaceAreaInTime() const
double * m_pLow
Definition: Region.h:98
uint32_t m_dimension
Definition: Point.h:77
virtual double getVCoord(uint32_t index) const
Definition: MovingPoint.cc:196
virtual double getIntersectingAreaInTime(const MovingRegion &r) const
double getAreaInTime() const override
virtual void getCombinedRegionAfterTime(double t, MovingRegion &out, const MovingRegion &in) const
uint32_t m_dimension
Definition: Region.h:97
double * m_pHigh
Definition: Region.h:99
SIDX_DLL std::ostream & operator<<(std::ostream &os, const Ball &ball)
Definition: Ball.cc:215
virtual void combineRegionAfterTime(double t, const MovingRegion &r)
virtual double getProjectedCoord(uint32_t index, double t) const
Definition: MovingPoint.cc:189
void loadFromByteArray(const uint8_t *data) override
MovingRegion * clone() override
virtual double getVLow(uint32_t index) const
virtual bool operator==(const MovingRegion &) const
virtual void getCombinedRegionInTime(MovingRegion &out, const MovingRegion &in) const
double * m_pCoords
Definition: Point.h:78
uint32_t getByteArraySize() override
virtual void combineRegionInTime(const MovingRegion &r)
virtual bool containsRegionAfterTime(double t, const MovingRegion &r) const
virtual double getHigh(uint32_t index, double t) const
virtual double getVHigh(uint32_t index) const
virtual bool intersectsRegionInTime(const MovingRegion &r) const