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  try
187  {
188  m_pLow = new double[m_dimension];
189  m_pHigh = new double[m_dimension];
190  m_pVLow = new double[m_dimension];
191  m_pVHigh = new double[m_dimension];
192  }
193  catch (...)
194  {
195  delete[] m_pLow;
196  delete[] m_pHigh;
197  delete[] m_pVLow;
198  delete[] m_pVHigh;
199  throw;
200  }
201 
202  // first store the point coordinates, than the point velocities.
203  memcpy(m_pLow, pLow, m_dimension * sizeof(double));
204  memcpy(m_pHigh, pHigh, m_dimension * sizeof(double));
205  memcpy(m_pVLow, pVLow, m_dimension * sizeof(double));
206  memcpy(m_pVHigh, pVHigh, m_dimension * sizeof(double));
207 }
208 
210 {
211  delete[] m_pVLow;
212  delete[] m_pVHigh;
213 }
214 
216 {
217  if(this != &r)
218  {
220  memcpy(m_pLow, r.m_pLow, m_dimension * sizeof(double));
221  memcpy(m_pHigh, r.m_pHigh, m_dimension * sizeof(double));
222  memcpy(m_pVLow, r.m_pVLow, m_dimension * sizeof(double));
223  memcpy(m_pVHigh, r.m_pVHigh, m_dimension * sizeof(double));
224 
226  m_endTime = r.m_endTime;
227 
228  assert(m_startTime < m_endTime);
229  }
230 
231  return *this;
232 }
233 
235 {
236  if (m_startTime < r.m_startTime - std::numeric_limits<double>::epsilon() ||
237  m_startTime > r.m_startTime + std::numeric_limits<double>::epsilon() ||
238  m_endTime < r.m_endTime - std::numeric_limits<double>::epsilon() ||
239  m_endTime > r.m_endTime + std::numeric_limits<double>::epsilon())
240  return false;
241 
242  for (uint32_t i = 0; i < m_dimension; ++i)
243  {
244  if (
245  m_pLow[i] < r.m_pLow[i] - std::numeric_limits<double>::epsilon() ||
246  m_pLow[i] > r.m_pLow[i] + std::numeric_limits<double>::epsilon() ||
247  m_pHigh[i] < r.m_pHigh[i] - std::numeric_limits<double>::epsilon() ||
248  m_pHigh[i] > r.m_pHigh[i] + std::numeric_limits<double>::epsilon() ||
249  m_pVLow[i] < r.m_pVLow[i] - std::numeric_limits<double>::epsilon() ||
250  m_pVLow[i] > r.m_pVLow[i] + std::numeric_limits<double>::epsilon() ||
251  m_pVHigh[i] < r.m_pVHigh[i] - std::numeric_limits<double>::epsilon() ||
252  m_pVHigh[i] > r.m_pVHigh[i] + std::numeric_limits<double>::epsilon())
253  return false;
254  }
255  return true;
256 }
257 
259 {
260  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
261  {
262  if (m_pVHigh[cDim] < m_pVLow[cDim]) return true;
263  }
264  return false;
265 }
266 
267 // assumes that the region is not moving before and after start and end time.
268 double MovingRegion::getLow(uint32_t d, double t) const
269 {
271 
272  if (t > m_endTime) return m_pLow[d] + m_pVLow[d] * (m_endTime - m_startTime);
273  else if (t < m_startTime) return m_pLow[d];
274  else return m_pLow[d] + m_pVLow[d] * (t - m_startTime);
275 }
276 
277 // assumes that the region is not moving before and after start and end time.
278 double MovingRegion::getHigh(uint32_t d, double t) const
279 {
281 
282  if (t > m_endTime) return m_pHigh[d] + m_pVHigh[d] * (m_endTime - m_startTime);
283  else if (t < m_startTime) return m_pHigh[d];
284  else return m_pHigh[d] + m_pVHigh[d] * (t - m_startTime);
285 }
286 
287 // assuming that the region kept moving.
288 double MovingRegion::getExtrapolatedLow(uint32_t d, double t) const
289 {
291 
292  return m_pLow[d] + m_pVLow[d] * (t - m_startTime);
293 }
294 
295 // assuming that the region kept moving.
296 double MovingRegion::getExtrapolatedHigh(uint32_t d, double t) const
297 {
299 
300  return m_pHigh[d] + m_pVHigh[d] * (t - m_startTime);
301 }
302 
303 double MovingRegion::getVLow(uint32_t d) const
304 {
306 
307  return m_pVLow[d];
308 }
309 
310 double MovingRegion::getVHigh(uint32_t d) const
311 {
313 
314  return m_pVHigh[d];
315 }
316 
317 bool MovingRegion::intersectsRegionInTime(const MovingRegion& r) const
318 {
319  Tools::Interval ivOut;
320  return intersectsRegionInTime(r, ivOut);
321 }
322 
323 bool MovingRegion::intersectsRegionInTime(const MovingRegion& r, IInterval& ivOut) const
324 {
325  return intersectsRegionInTime(r, r, ivOut);
326 }
327 
328 // if tmin, tmax are infinity then this will not work correctly (everything will always intersect).
329 // does not work for shrinking regions.
330 // does not work with degenerate time-intervals.
331 //
332 // WARNING: this will return true even if one region completely contains the other, since
333 // their areas do intersect in that case!
334 //
335 // there are various cases here:
336 // 1. one region contains the other.
337 // 2. one boundary of one region is always contained inside the other region, while the other
338 // boundary is not (so no boundaries will ever intersect).
339 // 3. either the upper or lower boundary of one region intersects a boundary of the other.
340 bool MovingRegion::intersectsRegionInTime(const IInterval& ivPeriod, const MovingRegion& r, IInterval& ivOut) const
341 {
342  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("intersectsRegionInTime: MovingRegions have different number of dimensions.");
343 
344  assert(m_startTime < m_endTime);
345  assert(r.m_startTime < r.m_endTime);
346  assert(ivPeriod.getLowerBound() < ivPeriod.getUpperBound());
347  assert(isShrinking() == false && r.isShrinking() == false);
348 
349  // this is needed, since we are assuming below that the two regions have some point of intersection
350  // inside itPeriod.
351  if (containsRegionInTime(ivPeriod, r) || r.containsRegionInTime(ivPeriod, *this))
352  {
353  ivOut = ivPeriod;
354  return true;
355  }
356 
357  double tmin = std::max(m_startTime, r.m_startTime);
358  double tmax = std::min(m_endTime, r.m_endTime);
359 
360  // the regions do not intersect in time.
361  if (tmax <= tmin) return false;
362 
363  tmin = std::max(tmin, ivPeriod.getLowerBound());
364  tmax = std::min(tmax, ivPeriod.getUpperBound());
365 
366  // the regions intersecting interval does not intersect with the given time period.
367  if (tmax <= tmin) return false;
368 
369  assert(tmax < std::numeric_limits<double>::max());
370  assert(tmin > -std::numeric_limits<double>::max());
371 
372  // I use projected low and high because they are faster and it does not matter.
373  // The are also necessary for calculating the intersection point with reference time instant 0.0.
374 
375  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
376  {
377  assert(
378  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
379  tmin >= m_startTime && tmax <= m_endTime &&
380  tmin >= r.m_startTime && tmax <= r.m_endTime);
381 
382  // completely above or below in i-th dimension
383  if (
384  (r.getExtrapolatedLow(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) &&
385  r.getExtrapolatedLow(cDim, tmax) >= getExtrapolatedHigh(cDim, tmax)) ||
386  (r.getExtrapolatedHigh(cDim, tmin) < getExtrapolatedLow(cDim, tmin) &&
387  r.getExtrapolatedHigh(cDim, tmax) <= getExtrapolatedLow(cDim, tmax)))
388  return false;
389 
390  // otherwise they intersect inside this interval for sure. Care needs to be taken since
391  // intersection does not necessarily mean that two line segments intersect. It could be
392  // that one line segment is completely above/below another, in which case there is no intersection
393  // point inside tmin, tmax, even though the two region areas do intersect.
394 
395  if (r.getExtrapolatedLow(cDim, tmin) > getExtrapolatedHigh(cDim, tmin)) // r above *this at tmin
396  {
397  tmin = (getExtrapolatedHigh(cDim, 0.0) - r.getExtrapolatedLow(cDim, 0.0)) / (r.getVLow(cDim) - getVHigh(cDim));
398  }
399  else if (r.getExtrapolatedHigh(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) // r below *this at tmin
400  {
401  tmin = (getExtrapolatedLow(cDim, 0.0) - r.getExtrapolatedHigh(cDim, 0.0)) / (r.getVHigh(cDim) - getVLow(cDim));
402  }
403  // else they do not intersect and the boundary might be completely contained in this region.
404 
405  if (r.getExtrapolatedLow(cDim, tmax) > getExtrapolatedHigh(cDim, tmax)) // r above *this at tmax
406  {
407  tmax = (getExtrapolatedHigh(cDim, 0.0) - r.getExtrapolatedLow(cDim, 0.0)) / (r.getVLow(cDim) - getVHigh(cDim));
408  }
409  else if (r.getExtrapolatedHigh(cDim, tmax) < getExtrapolatedLow(cDim, tmax)) // r below *this at tmax
410  {
411  tmax = (getExtrapolatedLow(cDim, 0.0) - r.getExtrapolatedHigh(cDim, 0.0)) / (r.getVHigh(cDim) - getVLow(cDim));
412  }
413  // else they do not intersect and the boundary might be completely contained in this region.
414 
415  assert(tmin <= tmax);
416  }
417 
418  assert(
419  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
420  tmin >= m_startTime && tmax <= m_endTime &&
421  tmin >= r.m_startTime && tmax <= r.m_endTime);
422 
423  ivOut.setBounds(tmin, tmax);
424 
425  return true;
426 }
427 
428 bool MovingRegion::containsRegionInTime(const MovingRegion& r) const
429 {
430  return containsRegionInTime(r, r);
431 }
432 
433 // does not work for shrinking regions.
434 // works fine for infinite bounds (both tmin and tmax).
435 // does not work with degenerate time-intervals.
436 //
437 // finds if during the intersecting time-interval of r and ivPeriod, r is completely contained in *this.
438 bool MovingRegion::containsRegionInTime(const IInterval& ivPeriod, const MovingRegion& r) const
439 {
440  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("containsRegionInTime: MovingRegions have different number of dimensions.");
441 
442  assert(isShrinking() == false && r.isShrinking() == false);
443 
444  double tmin = std::max(ivPeriod.getLowerBound(), r.m_startTime);
445  double tmax = std::min(ivPeriod.getUpperBound(), r.m_endTime);
446 
447  // it should be contained in time.
448  // it does not make sense if this region is not defined for any part ot [tmin, tmax].
449  if (tmax <= tmin || tmin < m_startTime || tmax > m_endTime) return false;
450 
451  double intersectionTime;
452 
453  // no need to take projected coordinates here, since tmin and tmax are always contained in
454  // the regions intersecting time-intervals.
455  assert(
456  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
457  tmin >= m_startTime && tmax <= m_endTime &&
458  tmin >= r.m_startTime && tmax <= r.m_endTime);
459 
460  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
461  {
462  // it should be contained at start time.
463  if (r.getExtrapolatedHigh(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) ||
464  r.getExtrapolatedLow(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) return false;
465 
466  // this will take care of infinite bounds.
467  if (r.m_pVHigh[cDim] != m_pVHigh[cDim])
468  {
469  intersectionTime = (getExtrapolatedHigh(cDim, 0.0) - r.getExtrapolatedHigh(cDim, 0.0)) / (r.m_pVHigh[cDim] - m_pVHigh[cDim]);
470  // if they intersect during this time-interval, then it is not contained.
471  if (tmin < intersectionTime && intersectionTime < tmax) return false;
472  if (tmin == intersectionTime && r.m_pVHigh[cDim] > m_pVHigh[cDim]) return false;
473  }
474 
475  if (r.m_pVLow[cDim] != m_pVLow[cDim])
476  {
477  intersectionTime = (getExtrapolatedLow(cDim, 0.0) - r.getExtrapolatedLow(cDim, 0.0)) / (r.m_pVLow[cDim] - m_pVLow[cDim]);
478  // if they intersect during this time-interval, then it is not contained.
479  if (tmin < intersectionTime && intersectionTime < tmax) return false;
480  if (tmin == intersectionTime && r.m_pVLow[cDim] < m_pVLow[cDim]) return false;
481  }
482  }
483 
484  return true;
485 }
486 
488 {
489  Tools::Interval ivT(t, r.m_endTime);
490  return containsRegionInTime(ivT, r);
491 }
492 
493 // Returns the area swept by the rectangle in time, in d-dimensional space (without
494 // including the temporal dimension, that is).
495 // This is what Saltenis calls Margin (which is different than what Beckmann proposes,
496 // where he computes only the wireframe -- instead of the surface/volume/etc. -- of the MBR in any dimension).
498 {
499  return getProjectedSurfaceAreaInTime(*this);
500 }
501 
502 double MovingRegion::getProjectedSurfaceAreaInTime(const IInterval& ivI) const
503 {
504  double tmin = std::max(ivI.getLowerBound(), m_startTime);
505  double tmax = std::min(ivI.getUpperBound(), m_endTime);
506 
507  assert(tmin > -std::numeric_limits<double>::max());
508  assert(tmax < std::numeric_limits<double>::max());
509  assert(tmin <= tmax);
510 
511  if (tmin >= tmax - std::numeric_limits<double>::epsilon() &&
512  tmin <= tmax + std::numeric_limits<double>::epsilon())
513  return 0.0;
514 
515  double dx1, dx2, dx3;
516  double dv1, dv2, dv3;
517  double H = tmax - tmin;
518 
519  if (m_dimension == 3)
520  {
521  dx3 = getExtrapolatedHigh(2, tmin) - getExtrapolatedLow(2, tmin);
522  dv3 = getVHigh(2) - getVLow(2);
523  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
524  dv2 = getVHigh(1) - getVLow(1);
525  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
526  dv1 = getVHigh(0) - getVLow(0);
527  return
528  H * (dx1 + dx2 + dx3 + dx1*dx2 + dx1*dx3 + dx2*dx3) +
529  H*H * (dv1 + dv2 + dv3 + dx1*dv2 + dv1*dx2 + dx1*dv3 +
530  dv1*dx3 + dx2*dv3 + dv2*dx3) / 2.0 +
531  H*H*H * (dv1*dv2 + dv1*dv3 + dv2*dv3) / 3.0;
532  }
533  else if (m_dimension == 2)
534  {
535  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
536  dv2 = getVHigh(1) - getVLow(1);
537  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
538  dv1 = getVHigh(0) - getVLow(0);
539  return H * (dx1 + dx2) + H * H * (dv1 + dv2) / 2.0;
540  }
541  else if (m_dimension == 1)
542  {
543  // marioh: why not use the increase of the length of the interval here?
544  return 0.0;
545  }
546  else
547  {
548  throw Tools::IllegalStateException("getProjectedSurfaceAreaInTime: unsupported dimensionality.");
549  }
550 }
551 
553 {
554 
555  return getCenterDistanceInTime(r, r);
556 }
557 
558 double MovingRegion::getCenterDistanceInTime(const IInterval& ivI, const MovingRegion& r) const
559 {
560  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("getCenterDistanceInTime: MovingRegions have different number of dimensions.");
561 
562  assert(m_startTime < m_endTime);
563  assert(r.m_startTime < r.m_endTime);
564  assert(ivI.getLowerBound() < ivI.getUpperBound());
565 
566  double tmin = std::max(m_startTime, r.m_startTime);
567  double tmax = std::min(m_endTime, r.m_endTime);
568 
569  // the regions do not intersect in time.
570  if (tmax <= tmin) return 0.0;
571 
572  tmin = std::max(tmin, ivI.getLowerBound());
573  tmax = std::min(tmax, ivI.getUpperBound());
574 
575  // the regions intersecting interval does not intersect with the given time period.
576  if (tmax <= tmin) return 0.0;
577 
578  assert(tmax < std::numeric_limits<double>::max());
579  assert(tmin > -std::numeric_limits<double>::max());
580 
581  if (tmin >= tmax - std::numeric_limits<double>::epsilon() &&
582  tmin <= tmax + std::numeric_limits<double>::epsilon())
583  return 0.0;
584 
585  double H = tmax - tmin;
586 
587  double* dx = new double[m_dimension];
588  double* dv = new double[m_dimension];
589  double a = 0.0, b = 0.0, c = 0.0, f = 0.0, l = 0.0, m = 0.0, n = 0.0;
590 
591  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
592  {
593  dx[cDim] =
594  (r.getExtrapolatedLow(cDim, tmin) + r.getExtrapolatedHigh(cDim, tmin)) / 2.0 -
595  (getExtrapolatedLow(cDim, tmin) + getExtrapolatedHigh(cDim, tmin)) / 2.0;
596  dv[cDim] =
597  (r.getVLow(cDim) + r.getVHigh(cDim)) / 2.0 -
598  (getVLow(cDim) + getVHigh(cDim)) / 2.0;
599  }
600 
601  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
602  {
603  a += dv[cDim] * dv[cDim];
604  b += 2.0 * dx[cDim] * dv[cDim];
605  c += dx[cDim] * dx[cDim];
606  }
607 
608  delete[] dx;
609  delete[] dv;
610 
611  if (a == 0.0 && c == 0.0) return 0.0;
612  if (a == 0.0) return H * std::sqrt(c);
613  if (c == 0.0) return H * H * std::sqrt(a) / 2.0;
614 
615  f = std::sqrt(a * H * H + b * H + c);
616  l = 2.0 * a * H + b;
617  m = 4.0 * a * c - b * b;
618  n = 2.0 * std::sqrt(a);
619 
620  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);
621 }
622 
623 // does not work with degenerate time-intervals.
625 {
626  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("intersectsRegionAtTime: MovingRegions have different number of dimensions.");
627 
628  // do they contain the time instant?
629  if (! (m_startTime <= t && t < m_endTime && r.m_startTime <= t && t < r.m_endTime)) return false;
630 
631  // do they intersect at that time instant?
632  for (uint32_t i = 0; i < m_dimension; ++i)
633  {
634  if (getExtrapolatedLow(i, t) > r.getExtrapolatedHigh(i, t) || getExtrapolatedHigh(i, t) < r.getExtrapolatedLow(i, t)) return false;
635  }
636  return true;
637 }
638 
639 // does not work with degenerate time-intervals.
640 bool MovingRegion::containsRegionAtTime(double t, const MovingRegion& r) const
641 {
642  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("containsRegionAtTime: MovingRegions have different number of dimensions.");
643 
644  // do they contain the time instant?
645  if (! (m_startTime <= t && t < m_endTime && r.m_startTime <= t && t < r.m_endTime)) return false;
646 
647  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
648  {
649  if (getExtrapolatedLow(cDim, t) > r.getExtrapolatedLow(cDim, t) || getExtrapolatedHigh(cDim, t) < r.getExtrapolatedHigh(cDim, t)) return false;
650  }
651  return true;
652 }
653 
655 {
656  Tools::Interval ivOut;
657  return intersectsPointInTime(p, ivOut);
658 }
659 
660 bool MovingRegion::intersectsPointInTime(const MovingPoint& p, IInterval& ivOut) const
661 {
662  return intersectsPointInTime(p, p, ivOut);
663 }
664 
665 // if tmin, tmax are infinity then this will not work correctly (everything will always intersect).
666 // does not work for shrinking regions.
667 // does not work with degenerate time-intervals.
668 // FIXME: don't know what happens if tmin is negative infinity.
669 //
670 // WARNING: This will return true even if the region completely contains the point, since
671 // in that case the point trajectory intersects the region area!
672 bool MovingRegion::intersectsPointInTime(const IInterval& ivPeriod, const MovingPoint& p, IInterval& ivOut) const
673 {
674  if (m_dimension != p.m_dimension) throw Tools::IllegalArgumentException("intersectsPointInTime: MovingPoint has different number of dimensions.");
675 
676  assert(m_startTime < m_endTime);
677  assert(p.m_startTime < p.m_endTime);
678  assert(ivPeriod.getLowerBound() < ivPeriod.getUpperBound());
679  assert(isShrinking() == false);
680 
681  if (containsPointInTime(ivPeriod, p))
682  {
683  ivOut = ivPeriod;
684  return true;
685  }
686 
687  double tmin = std::max(m_startTime, p.m_startTime);
688  double tmax = std::min(m_endTime, p.m_endTime);
689 
690  // the shapes do not intersect in time.
691  if (tmax <= tmin) return false;
692 
693  tmin = std::max(tmin, ivPeriod.getLowerBound());
694  tmax = std::min(tmax, ivPeriod.getUpperBound());
695 
696  // the shapes intersecting interval does not intersect with the given time period.
697  if (tmax <= tmin) return false;
698 
699  assert(tmax < std::numeric_limits<double>::max());
700  assert(tmin > -std::numeric_limits<double>::max());
701 
702  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
703  {
704  assert(
705  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
706  tmin >= m_startTime && tmax <= m_endTime &&
707  tmin >= p.m_startTime && tmax <= p.m_endTime);
708 
709  // completely above or below in i-th dimension
710  if ((p.getProjectedCoord(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) &&
711  p.getProjectedCoord(cDim, tmax) >= getExtrapolatedHigh(cDim, tmax)) ||
712  (p.getProjectedCoord(cDim, tmin) < getExtrapolatedLow(cDim, tmin) &&
713  p.getProjectedCoord(cDim, tmax) <= getExtrapolatedLow(cDim, tmax)))
714  return false;
715 
716  // otherwise they intersect inside this interval for sure, since we know that the point is not contained,
717  // so there is no need to check for 0 divisors, negative values, etc...
718 
719  // adjust tmin
720  if (p.getProjectedCoord(cDim, tmin) > getExtrapolatedHigh(cDim, tmin)) // p above *this at tmin
721  {
722  tmin = (getExtrapolatedHigh(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVHigh(cDim));
723  }
724  else if (p.getProjectedCoord(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) // p below *this at tmin
725  {
726  tmin = (getExtrapolatedLow(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVLow(cDim));
727  }
728 
729  // adjust tmax
730  if (p.getProjectedCoord(cDim, tmax) > getExtrapolatedHigh(cDim, tmax)) // p above *this at tmax
731  {
732  tmax = (getExtrapolatedHigh(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVHigh(cDim));
733  }
734  else if (p.getProjectedCoord(cDim, tmax) < getExtrapolatedLow(cDim, tmax)) // p below *this at tmax
735  {
736  tmax = (getExtrapolatedLow(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.getVCoord(cDim) - getVLow(cDim));
737  }
738 
739  if (tmin > tmax) return false;
740  }
741 
742  ivOut.setBounds(tmin, tmax);
743 
744  return true;
745 }
746 
747 bool MovingRegion::containsPointInTime(const MovingPoint& p) const
748 {
749  return containsPointInTime(p, p);
750 }
751 
752 // does not work for shrinking regions.
753 // works fine for infinite bounds (both tmin and tmax).
754 // does not work with degenerate time-intervals.
755 //
756 // finds if during the intersecting time-interval of p and ivPeriod, p is completely contained in *this.
757 bool MovingRegion::containsPointInTime(const IInterval& ivPeriod, const MovingPoint& p) const
758 {
759  if (m_dimension != p.m_dimension) throw Tools::IllegalArgumentException("containsPointInTime: MovingPoint has different number of dimensions.");
760 
761  assert(isShrinking() == false);
762 
763  double tmin = std::max(ivPeriod.getLowerBound(), p.m_startTime);
764  double tmax = std::min(ivPeriod.getUpperBound(), p.m_endTime);
765 
766  // it should be contained in time.
767  if (tmax <= tmin || tmin < m_startTime || tmax > m_endTime) return false;
768 
769  double intersectionTime;
770 
771  assert(
772  tmin >= ivPeriod.getLowerBound() && tmax <= ivPeriod.getUpperBound() &&
773  tmin >= m_startTime && tmax <= m_endTime &&
774  tmin >= p.m_startTime && tmax <= p.m_endTime);
775 
776  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
777  {
778  // it should be contained at start time.
779  if (p.getProjectedCoord(cDim, tmin) > getExtrapolatedHigh(cDim, tmin) ||
780  p.getProjectedCoord(cDim, tmin) < getExtrapolatedLow(cDim, tmin)) return false;
781 
782  if (p.m_pVCoords[cDim] != m_pVHigh[cDim])
783  {
784  intersectionTime = (getExtrapolatedHigh(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.m_pVCoords[cDim] - m_pVHigh[cDim]);
785  // if they intersect during this time-interval, then it is not contained.
786  if (tmin < intersectionTime && intersectionTime < tmax) return false;
787  if (tmin == intersectionTime && p.m_pVCoords[cDim] > m_pVHigh[cDim]) return false;
788  }
789 
790  if (p.m_pVCoords[cDim] != m_pVLow[cDim])
791  {
792  intersectionTime = (getExtrapolatedLow(cDim, 0.0) - p.getProjectedCoord(cDim, 0.0)) / (p.m_pVCoords[cDim] - m_pVLow[cDim]);
793  // if they intersect during this time-interval, then it is not contained.
794  if (tmin < intersectionTime && intersectionTime < tmax) return false;
795  if (tmin == intersectionTime && p.m_pVCoords[cDim] < m_pVLow[cDim]) return false;
796  }
797  }
798 
799  return true;
800 }
801 
802 void MovingRegion::combineRegionInTime(const MovingRegion& r)
803 {
804  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("combineRegionInTime: MovingRegions have different number of dimensions.");
805 
806  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
807  {
808  m_pLow[cDim] = std::min(getExtrapolatedLow(cDim, m_startTime), r.getExtrapolatedLow(cDim, m_startTime));
809  m_pHigh[cDim] = std::max(getExtrapolatedHigh(cDim, m_startTime), r.getExtrapolatedHigh(cDim, m_startTime));
810  m_pVLow[cDim] = std::min(m_pVLow[cDim], r.m_pVLow[cDim]);
811  m_pVHigh[cDim] = std::max(m_pVHigh[cDim], r.m_pVHigh[cDim]);
812  }
813 
814  // m_startTime should be modified at the end, since it affects the
815  // calculation of extrapolated coordinates.
816  m_startTime = std::min(m_startTime, r.m_startTime);
817  m_endTime = std::max(m_endTime, r.m_endTime);
818 }
819 
820 void MovingRegion::getCombinedRegionInTime(MovingRegion& out, const MovingRegion& in) const
821 {
822  if (m_dimension != in.m_dimension) throw Tools::IllegalArgumentException("getCombinedProjectedRegionInTime: MovingRegions have different number of dimensions.");
823 
824  out = *this;
825  out.combineRegionInTime(in);
826 }
827 
829 {
830  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("combineRegionInTime: MovingRegions have different number of dimensions.");
831 
832  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
833  {
834  m_pLow[cDim] = std::min(getExtrapolatedLow(cDim, t), r.getExtrapolatedLow(cDim, t));
835  m_pHigh[cDim] = std::max(getExtrapolatedHigh(cDim, t), r.getExtrapolatedHigh(cDim, t));
836  m_pVLow[cDim] = std::min(m_pVLow[cDim], r.m_pVLow[cDim]);
837  m_pVHigh[cDim] = std::max(m_pVHigh[cDim], r.m_pVHigh[cDim]);
838  }
839 
840  // m_startTime should be modified at the end, since it affects the
841  // calculation of extrapolated coordinates.
842  m_startTime = t;
843  m_endTime = std::max(m_endTime, r.m_endTime);
844  if (t >= m_endTime) m_endTime = std::numeric_limits<double>::max();
845 }
846 
848 {
849  if (m_dimension != in.m_dimension) throw Tools::IllegalArgumentException("getCombinedProjectedRegionInTime: MovingRegions have different number of dimensions.");
850 
851  out = *this;
852  out.combineRegionAfterTime(t, in);
853 }
854 
856 {
857  return getIntersectingAreaInTime(r, r);
858 }
859 
860 double MovingRegion::getIntersectingAreaInTime(const IInterval& ivI, const MovingRegion& r) const
861 {
862  if (m_dimension != r.m_dimension) throw Tools::IllegalArgumentException("getIntersectingAreaInTime: MovingRegions have different number of dimensions.");
863 
864  assert(m_startTime < m_endTime);
865  assert(r.m_startTime < r.m_endTime);
866  assert(ivI.getLowerBound() < ivI.getUpperBound());
867  assert(isShrinking() == false && r.isShrinking() == false);
868 
869  double tmin = std::max(m_startTime, r.m_startTime);
870  double tmax = std::min(m_endTime, r.m_endTime);
871 
872  // the regions do not intersect in time.
873  if (tmax <= tmin) return 0.0;
874 
875  tmin = std::max(tmin, ivI.getLowerBound());
876  tmax = std::min(tmax, ivI.getUpperBound());
877 
878  // the regions intersecting interval does not intersect with the given time period.
879  if (tmax <= tmin) return 0.0;
880 
881  assert(tmax < std::numeric_limits<double>::max());
882  assert(tmin > -std::numeric_limits<double>::max());
883 
884  Tools::Interval ivIn(tmin, tmax);
885  Tools::Interval ivOut(ivIn);
886 
887  if (! intersectsRegionInTime(ivIn, r, ivOut)) return 0.0;
888 
889  ivIn = ivOut;
890  tmin = ivIn.getLowerBound();
891  tmax = ivIn.getUpperBound();
892  assert(tmin <= tmax);
893 
894  assert(tmin >= ivI.getLowerBound() && tmax <= ivI.getUpperBound());
895 
896  if (containsRegionInTime(ivIn, r))
897  {
898  return r.getAreaInTime(ivIn);
899  }
900  else if (r.containsRegionInTime(ivIn, *this))
901  {
902  return getAreaInTime(ivIn);
903  }
904 
905  MovingRegion x = *this;
906  CrossPoint c;
907  auto ascending = [](CrossPoint& lhs, CrossPoint& rhs) { return lhs.m_t > rhs.m_t; };
908  std::priority_queue < CrossPoint, std::vector<CrossPoint>, decltype(ascending)> pq(ascending);
909 
910  // find points of intersection in all dimensions.
911  for (uint32_t i = 0; i < m_dimension; ++i)
912  {
913  if (getLow(i, tmin) > r.getLow(i, tmin))
914  {
915  x.m_pLow[i] = m_pLow[i];
916  x.m_pVLow[i] = m_pVLow[i];
917 
918  if (getLow(i, tmax) < r.getLow(i, tmax))
919  {
920  c.m_dimension = i;
921  c.m_boundary = 0;
922  c.m_t = (getExtrapolatedLow(i, 0.0) - r.getExtrapolatedLow(i, 0.0)) / (r.getVLow(i) - getVLow(i));
923  assert(c.m_t >= tmin && c.m_t <= tmax);
924  c.m_to = &r;
925  pq.push(c);
926  }
927  }
928  else
929  {
930  x.m_pLow[i] = r.m_pLow[i];
931  x.m_pVLow[i] = r.m_pVLow[i];
932 
933  if (r.getLow(i, tmax) < getLow(i, tmax))
934  {
935  c.m_dimension = i;
936  c.m_boundary = 0;
937  c.m_t = (getExtrapolatedLow(i, 0.0) - r.getExtrapolatedLow(i, 0.0)) / (r.getVLow(i) - getVLow(i));
938  assert(c.m_t >= tmin && c.m_t <= tmax);
939  c.m_to = this;
940  pq.push(c);
941  }
942  }
943 
944  if (getHigh(i, tmin) < r.getHigh(i, tmin))
945  {
946  x.m_pHigh[i] = m_pHigh[i];
947  x.m_pVHigh[i] = m_pVHigh[i];
948 
949  if (getHigh(i, tmax) > r.getHigh(i, tmax))
950  {
951  c.m_dimension = i;
952  c.m_boundary = 1;
953  c.m_t = (getExtrapolatedHigh(i, 0.0) - r.getExtrapolatedHigh(i, 0.0)) / (r.getVHigh(i) - getVHigh(i));
954  assert(c.m_t >= tmin && c.m_t <= tmax);
955  c.m_to = &r;
956  pq.push(c);
957  }
958  }
959  else
960  {
961  x.m_pHigh[i] = r.m_pHigh[i];
962  x.m_pVHigh[i] = r.m_pVHigh[i];
963 
964  if (r.getHigh(i, tmax) > getHigh(i, tmax))
965  {
966  c.m_dimension = i;
967  c.m_boundary = 1;
968  c.m_t = (getExtrapolatedHigh(i, 0.0) - r.getExtrapolatedHigh(i, 0.0)) / (r.getVHigh(i) - getVHigh(i));
969  assert(c.m_t >= tmin && c.m_t <= tmax);
970  c.m_to = this;
971  pq.push(c);
972  }
973  }
974  }
975 
976  // add up the total area of the intersecting pieces.
977  double area = 0.0;
978 
979  while (! pq.empty())
980  {
981  c = pq.top(); pq.pop();
982 
983  // needed in case two consecutive points have the same intersection time.
984  if (c.m_t > tmin) area += x.getAreaInTime(Tools::Interval(tmin, c.m_t));
985 
986  if (c.m_boundary == 0)
987  {
988  x.m_pLow[c.m_dimension] = c.m_to->m_pLow[c.m_dimension];
989  x.m_pVLow[c.m_dimension] = c.m_to->m_pVLow[c.m_dimension];
990  }
991  else
992  {
993  x.m_pHigh[c.m_dimension] = c.m_to->m_pHigh[c.m_dimension];
994  x.m_pVHigh[c.m_dimension] = c.m_to->m_pVHigh[c.m_dimension];
995  }
996 
997  tmin = c.m_t;
998  }
999 
1000  // ... and the last piece
1001  if (tmax > tmin) area += x.getAreaInTime(Tools::Interval(tmin, tmax));
1002 
1003  return area;
1004 }
1005 
1006 //
1007 // IObject interface
1008 //
1010 {
1011  return new MovingRegion(*this);
1012 }
1013 
1014 //
1015 // ISerializable interface
1016 //
1018 {
1019  return (sizeof(uint32_t) + 2 * sizeof(double) + 4 * m_dimension * sizeof(double));
1020 }
1021 
1022 void MovingRegion::loadFromByteArray(const uint8_t* ptr)
1023 {
1024  uint32_t dimension;
1025 
1026  memcpy(&dimension, ptr, sizeof(uint32_t));
1027  ptr += sizeof(uint32_t);
1028  memcpy(&m_startTime, ptr, sizeof(double));
1029  ptr += sizeof(double);
1030  memcpy(&m_endTime, ptr, sizeof(double));
1031  ptr += sizeof(double);
1032 
1033  makeDimension(dimension);
1034  memcpy(m_pLow, ptr, m_dimension * sizeof(double));
1035  ptr += m_dimension * sizeof(double);
1036  memcpy(m_pHigh, ptr, m_dimension * sizeof(double));
1037  ptr += m_dimension * sizeof(double);
1038  memcpy(m_pVLow, ptr, m_dimension * sizeof(double));
1039  ptr += m_dimension * sizeof(double);
1040  memcpy(m_pVHigh, ptr, m_dimension * sizeof(double));
1041  //ptr += m_dimension * sizeof(double);
1042 }
1043 
1044 void MovingRegion::storeToByteArray(uint8_t** data, uint32_t& len)
1045 {
1046  len = getByteArraySize();
1047  *data = new uint8_t[len];
1048  uint8_t* ptr = *data;
1049 
1050  memcpy(ptr, &m_dimension, sizeof(uint32_t));
1051  ptr += sizeof(uint32_t);
1052  memcpy(ptr, &m_startTime, sizeof(double));
1053  ptr += sizeof(double);
1054  memcpy(ptr, &m_endTime, sizeof(double));
1055  ptr += sizeof(double);
1056 
1057  memcpy(ptr, m_pLow, m_dimension * sizeof(double));
1058  ptr += m_dimension * sizeof(double);
1059  memcpy(ptr, m_pHigh, m_dimension * sizeof(double));
1060  ptr += m_dimension * sizeof(double);
1061  memcpy(ptr, m_pVLow, m_dimension * sizeof(double));
1062  ptr += m_dimension * sizeof(double);
1063  memcpy(ptr, m_pVHigh, m_dimension * sizeof(double));
1064  //ptr += m_dimension * sizeof(double);
1065 }
1066 
1067 //
1068 // IEvolvingShape interface
1069 //
1071 {
1073  memcpy(out.m_pLow, m_pVLow, m_dimension * sizeof(double));
1074  memcpy(out.m_pHigh, m_pVHigh, m_dimension * sizeof(double));
1075 }
1076 
1077 void MovingRegion::getMBRAtTime(double t, Region& out) const
1078 {
1080  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
1081  {
1082  out.m_pLow[cDim] = getLow(cDim, t);
1083  out.m_pHigh[cDim] = getHigh(cDim, t);
1084  }
1085 }
1086 
1087 //
1088 // ITimeShape interface
1089 //
1091 {
1092  return getAreaInTime(*this);
1093 }
1094 
1095 // this computes the area/volume/etc. swept by the Region in time.
1096 double MovingRegion::getAreaInTime(const IInterval& ivI) const
1097 {
1098  double tmin = std::max(ivI.getLowerBound(), m_startTime);
1099  double tmax = std::min(ivI.getUpperBound(), m_endTime);
1100 
1101  assert(tmin > -std::numeric_limits<double>::max());
1102  assert(tmax < std::numeric_limits<double>::max());
1103  assert(tmin <= tmax);
1104 
1105  if (tmin >= tmax - std::numeric_limits<double>::epsilon() &&
1106  tmin <= tmax + std::numeric_limits<double>::epsilon())
1107  return 0.0;
1108 
1109  double dx1, dx2, dx3;
1110  double dv1, dv2, dv3;
1111  double H = tmax - tmin;
1112 
1113  if (m_dimension == 3)
1114  {
1115  dx3 = getExtrapolatedHigh(2, tmin) - getExtrapolatedLow(2, tmin);
1116  dv3 = getVHigh(2) - getVLow(2);
1117  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
1118  dv2 = getVHigh(1) - getVLow(1);
1119  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
1120  dv1 = getVHigh(0) - getVLow(0);
1121  return
1122  H * dx1 * dx2 * dx3 + H * H * (dx1 * dx2 * dv3 + (dx1 * dv2 + dv1 * dx2) * dx3) / 2.0 +
1123  H * H * H * ((dx1 * dv2 + dv1 * dx2) * dv3 + dv1 * dv2 * dx3) / 3.0 + H * H * H * H * dv1 * dv2 * dv3 / 4.0;
1124  }
1125  else if (m_dimension == 2)
1126  {
1127  dx2 = getExtrapolatedHigh(1, tmin) - getExtrapolatedLow(1, tmin);
1128  dv2 = getVHigh(1) - getVLow(1);
1129  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
1130  dv1 = getVHigh(0) - getVLow(0);
1131  return H * dx1 * dx2 + H * H * (dx1 * dv2 + dv1 * dx2) / 2.0 + H * H * H * dv1 * dv2 / 3.0;
1132  }
1133  else if (m_dimension == 1)
1134  {
1135  dx1 = getExtrapolatedHigh(0, tmin) - getExtrapolatedLow(0, tmin);
1136  dv1 = getVHigh(0) - getVLow(0);
1137  return H * dx1 + H * H * dv1 / 2.0;
1138  }
1139  else
1140  {
1141  throw Tools::NotSupportedException("getAreaInTime: unsupported dimensionality.");
1142  }
1143 }
1144 
1146 {
1147  return getIntersectingAreaInTime(r, r);
1148 }
1149 
1150 double MovingRegion::getIntersectingAreaInTime(const IInterval&, const ITimeShape& in) const
1151 {
1152  const MovingRegion* pr = dynamic_cast<const MovingRegion*>(&in);
1153  if (pr != nullptr) return getIntersectingAreaInTime(*pr);
1154 
1155  throw Tools::IllegalStateException("getIntersectingAreaInTime: Not implemented yet!");
1156 }
1157 
1158 void MovingRegion::makeInfinite(uint32_t dimension)
1159 {
1160  makeDimension(dimension);
1161  for (uint32_t cIndex = 0; cIndex < m_dimension; ++cIndex)
1162  {
1163  m_pLow[cIndex] = std::numeric_limits<double>::max();
1164  m_pHigh[cIndex] = -std::numeric_limits<double>::max();
1165  m_pVLow[cIndex] = std::numeric_limits<double>::max();
1166  m_pVHigh[cIndex] = -std::numeric_limits<double>::max();
1167  }
1168 
1169  m_startTime = -std::numeric_limits<double>::max();
1170  m_endTime = std::numeric_limits<double>::max();
1171 }
1172 
1173 void MovingRegion::makeDimension(uint32_t dimension)
1174 {
1175  if (m_dimension != dimension)
1176  {
1177  delete[] m_pLow;
1178  delete[] m_pHigh;
1179  delete[] m_pVLow;
1180  delete[] m_pVHigh;
1181  m_pLow = nullptr; m_pHigh = nullptr;
1182  m_pVLow = nullptr; m_pVHigh = nullptr;
1183 
1184  m_dimension = dimension;
1185  m_pLow = new double[m_dimension];
1186  m_pHigh = new double[m_dimension];
1187  m_pVLow = new double[m_dimension];
1188  m_pVHigh = new double[m_dimension];
1189  }
1190 }
1191 
1192 std::ostream& SpatialIndex::operator<<(std::ostream& os, const MovingRegion& r)
1193 {
1194  uint32_t i;
1195 
1196  os << "Low: ";
1197  for (i = 0; i < r.m_dimension; ++i)
1198  {
1199  os << r.m_pLow[i] << " ";
1200  }
1201 
1202  os << ", High: ";
1203 
1204  for (i = 0; i < r.m_dimension; ++i)
1205  {
1206  os << r.m_pHigh[i] << " ";
1207  }
1208 
1209  os << "VLow: ";
1210  for (i = 0; i < r.m_dimension; ++i)
1211  {
1212  os << r.m_pVLow[i] << " ";
1213  }
1214 
1215  os << ", VHigh: ";
1216 
1217  for (i = 0; i < r.m_dimension; ++i)
1218  {
1219  os << r.m_pVHigh[i] << " ";
1220  }
1221 
1222  os << ", Start: " << r.m_startTime << ", End: " << r.m_endTime;
1223 
1224  return os;
1225 }
virtual double getVCoord(uint32_t index) const
Definition: MovingPoint.cc:196
virtual double getProjectedCoord(uint32_t index, double t) const
Definition: MovingPoint.cc:189
virtual bool intersectsRegionAtTime(double t, const MovingRegion &r) const
virtual bool containsRegionInTime(const MovingRegion &r) const
virtual bool operator==(const MovingRegion &) const
void getVMBR(Region &out) const override
virtual void combineRegionInTime(const MovingRegion &r)
virtual double getVLow(uint32_t index) const
void makeDimension(uint32_t dimension) override
virtual bool containsPointInTime(const MovingPoint &p) const
virtual double getCenterDistanceInTime(const MovingRegion &r) const
void loadFromByteArray(const uint8_t *data) override
void storeToByteArray(uint8_t **data, uint32_t &len) override
double getAreaInTime() const override
uint32_t getByteArraySize() override
virtual bool containsRegionAfterTime(double t, const MovingRegion &r) const
virtual double getVHigh(uint32_t index) const
virtual bool intersectsPointInTime(const MovingPoint &p) const
virtual void getCombinedRegionAfterTime(double t, MovingRegion &out, const MovingRegion &in) const
virtual double getIntersectingAreaInTime(const MovingRegion &r) const
virtual void combineRegionAfterTime(double t, const MovingRegion &r)
virtual bool intersectsRegionInTime(const MovingRegion &r) const
virtual double getProjectedSurfaceAreaInTime() const
virtual double getHigh(uint32_t index, double t) const
void makeInfinite(uint32_t dimension) override
virtual bool containsRegionAtTime(double t, const MovingRegion &r) const
virtual double getExtrapolatedLow(uint32_t index, double t) const
void getMBRAtTime(double t, Region &out) const override
MovingRegion * clone() override
virtual MovingRegion & operator=(const MovingRegion &r)
virtual double getLow(uint32_t index, double t) const
virtual double getExtrapolatedHigh(uint32_t index, double t) const
double * m_pCoords
Definition: Point.h:80
uint32_t m_dimension
Definition: Point.h:79
double * m_pHigh
Definition: Region.h:101
uint32_t m_dimension
Definition: Region.h:99
virtual void makeDimension(uint32_t dimension)
Definition: Region.cc:540
double * m_pLow
Definition: Region.h:100
SIDX_DLL std::ostream & operator<<(std::ostream &os, const Ball &ball)
Definition: Ball.cc:215