libspatialindex API Reference  (git-trunk)
Region.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 
29 
30 #include <cstring>
31 #include <cmath>
32 #include <limits>
33 
34 using namespace SpatialIndex;
35 
37 = default;
38 
39 Region::Region(const double* pLow, const double* pHigh, uint32_t dimension)
40 {
41  initialize(pLow, pHigh, dimension);
42 }
43 
44 Region::Region(const Point& low, const Point& high)
45 {
46  if (low.m_dimension != high.m_dimension)
48  "Region::Region: arguments have different number of dimensions."
49  );
50 
51  initialize(low.m_pCoords, high.m_pCoords, low.m_dimension);
52 }
53 
55 {
56  initialize(r.m_pLow, r.m_pHigh, r.m_dimension);
57 }
58 
59 void Region::initialize(const double* pLow, const double* pHigh, uint32_t dimension)
60 {
61  m_pLow = nullptr;
62  m_dimension = dimension;
63 
64 #ifndef NDEBUG
65  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
66  {
67  if ((pLow[cDim] > pHigh[cDim]))
68  {
69  // check for infinitive region
70  if (!(pLow[cDim] == std::numeric_limits<double>::max() ||
71  pHigh[cDim] == -std::numeric_limits<double>::max() ))
73  "Region::initialize: Low point has larger coordinates than High point."
74  " Neither point is infinity."
75  );
76  }
77  }
78 #endif
79 
80  try
81  {
82  m_pLow = new double[m_dimension];
83  m_pHigh = new double[m_dimension];
84  }
85  catch (...)
86  {
87  delete[] m_pLow;
88  throw;
89  }
90 
91  memcpy(m_pLow, pLow, m_dimension * sizeof(double));
92  memcpy(m_pHigh, pHigh, m_dimension * sizeof(double));
93 }
94 
96 {
97  delete[] m_pLow;
98  delete[] m_pHigh;
99 }
100 
102 {
103  if(this != &r)
104  {
106  memcpy(m_pLow, r.m_pLow, m_dimension * sizeof(double));
107  memcpy(m_pHigh, r.m_pHigh, m_dimension * sizeof(double));
108  }
109 
110  return *this;
111 }
112 
113 bool Region::operator==(const Region& r) const
114 {
115  if (m_dimension != r.m_dimension)
117  "Region::operator==: Regions have different number of dimensions."
118  );
119 
120  for (uint32_t i = 0; i < m_dimension; ++i)
121  {
122  if (
123  m_pLow[i] < r.m_pLow[i] - std::numeric_limits<double>::epsilon() ||
124  m_pLow[i] > r.m_pLow[i] + std::numeric_limits<double>::epsilon() ||
125  m_pHigh[i] < r.m_pHigh[i] - std::numeric_limits<double>::epsilon() ||
126  m_pHigh[i] > r.m_pHigh[i] + std::numeric_limits<double>::epsilon())
127  return false;
128  }
129  return true;
130 }
131 
132 //
133 // IObject interface
134 //
136 {
137  return new Region(*this);
138 }
139 
140 //
141 // ISerializable interface
142 //
144 {
145  return (sizeof(uint32_t) + 2 * m_dimension * sizeof(double));
146 }
147 
148 void Region::loadFromByteArray(const uint8_t* ptr)
149 {
150  uint32_t dimension;
151  memcpy(&dimension, ptr, sizeof(uint32_t));
152  ptr += sizeof(uint32_t);
153 
154  makeDimension(dimension);
155  memcpy(m_pLow, ptr, m_dimension * sizeof(double));
156  ptr += m_dimension * sizeof(double);
157  memcpy(m_pHigh, ptr, m_dimension * sizeof(double));
158  //ptr += m_dimension * sizeof(double);
159 }
160 
161 void Region::storeToByteArray(uint8_t** data, uint32_t& len)
162 {
163  len = getByteArraySize();
164  *data = new uint8_t[len];
165  uint8_t* ptr = *data;
166 
167  memcpy(ptr, &m_dimension, sizeof(uint32_t));
168  ptr += sizeof(uint32_t);
169  memcpy(ptr, m_pLow, m_dimension * sizeof(double));
170  ptr += m_dimension * sizeof(double);
171  memcpy(ptr, m_pHigh, m_dimension * sizeof(double));
172  //ptr += m_dimension * sizeof(double);
173 }
174 
175 //
176 // IShape interface
177 //
178 bool Region::intersectsShape(const IShape& s) const
179 {
180  const Region* pr = dynamic_cast<const Region*>(&s);
181  if (pr != nullptr) return intersectsRegion(*pr);
182 
183  const LineSegment* pls = dynamic_cast<const LineSegment*>(&s);
184  if (pls != nullptr) return intersectsLineSegment(*pls);
185 
186  const Point* ppt = dynamic_cast<const Point*>(&s);
187  if (ppt != nullptr) return containsPoint(*ppt);
188 
190  "Region::intersectsShape: Not implemented yet!"
191  );
192 }
193 
194 bool Region::containsShape(const IShape& s) const
195 {
196  const Region* pr = dynamic_cast<const Region*>(&s);
197  if (pr != nullptr) return containsRegion(*pr);
198 
199  const Point* ppt = dynamic_cast<const Point*>(&s);
200  if (ppt != nullptr) return containsPoint(*ppt);
201 
203  "Region::containsShape: Not implemented yet!"
204  );
205 }
206 
207 bool Region::touchesShape(const IShape& s) const
208 {
209  const Region* pr = dynamic_cast<const Region*>(&s);
210  if (pr != nullptr) return touchesRegion(*pr);
211 
212  const Point* ppt = dynamic_cast<const Point*>(&s);
213  if (ppt != nullptr) return touchesPoint(*ppt);
214 
216  "Region::touchesShape: Not implemented yet!"
217  );
218 }
219 
220 void Region::getCenter(Point& out) const
221 {
223  for (uint32_t i = 0; i < m_dimension; ++i)
224  {
225  out.m_pCoords[i] = (m_pLow[i] + m_pHigh[i]) / 2.0;
226  }
227 }
228 
229 uint32_t Region::getDimension() const
230 {
231  return m_dimension;
232 }
233 
234 void Region::getMBR(Region& out) const
235 {
236  out = *this;
237 }
238 
239 double Region::getArea() const
240 {
241  double area = 1.0;
242 
243  for (uint32_t i = 0; i < m_dimension; ++i)
244  {
245  area *= m_pHigh[i] - m_pLow[i];
246  }
247 
248  return area;
249 }
250 
251 double Region::getMinimumDistance(const IShape& s) const
252 {
253  const Region* pr = dynamic_cast<const Region*>(&s);
254  if (pr != nullptr) return getMinimumDistance(*pr);
255 
256  const Point* ppt = dynamic_cast<const Point*>(&s);
257  if (ppt != nullptr) return getMinimumDistance(*ppt);
258 
260  "Region::getMinimumDistance: Not implemented yet!"
261  );
262 }
263 
264 bool Region::intersectsRegion(const Region& r) const
265 {
266  if (m_dimension != r.m_dimension)
268  "Region::intersectsRegion: Regions have different number of dimensions."
269  );
270 
271  for (uint32_t i = 0; i < m_dimension; ++i)
272  {
273  if (m_pLow[i] > r.m_pHigh[i] || m_pHigh[i] < r.m_pLow[i]) return false;
274  }
275  return true;
276 }
277 
278 bool Region::containsRegion(const Region& r) const
279 {
280  if (m_dimension != r.m_dimension)
282  "Region::containsRegion: Regions have different number of dimensions."
283  );
284 
285  for (uint32_t i = 0; i < m_dimension; ++i)
286  {
287  if (m_pLow[i] > r.m_pLow[i] || m_pHigh[i] < r.m_pHigh[i]) return false;
288  }
289  return true;
290 }
291 
292 bool Region::touchesRegion(const Region& r) const
293 {
294  if (m_dimension != r.m_dimension)
296  "Region::touchesRegion: Regions have different number of dimensions."
297  );
298 
299  for (uint32_t i = 0; i < m_dimension; ++i)
300  {
301  if (
302  (m_pLow[i] >= r.m_pLow[i] - std::numeric_limits<double>::epsilon() &&
303  m_pLow[i] <= r.m_pLow[i] + std::numeric_limits<double>::epsilon()) ||
304  (m_pHigh[i] >= r.m_pHigh[i] - std::numeric_limits<double>::epsilon() &&
305  m_pHigh[i] <= r.m_pHigh[i] + std::numeric_limits<double>::epsilon()))
306  return true;
307  }
308  return false;
309 }
310 
311 
312 double Region::getMinimumDistance(const Region& r) const
313 {
314  if (m_dimension != r.m_dimension)
316  "Region::getMinimumDistance: Regions have different number of dimensions."
317  );
318 
319  double ret = 0.0;
320 
321  for (uint32_t i = 0; i < m_dimension; ++i)
322  {
323  double x = 0.0;
324 
325  if (r.m_pHigh[i] < m_pLow[i])
326  {
327  x = std::abs(r.m_pHigh[i] - m_pLow[i]);
328  }
329  else if (m_pHigh[i] < r.m_pLow[i])
330  {
331  x = std::abs(r.m_pLow[i] - m_pHigh[i]);
332  }
333 
334  ret += x * x;
335  }
336 
337  return std::sqrt(ret);
338 }
339 
341 {
342  if (m_dimension != 2)
344  "Region::intersectsLineSegment: only supported for 2 dimensions"
345  );
346 
347  if (m_dimension != in.m_dimension)
349  "Region::intersectsRegion: Region and LineSegment have different number of dimensions."
350  );
351 
352  // there may be a more efficient method, but this suffices for now
353  Point ll = Point(m_pLow, 2);
354  Point ur = Point(m_pHigh, 2);
355  // fabricate ul and lr coordinates and points
356  double c_ul[2] = {m_pLow[0], m_pHigh[1]};
357  double c_lr[2] = {m_pHigh[0], m_pLow[1]};
358  Point ul = Point(&c_ul[0], 2);
359  Point lr = Point(&c_lr[0], 2);
360 
361  // Points/LineSegment for the segment
362  Point p1 = Point(in.m_pStartPoint, 2);
363  Point p2 = Point(in.m_pEndPoint, 2);
364 
365 
366  //Check whether either or both the endpoints are within the region OR
367  //whether any of the bounding segments of the Region intersect the segment
368  return (containsPoint(p1) || containsPoint(p2) ||
369  in.intersectsShape(LineSegment(ll, ul)) || in.intersectsShape(LineSegment(ul, ur)) ||
370  in.intersectsShape(LineSegment(ur, lr)) || in.intersectsShape(LineSegment(lr, ll)));
371 
372 }
373 
374 bool Region::containsPoint(const Point& p) const
375 {
376  if (m_dimension != p.m_dimension)
378  "Region::containsPoint: Point has different number of dimensions."
379  );
380 
381  for (uint32_t i = 0; i < m_dimension; ++i)
382  {
383  if (m_pLow[i] > p.getCoordinate(i) || m_pHigh[i] < p.getCoordinate(i)) return false;
384  }
385  return true;
386 }
387 
388 bool Region::touchesPoint(const Point& p) const
389 {
390  if (m_dimension != p.m_dimension)
392  "Region::touchesPoint: Point has different number of dimensions."
393  );
394 
395  for (uint32_t i = 0; i < m_dimension; ++i)
396  {
397  if (
398  (m_pLow[i] >= p.getCoordinate(i) - std::numeric_limits<double>::epsilon() &&
399  m_pLow[i] <= p.getCoordinate(i) + std::numeric_limits<double>::epsilon()) ||
400  (m_pHigh[i] >= p.getCoordinate(i) - std::numeric_limits<double>::epsilon() &&
401  m_pHigh[i] <= p.getCoordinate(i) + std::numeric_limits<double>::epsilon()))
402  return true;
403  }
404  return false;
405 }
406 
407 double Region::getMinimumDistance(const Point& p) const
408 {
409  if (m_dimension != p.m_dimension)
411  "Region::getMinimumDistance: Point has different number of dimensions."
412  );
413 
414  double ret = 0.0;
415 
416  for (uint32_t i = 0; i < m_dimension; ++i)
417  {
418  if (p.getCoordinate(i) < m_pLow[i])
419  {
420  ret += std::pow(m_pLow[i] - p.getCoordinate(i), 2.0);
421  }
422  else if (p.getCoordinate(i) > m_pHigh[i])
423  {
424  ret += std::pow(p.getCoordinate(i) - m_pHigh[i], 2.0);
425  }
426  }
427 
428  return std::sqrt(ret);
429 }
430 
432 {
433  if (m_dimension != r.m_dimension)
435  "Region::getIntersectingRegion: Regions have different number of dimensions."
436  );
437 
438  Region ret;
440 
441  // check for intersection.
442  // marioh: avoid function call since this is called billions of times.
443  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
444  {
445  if (m_pLow[cDim] > r.m_pHigh[cDim] || m_pHigh[cDim] < r.m_pLow[cDim]) return ret;
446  }
447 
448  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
449  {
450  ret.m_pLow[cDim] = std::max(m_pLow[cDim], r.m_pLow[cDim]);
451  ret.m_pHigh[cDim] = std::min(m_pHigh[cDim], r.m_pHigh[cDim]);
452  }
453 
454  return ret;
455 }
456 
457 double Region::getIntersectingArea(const Region& r) const
458 {
459  if (m_dimension != r.m_dimension)
461  "Region::getIntersectingArea: Regions have different number of dimensions."
462  );
463 
464  double ret = 1.0;
465  double f1, f2;
466 
467  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
468  {
469  if (m_pLow[cDim] > r.m_pHigh[cDim] || m_pHigh[cDim] < r.m_pLow[cDim]) return 0.0;
470 
471  f1 = std::max(m_pLow[cDim], r.m_pLow[cDim]);
472  f2 = std::min(m_pHigh[cDim], r.m_pHigh[cDim]);
473  ret *= f2 - f1;
474  }
475 
476  return ret;
477 }
478 
479 /*
480  * Returns the margin of a region. It is calcuated as the sum of 2^(d-1) * width, in each dimension.
481  * It is actually the sum of all edges, no matter what the dimensionality is.
482 */
483 double Region::getMargin() const
484 {
485  double mul = std::pow(2.0, static_cast<double>(m_dimension) - 1.0);
486  double margin = 0.0;
487 
488  for (uint32_t i = 0; i < m_dimension; ++i)
489  {
490  margin += (m_pHigh[i] - m_pLow[i]) * mul;
491  }
492 
493  return margin;
494 }
495 
497 {
498  if (m_dimension != r.m_dimension)
500  "Region::combineRegion: Region has different number of dimensions."
501  );
502 
503  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
504  {
505  m_pLow[cDim] = std::min(m_pLow[cDim], r.m_pLow[cDim]);
506  m_pHigh[cDim] = std::max(m_pHigh[cDim], r.m_pHigh[cDim]);
507  }
508 }
509 
511 {
512  if (m_dimension != p.m_dimension)
514  "Region::combinePoint: Point has different number of dimensions."
515  );
516 
517  for (uint32_t cDim = 0; cDim < m_dimension; ++cDim)
518  {
519  m_pLow[cDim] = std::min(m_pLow[cDim], p.m_pCoords[cDim]);
520  m_pHigh[cDim] = std::max(m_pHigh[cDim], p.m_pCoords[cDim]);
521  }
522 }
523 
524 void Region::getCombinedRegion(Region& out, const Region& in) const
525 {
526  if (m_dimension != in.m_dimension)
528  "Region::getCombinedRegion: Regions have different number of dimensions."
529  );
530 
531  out = *this;
532  out.combineRegion(in);
533 }
534 
535 double Region::getLow(uint32_t index) const
536 {
537  if (index >= m_dimension)
539 
540  return m_pLow[index];
541 }
542 
543 double Region::getHigh(uint32_t index) const
544 {
545  if (index >= m_dimension)
547 
548  return m_pHigh[index];
549 }
550 
551 void Region::makeInfinite(uint32_t dimension)
552 {
553  makeDimension(dimension);
554  for (uint32_t cIndex = 0; cIndex < m_dimension; ++cIndex)
555  {
556  m_pLow[cIndex] = std::numeric_limits<double>::max();
557  m_pHigh[cIndex] = -std::numeric_limits<double>::max();
558  }
559 }
560 
561 void Region::makeDimension(uint32_t dimension)
562 {
563  if (m_dimension != dimension)
564  {
565  delete[] m_pLow;
566  delete[] m_pHigh;
567 
568  // remember that this is not a constructor. The object will be destructed normally if
569  // something goes wrong (bad_alloc), so we must take care not to leave the object at an intermediate state.
570  m_pLow = nullptr; m_pHigh = nullptr;
571 
572  m_dimension = dimension;
573  m_pLow = new double[m_dimension];
574  m_pHigh = new double[m_dimension];
575  }
576 }
577 
578 std::ostream& SpatialIndex::operator<<(std::ostream& os, const Region& r)
579 {
580  uint32_t i;
581 
582  os << "Low: ";
583  for (i = 0; i < r.m_dimension; ++i)
584  {
585  os << r.m_pLow[i] << " ";
586  }
587 
588  os << ", High: ";
589 
590  for (i = 0; i < r.m_dimension; ++i)
591  {
592  os << r.m_pHigh[i] << " ";
593  }
594 
595  return os;
596 }
Region * clone() override
Definition: Region.cc:135
virtual bool containsPoint(const Point &in) const
Definition: Region.cc:374
virtual double getLow(uint32_t index) const
Definition: Region.cc:535
virtual bool containsRegion(const Region &in) const
Definition: Region.cc:278
virtual void makeDimension(uint32_t dimension)
Definition: Region.cc:561
virtual Region & operator=(const Region &r)
Definition: Region.cc:101
virtual void makeDimension(uint32_t dimension)
Definition: Point.cc:243
virtual bool touchesRegion(const Region &in) const
Definition: Region.cc:292
~Region() override
Definition: Region.cc:95
virtual double getIntersectingArea(const Region &in) const
Definition: Region.cc:457
double * m_pLow
Definition: Region.h:98
virtual void getCombinedRegion(Region &out, const Region &in) const
Definition: Region.cc:524
uint32_t m_dimension
Definition: Point.h:77
bool touchesShape(const IShape &in) const override
Definition: Region.cc:207
bool containsShape(const IShape &in) const override
Definition: Region.cc:194
virtual bool intersectsRegion(const Region &in) const
Definition: Region.cc:264
virtual void combineRegion(const Region &in)
Definition: Region.cc:496
virtual bool touchesPoint(const Point &in) const
Definition: Region.cc:388
uint32_t m_dimension
Definition: Region.h:97
bool intersectsShape(const IShape &in) const override
Definition: LineSegment.cc:162
double * m_pHigh
Definition: Region.h:99
double getArea() const override
Definition: Region.cc:239
virtual double getHigh(uint32_t index) const
Definition: Region.cc:543
void storeToByteArray(uint8_t **data, uint32_t &length) override
Definition: Region.cc:161
SIDX_DLL std::ostream & operator<<(std::ostream &os, const Ball &ball)
Definition: Ball.cc:215
virtual void makeInfinite(uint32_t dimension)
Definition: Region.cc:551
uint32_t getDimension() const override
Definition: Region.cc:229
bool intersectsShape(const IShape &in) const override
Definition: Region.cc:178
void getMBR(Region &out) const override
Definition: Region.cc:234
virtual bool operator==(const Region &) const
Definition: Region.cc:113
uint32_t getByteArraySize() override
Definition: Region.cc:143
double getMinimumDistance(const IShape &in) const override
Definition: Region.cc:251
virtual double getMargin() const
Definition: Region.cc:483
virtual Region getIntersectingRegion(const Region &r) const
Definition: Region.cc:431
virtual double getCoordinate(uint32_t index) const
Definition: Point.cc:226
virtual void combinePoint(const Point &in)
Definition: Region.cc:510
void loadFromByteArray(const uint8_t *data) override
Definition: Region.cc:148
double * m_pCoords
Definition: Point.h:78
void getCenter(Point &out) const override
Definition: Region.cc:220
virtual bool intersectsLineSegment(const LineSegment &in) const
Definition: Region.cc:340