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