LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
SimpleGeo.h
Go to the documentation of this file.
1 
10 #ifndef LARCOREALG_GEOMETRY_SIMPLEGEO_H
11 #define LARCOREALG_GEOMETRY_SIMPLEGEO_H
12 
13 // C/C++ standard library
14 #include <algorithm> // std::min(), std::max()
15 #include <array>
16 #include <stdexcept> // std::runtime_error
17 
18 namespace lar {
19  namespace util {
20 
21  // --- BEGIN Geometry group ------------------------------------------------
24 
42  namespace simple_geo {
43 
46 
48  template <typename Data = double>
49  struct Point2D {
50  using Data_t = Data;
51  Data_t x = 0.;
52  Data_t y = 0.;
53 
54  Point2D() = default;
55  Point2D(Data_t x, Data_t y) : x(x), y(y) {}
56  Point2D(Data_t const* p) : x(p[0]), y(p[1]) {}
57 
58  }; // struct Point2D<>
59 
60  template <typename T>
61  bool operator==(Point2D<T> const& a, Point2D<T> const& b)
62  {
63  return (a.x == b.x) && (a.y == b.y);
64  }
65  template <typename T>
66  bool operator!=(Point2D<T> const& a, Point2D<T> const& b)
67  {
68  return (a.x != b.x) || (a.y != b.y);
69  }
70  template <typename T>
72  {
73  return {a.x + b.x, a.y + b.y};
74  }
75  template <typename T>
77  {
78  return {p.x * f, p.y * f};
79  }
80  template <typename T>
82  {
83  return {p.x / f, p.y / f};
84  }
85  template <typename Stream, typename T>
86  Stream& operator<<(Stream&& out, Point2D<T> const& p)
87  {
88  out << "( " << p.x << " ; " << p.y << " )";
89  return out;
90  }
91 
93  template <typename Data = double>
94  struct Point3D {
95  using Data_t = Data;
96  Data_t x = 0.;
97  Data_t y = 0.;
98  Data_t z = 0.;
99 
100  Point3D() = default;
101  Point3D(Data_t x, Data_t y, Data_t z) : x(x), y(y), z(z) {}
102  Point3D(Data_t const* p) : x(p[0]), y(p[1]), z(p[2]) {}
103  }; // struct Point3D<>
104 
105  template <typename T>
106  bool operator==(Point3D<T> const& a, Point3D<T> const& b)
107  {
108  return (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
109  }
110  template <typename T>
111  bool operator!=(Point3D<T> const& a, Point3D<T> const& b)
112  {
113  return (a.x != b.x) || (a.y != b.y) || (a.z != b.z);
114  }
115  template <typename T>
117  {
118  return {a.x + b.x, a.y + b.y, a.z + b.z};
119  }
120  template <typename T>
122  {
123  return {p.x * f, p.y * f, p.z * f};
124  }
125  template <typename T>
127  {
128  return {p.x / f, p.y / f, p.z / f};
129  }
130  template <typename Stream, typename T>
131  Stream& operator<<(Stream&& out, Point3D<T> const& p)
132  {
133  out << "( " << p.x << " ; " << p.y << " ; " << p.z << " )";
134  return out;
135  }
136 
138 
141 
143  template <typename Point>
144  class AreaBase {
145  public:
146  using Point_t = Point;
148 
150  class NullIntersection : public std::runtime_error {
151  using std::runtime_error::runtime_error;
152  };
153 
154  AreaBase() = default;
155 
156  AreaBase(Point_t const& a, Point_t const& b) { set_sorted(min.x, max.x, a.x, b.x); }
157 
158  Point_t const& Min() const { return min; }
159  Point_t const& Max() const { return max; }
160  Point_t Center() const { return (min + max) * 0.5; }
161 
162  auto DeltaX() const { return Max().x - Min().x; }
163  bool isEmptyX() const { return (DeltaX() == 0); }
164  bool isNullX() const { return Max().x < Min().x; }
165  bool isNull() const { return isNullX(); }
166  unsigned int nonEmptyDims() const { return isEmptyX() ? 0 : 1; }
167  bool isEmpty() const { return nonEmptyDims() == 0; }
168  bool isLine() const { return nonEmptyDims() == 1; }
169 
170  auto thinnestSize() const { return DeltaX(); }
171 
173  unsigned int thinnestSide() const { return 0; }
174 
175  void IncludePoint(Point_t const& point) { set_min_max(min.x, max.x, point.x); }
176 
177  void Include(Area_t const& area)
178  {
179  IncludePoint(area.min);
180  IncludePoint(area.max);
181  }
182 
183  void Intersect(Area_t const& area)
184  {
185  set_max(min.x, area.min.x);
186  set_min(max.x, area.max.x);
187  if (isNullX()) throw NullIntersection("null x dimension");
188  }
189 
190  bool operator==(Area_t const& as) const { return (min == as.min) && (max == as.max); }
191  bool operator!=(Area_t const& as) const { return (min != as.min) || (max != as.max); }
192 
193  protected:
194  using Data_t = typename Point_t::Data_t;
195 
196  Point_t min, max;
197 
198  static void set_min(Data_t& var, Data_t val)
199  {
200  if (val < var) var = val;
201  }
202 
203  static void set_max(Data_t& var, Data_t val)
204  {
205  if (val > var) var = val;
206  }
207 
208  static void set_min_max(Data_t& min_var, Data_t& max_var, Data_t val)
209  {
210  set_min(min_var, val);
211  set_max(max_var, val);
212  }
213 
214  static void set_sorted(Data_t& min_var, Data_t& max_var, Data_t a, Data_t b)
215  {
216  if (a > b) {
217  min_var = b;
218  max_var = a;
219  }
220  else {
221  min_var = a;
222  max_var = b;
223  }
224  }
225 
226  }; // class AreaBase<>
227 
229  template <typename Point = Point2D<double>>
230  class Area : public AreaBase<Point> {
232 
233  public:
234  using Point_t = typename Base_t::Point_t;
236 
237  Area() = default;
238 
239  Area(Point_t const& a, Point_t const& b) : Base_t(a, b)
240  {
241  Base_t::set_sorted(Base_t::min.y, Base_t::max.y, a.y, b.y);
242  }
243 
244  auto DeltaY() const { return Base_t::Max().y - Base_t::Min().y; }
245  bool isEmptyY() const { return DeltaY() == 0; }
246  unsigned int nonEmptyDims() const { return Base_t::nonEmptyDims() + (isEmptyY() ? 0 : 1); }
247  bool isNullY() const { return Base_t::Max().y < Base_t::Min().y; }
248  bool isNull() const { return Base_t::isNull() || isNullY(); }
249  bool isEmpty() const { return nonEmptyDims() == 0; }
250  bool isLine() const { return nonEmptyDims() == 1; }
251  bool isPlane() const { return nonEmptyDims() == 2; }
252 
253  auto thinnestSize() const { return std::min(DeltaY(), Base_t::thinnestSize()); }
254 
256  unsigned int thinnestSide() const
257  {
258  return (DeltaY() < Base_t::thinnestSize()) ? 1 : Base_t::thinnestSide();
259  }
260 
261  void IncludePoint(Point_t const& point)
262  {
263  Base_t::IncludePoint(point);
264  Base_t::set_min_max(Base_t::min.y, Base_t::max.y, point.y);
265  }
266 
267  void Include(Area_t const& area)
268  {
269  IncludePoint(area.min);
270  IncludePoint(area.max);
271  }
272 
273  void Intersect(Area_t const& area)
274  {
275  Base_t::Intersect(area);
276  Base_t::set_max(Base_t::min.y, area.min.y);
277  Base_t::set_min(Base_t::max.y, area.max.y);
278  if (isNullY()) throw typename Base_t::NullIntersection("null y dimension");
279  }
280 
281  }; // class Area<>
282 
283  template <typename Stream, typename Point>
284  Stream& operator<<(Stream&& out, AreaBase<Point> const& area)
285  {
286  out << area.Min() << " - " << area.Max();
287  return out;
288  }
289 
291  template <typename Point = Point3D<double>>
292  class Volume : public Area<Point> {
294 
295  public:
296  using Point_t = typename Base_t::Point_t;
298 
299  Volume() = default;
300 
301  Volume(Point_t const& a, Point_t const& b) : Base_t(a, b)
302  {
303  Base_t::set_sorted(Base_t::min.z, Base_t::max.z, a.z, b.z);
304  }
305 
306  auto DeltaZ() const { return Base_t::Max().z - Base_t::Min().z; }
307  bool isEmptyZ() const { return DeltaZ() == 0; }
308  unsigned int nonEmptyDims() const { return Base_t::nonEmptyDims() + (isEmptyZ() ? 0 : 1); }
309  bool isNullZ() const { return Base_t::Max().z < Base_t::Min().z; }
310  bool isNull() const { return Base_t::isNull() || isNullZ(); }
311  bool isEmpty() const { return nonEmptyDims() == 0; }
312  bool isLine() const { return nonEmptyDims() == 1; }
313  bool isPlane() const { return nonEmptyDims() == 2; }
314  bool isVolume() const { return nonEmptyDims() == 3; }
315 
316  auto thinnestSize() const { return std::min(DeltaZ(), Base_t::thinnestSize()); }
317 
319  unsigned int thinnestSide() const
320  {
321  return (DeltaZ() < Base_t::thinnestSize()) ? 2 : Base_t::thinnestSide();
322  }
323 
324  void IncludePoint(Point_t const& point)
325  {
326  Base_t::IncludePoint(point);
327  Base_t::set_min_max(Base_t::min.z, Base_t::max.z, point.z);
328  }
329 
330  void Include(Volume_t const& volume)
331  {
332  IncludePoint(volume.min);
333  IncludePoint(volume.max);
334  }
335 
336  void Intersect(Volume_t const& volume)
337  {
338  Base_t::Intersect(volume);
339  Base_t::set_max(Base_t::min.z, volume.min.z);
340  Base_t::set_min(Base_t::max.z, volume.max.z);
341  if (isNullZ()) throw typename Base_t::NullIntersection("null z dimension");
342  }
343 
344  }; // class Volume<>
345 
347 
350 
352  template <typename Data = double>
353  struct Range {
354  using Data_t = Data;
356 
357  Data_t lower = 1.0;
358  Data_t upper = 0.0;
359 
361  Range() = default;
362 
364  Range(Data_t lower, Data_t upper, bool doSort = false) : lower(lower), upper(upper)
365  {
366  if (doSort) sort();
367  }
368 
370  bool isNull() const { return lower >= upper; }
371 
373  Data_t length() const { return std::max(upper - lower, Data_t(0.0)); }
374 
376  bool contains(Data_t v) const { return (v >= lower) && (v <= upper); }
377 
379  bool overlaps(Range_t const& r) const;
380 
383  Data_t delta(Data_t v, Data_t margin = 0.0) const;
384 
386  void extendToInclude(Data_t);
387 
389  void extendToInclude(Range_t const& r);
390 
392  void intersect(Range_t const& r);
393 
394  private:
396  void sort()
397  {
398  if (lower > upper) std::swap(lower, upper);
399  }
400 
402  void makeNull() { *this = Range_t{}; }
403 
404  }; // struct Range<>
405 
407  template <typename Stream, typename Data>
408  Stream& operator<<(Stream&& out, Range<Data> const& range);
409 
422  template <typename Data = double>
423  struct Rectangle {
424  using Data_t = Data;
427 
430 
432  Rectangle() = default;
433 
435  Rectangle(Range_t const& width, Range_t const& depth) : width(width), depth(depth) {}
436 
438  bool isNull() const { return width.isNull() || depth.isNull(); }
439 
441  bool contains(Data_t w, Data_t d) const { return width.contains(w) && depth.contains(d); }
442 
444  bool overlaps(Rectangle_t const& r) const;
445 
447  void extendToInclude(Rectangle_t const& r);
448 
449  }; // Rectangle<>
450 
452  template <typename Stream, typename Data>
453  Stream& operator<<(Stream&& out, Rectangle<Data> const& rect);
454 
456 
457  } // namespace simple_geo
458 
460  // --- END Geometry group --------------------------------------------------
461 
462  } // namespace util
463 } // namespace lar
464 
465 //==============================================================================
466 //--- Template implementation
467 //---
468 //------------------------------------------------------------------------------
469 //--- geo::PlaneGeo::Range<>
470 //---
471 template <typename Data>
473 {
474 
475  if (v < (lower + margin)) return lower + margin - v; // always positive
476  if (v > (upper - margin)) return upper - margin - v; // always negative
477  return 0.0; // always zero
478 
479 } // lar::util::simple_geo::Range<Data>::delta()
480 
481 //------------------------------------------------------------------------------
482 template <typename Data>
484 {
485 
486  if (lower > upper)
487  lower = upper = v;
488  else if (lower > v)
489  lower = v;
490  else if (upper < v)
491  upper = v;
492 
493 } // lar::util::simple_geo::Range<Data>::extendToInclude()
494 
495 //------------------------------------------------------------------------------
496 template <typename Data>
498 {
499 
500  if (r.isNull()) return;
501  if (isNull()) {
502  *this = r;
503  return;
504  }
505  extendToInclude(r.lower);
506  extendToInclude(r.upper);
507 
508 } // lar::util::simple_geo::Range<Data>::extendToInclude()
509 
510 //------------------------------------------------------------------------------
511 template <typename Data>
513 {
514  // this implementation explicitly makes the range default-constructed-null
515  // if the intersection results empty
516  if (isNull()) return;
517  if (r.isNull()) {
518  makeNull();
519  return;
520  }
521  if (lower < r.lower) lower = r.lower;
522  if (upper > r.upper) upper = r.upper;
523  if (lower > upper) makeNull();
524 } // lar::util::simple_geo::Range<Data>::intersect()
525 
526 //------------------------------------------------------------------------------
527 template <typename Data>
529 {
530  if (isNull() || r.isNull()) return false;
531  return (r.lower < upper) && (lower < r.upper);
532 } // lar::util::simple_geo::Range<Data>::overlaps()
533 
534 //------------------------------------------------------------------------------
535 template <typename Stream, typename Data>
536 Stream& lar::util::simple_geo::operator<<(Stream&& out, Range<Data> const& range)
537 {
538  out << "( " << range.lower << " -- " << range.upper << " )";
539  return out;
540 } // operator<< (Range)
541 
542 //------------------------------------------------------------------------------
543 template <typename Data>
545 {
546  width.extendToInclude(r.width);
547  depth.extendToInclude(r.depth);
548 } // lar::util::simple_geo::Rectangle<Data>::extendToInclude()
549 
550 //------------------------------------------------------------------------------
551 template <typename Data>
553 {
554  if (isNull() || r.isNull()) return false;
555  return width.overlap(r.width) && depth.overlap(r.depth);
556 } // lar::util::simple_geo::Rectangle<Data>::overlaps()
557 
558 //------------------------------------------------------------------------------
559 template <typename Stream, typename Data>
560 Stream& lar::util::simple_geo::operator<<(Stream&& out, Rectangle<Data> const& rect)
561 {
562  out << "w=" << rect.width << " d=" << rect.depth;
563  return out;
564 } // operator<< (Rectangle)
565 
566 //------------------------------------------------------------------------------
567 
568 #endif // LARCOREALG_GEOMETRY_SIMPLEGEO_H
TRandom r
Definition: spectrum.C:23
bool operator==(Area_t const &as) const
Definition: SimpleGeo.h:190
unsigned int nonEmptyDims() const
Definition: SimpleGeo.h:166
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
AreaBase(Point_t const &a, Point_t const &b)
Definition: SimpleGeo.h:156
2D point (x, y) (by default, with double precision)
Definition of a range along one dimension.
Definition: SimpleGeo.h:353
void Intersect(Area_t const &area)
Definition: SimpleGeo.h:183
auto thinnestSize() const
Definition: SimpleGeo.h:253
Point_t const & Min() const
Definition: SimpleGeo.h:158
void sort()
Ensures order of boundaries. Corrupts invalid ranges.
Definition: SimpleGeo.h:396
Point2D< T > operator/(Point2D< T > const &p, typename Point2D< T >::Data_t f)
Definition: SimpleGeo.h:81
unsigned int nonEmptyDims() const
Definition: SimpleGeo.h:246
Point_t const & Max() const
Definition: SimpleGeo.h:159
Double_t z
Definition: plot.C:276
void extendToInclude(Data_t)
Extends the range to include the specified point.
Definition: SimpleGeo.h:483
Data_t Data_t
Numeric type for boundaries.
Definition: SimpleGeo.h:354
Volume delimited by two points.
Definition: SimpleGeo.h:292
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
bool operator!=(Area_t const &as) const
Definition: SimpleGeo.h:191
bool contains(Data_t w, Data_t d) const
Returns whether the specified point is in the area.
Definition: SimpleGeo.h:441
bool operator!=(Point2D< T > const &a, Point2D< T > const &b)
Definition: SimpleGeo.h:66
Point2D(Data_t const *p)
Definition: SimpleGeo.h:56
Rectangle(Range_t const &width, Range_t const &depth)
Constructor from width and depth ranges.
Definition: SimpleGeo.h:435
static void set_min_max(Data_t &min_var, Data_t &max_var, Data_t val)
Definition: SimpleGeo.h:208
bool isNull() const
Returns whether the rectangle has null area.
Definition: SimpleGeo.h:438
recob::tracking::Point_t Point_t
unsigned int thinnestSide() const
Returns the index of the thinnest side (0 is x, 1 is y)
Definition: SimpleGeo.h:256
TFile f
Definition: plotHisto.C:6
void makeNull()
Resets this range to be empty (that is, like default-constructed).
Definition: SimpleGeo.h:402
Point3D(Data_t const *p)
Definition: SimpleGeo.h:102
Point2D< T > operator*(Point2D< T > const &p, typename Point2D< T >::Data_t f)
Definition: SimpleGeo.h:76
Volume(Point_t const &a, Point_t const &b)
Definition: SimpleGeo.h:301
Exception thrown when result of intersection is null.
Definition: SimpleGeo.h:150
Point2D< T > operator+(Point2D< T > const &a, Point2D< T > const &b)
Definition: SimpleGeo.h:71
Area(Point_t const &a, Point_t const &b)
Definition: SimpleGeo.h:239
unsigned int thinnestSide() const
Returns the index of the thinnest side (0 is x)
Definition: SimpleGeo.h:173
bool overlaps(Range_t const &r) const
Returns whether the specified range overlaps this range.
Definition: SimpleGeo.h:528
bool overlaps(Rectangle_t const &r) const
Returns whether this and the specified rectangle overlap.
Definition: SimpleGeo.h:552
bool operator==(Point2D< T > const &a, Point2D< T > const &b)
Definition: SimpleGeo.h:61
3D point (x, y, z) (by default, with double precision)
Float_t d
Definition: plot.C:235
bool contains(Data_t v) const
Returns whether the specified value is within the range.
Definition: SimpleGeo.h:376
Range_t width
Range along width direction.
Definition: SimpleGeo.h:428
void IncludePoint(Point_t const &point)
Definition: SimpleGeo.h:261
void Include(Area_t const &area)
Definition: SimpleGeo.h:177
Area delimited by two points.
Definition: SimpleGeo.h:230
unsigned int thinnestSide() const
Returns the index of the thinnest side (0 is x, 1 is y)
Definition: SimpleGeo.h:319
Range_t depth
Range along depth direction.
Definition: SimpleGeo.h:429
void Intersect(Volume_t const &volume)
Definition: SimpleGeo.h:336
unsigned int nonEmptyDims() const
Definition: SimpleGeo.h:308
Data_t delta(Data_t v, Data_t margin=0.0) const
Definition: SimpleGeo.h:472
Point3D(Data_t x, Data_t y, Data_t z)
Definition: SimpleGeo.h:101
LArSoft-specific namespace.
double Data_t
Numerical type for boundaries.
Definition: SimpleGeo.h:424
Definition of a rectangle from dimension ranges.
Definition: SimpleGeo.h:423
void IncludePoint(Point_t const &point)
Definition: SimpleGeo.h:175
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:42
Data_t upper
Ending coordinate.
Definition: SimpleGeo.h:358
void IncludePoint(Point_t const &point)
Definition: SimpleGeo.h:324
void extendToInclude(Rectangle_t const &r)
Extends the range to include the specified point.
Definition: SimpleGeo.h:544
typename Point_t::Data_t Data_t
Definition: SimpleGeo.h:194
bool isNull() const
Returns whether the range is empty.
Definition: SimpleGeo.h:370
void Include(Area_t const &area)
Definition: SimpleGeo.h:267
Range(Data_t lower, Data_t upper, bool doSort=false)
Constructor from lower and upper bounds.
Definition: SimpleGeo.h:364
void Intersect(Area_t const &area)
Definition: SimpleGeo.h:273
Data_t lower
Starting coordinate.
Definition: SimpleGeo.h:357
Float_t w
Definition: plot.C:20
Area/volume delimited by points: base/1D implementation.
Definition: SimpleGeo.h:144
static void set_sorted(Data_t &min_var, Data_t &max_var, Data_t a, Data_t b)
Definition: SimpleGeo.h:214
Point2D(Data_t x, Data_t y)
Definition: SimpleGeo.h:55
static void set_min(Data_t &var, Data_t val)
Definition: SimpleGeo.h:198
Data_t length() const
Returns the distance between upper and lower bounds.
Definition: SimpleGeo.h:373
void intersect(Range_t const &r)
Shortens this range to include only points also in r.
Definition: SimpleGeo.h:512
void Include(Volume_t const &volume)
Definition: SimpleGeo.h:330
static void set_max(Data_t &var, Data_t val)
Definition: SimpleGeo.h:203