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