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