PlaneGeo.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file larcorealg/Geometry/PlaneGeo.cxx
3 ///
4 /// \author brebel@fnal.gov
5 ////////////////////////////////////////////////////////////////////////
6 
7 // class header
9 
10 // LArSoft includes
11 #include "larcorealg/Geometry/Exceptions.h" // geo::InvalidWireError
13 #include "larcorealg/Geometry/geo_vectors_utils.h" // geo::vect::convertTo()
16 
17 // Framework includes
19 #include "cetlib/pow.h"
20 #include "cetlib_except/exception.h"
21 
22 // ROOT includes
23 #include "TMath.h"
24 #include "TVector3.h"
25 #include "TGeoManager.h"
26 #include "TGeoNode.h"
27 #include "TGeoBBox.h"
28 #include "TGeoMatrix.h"
29 #include "TClass.h"
30 
31 // C/C++ standard library
32 #include <sstream> // std::ostringstream
33 #include <array>
34 #include <functional> // std::less<>, std::greater<>, std::transform()
35 #include <iterator> // std::back_inserter()
36 #include <type_traits> // std::is_same<>, std::decay_t<>
37 #include <cassert>
38 
39 
40 namespace {
41 
42  /// Returns the offset to apply to value to move it inside [ -limit, +limit ].
43  template <typename T>
44  T symmetricCapDelta(T value, T limit) {
45 
46  return (value < -limit)
47  ? -limit - value
48  : (value > +limit)
49  ? +limit - value
50  : 0.0
51  ;
52 
53  } // symmetricCapDelta()
54 
55 
56  /// Returns a value shifted to fall into [ -limit; +limit ] interval.
57  template <typename T>
58  T symmetricCap(T value, T limit) {
59 
60  return value + symmetricCapDelta(value, limit);
61 
62  } // symmetricCap()
63 
64 } // local namespace
65 
66 
67 namespace geo{
68 
69  namespace details {
70 
71  //......................................................................
72  /**
73  * @brief Class computing the active area of the plane.
74  *
75  * The active area is defined in the width/depth space which include
76  * approximatively all wires.
77  *
78  * This algorithm requires the frame reference and the wire pitch to be
79  * already defined.
80  *
81  * That area is tuned so that all its points are closer than half a wire
82  * pitch from a wire.
83  *
84  */
86 
88  (geo::PlaneGeo const& plane, double wMargin, double dMargin)
89  : plane(plane)
90  , wMargin(wMargin)
91  , dMargin(dMargin)
92  {}
93 
94  ActiveAreaCalculator(geo::PlaneGeo const& plane, double margin = 0.0)
95  : ActiveAreaCalculator(plane, margin, margin)
96  {}
97 
99  { return recomputeArea(); }
100 
101  private:
102  using Projection_t = ROOT::Math::PositionVector2D
103  <ROOT::Math::Cartesian2D<double>, geo::PlaneGeo::WidthDepthReferenceTag>;
105 
106  static_assert(
108  "Necessary maintenance: remove the now optional conversions"
109  );
110 
111  static constexpr std::size_t kFirstWireStart = 0;
112  static constexpr std::size_t kFirstWireEnd = 1;
113  static constexpr std::size_t kLastWireStart = 2;
114  static constexpr std::size_t kLastWireEnd = 3;
115 
116  PlaneGeo const& plane; ///< Plane to work on.
117  double const wMargin = 0.0; ///< Margin subtracted from each side of width.
118  double const dMargin = 0.0; ///< Margin subtracted from each side of depth.
120 
121  /// Cache: wire end projections.
123 
125  {
126  //
127  // Collect the projections of the relevant points.
128  //
129  // Sorted so that start points have width not larger than end points.
130  //
131  // PointWidthDepthProjection() erroneously returns a vector rather
132  // than a point, so a conversion is required
133  auto makeProjection
134  = [](auto v){ return Projection_t(v.X(), v.Y()); };
135 
136  wireEnds[kFirstWireStart] = makeProjection
137  (plane.PointWidthDepthProjection(plane.FirstWire().GetStart()));
138  wireEnds[kFirstWireEnd] = makeProjection
139  (plane.PointWidthDepthProjection(plane.FirstWire().GetEnd()));
140  if (wireEnds[kFirstWireStart].X() > wireEnds[kFirstWireEnd].X())
141  std::swap(wireEnds[kFirstWireStart], wireEnds[kFirstWireEnd]);
142  wireEnds[kLastWireStart] = makeProjection
143  (plane.PointWidthDepthProjection(plane.LastWire().GetStart()));
144  wireEnds[kLastWireEnd] = makeProjection
145  (plane.PointWidthDepthProjection(plane.LastWire().GetEnd()));
146  if (wireEnds[kLastWireStart].X() > wireEnds[kLastWireEnd].X())
147  std::swap(wireEnds[kLastWireStart], wireEnds[kLastWireEnd]);
148  } // initializeWireEnds()
149 
151  {
152  //
153  // Find the basic area containing all the coordinates.
154  //
155 
156  // include all the coordinates of the first and last wire
157  for (auto const& aWireEnd: wireEnds) {
158  activeArea.width.extendToInclude(aWireEnd.X());
159  activeArea.depth.extendToInclude(aWireEnd.Y());
160  }
161 
162  } // includeAllWireEnds()
163 
165  {
166  //
167  // Modify the corners so that none is father than half a pitch from all
168  // wires.
169  //
170  // directions in wire/depth plane
171  Vector_t const widthDir = { 1.0, 0.0 };
172  Vector_t const depthDir = { 0.0, 1.0 };
173  Vector_t wireCoordDir = plane.VectorWidthDepthProjection
174  (plane.GetIncreasingWireDirection());
175  double const hp = plane.WirePitch() / 2.0; // half pitch
176 
177  //
178  // The plan: identify if wires are across or corner, and then:
179  // - across:
180  // - identify which sides
181  // - set the farther end of the wire from the side to be p/2 from
182  // its corner
183  // - corner:
184  // - identify which corners
185  // - move the corners to p/2 from the wires
186  //
187 
188  //
189  // are the wires crossing side to side, as opposed to cutting corners?
190  //
191 
192  // these are the angles of the original wire coordinate direction
193  double const cosAngleWidth = geo::vect::dot(wireCoordDir, widthDir);
194  double const cosAngleDepth = geo::vect::dot(wireCoordDir, depthDir);
195  // if the wire coordinate direction is on first or third quadrant:
196  bool const bPositiveAngle
197  = none_or_both((wireCoordDir.X() >= 0), (wireCoordDir.Y() >= 0));
198 
199  // now we readjust the wire coordinate direction to always point
200  // toward positive width; this breaks the relation between
201  // wireCoordDir and which is the first/last wire
202  if (cosAngleWidth < 0) wireCoordDir = -wireCoordDir;
203 
204  // let's study the first wire (ends are sorted by width)
205  assert(wireEnds[kFirstWireEnd].X() >= wireEnds[kFirstWireStart].X());
206  bool const bAlongWidth // horizontal
207  = equal(wireEnds[kFirstWireEnd].X(), activeArea.width.upper)
208  && equal(wireEnds[kFirstWireStart].X(), activeArea.width.lower);
209  bool const bAlongDepth = !bAlongWidth && // vertical
210  equal(std::max(wireEnds[kFirstWireStart].Y(), wireEnds[kFirstWireEnd].Y()), activeArea.depth.upper)
211  && equal(std::min(wireEnds[kFirstWireStart].Y(), wireEnds[kFirstWireEnd].Y()), activeArea.depth.lower);
212  assert(!(bAlongWidth && bAlongDepth));
213 
214  if (bAlongWidth) { // horizontal
215 
216  // +---------+
217  // | ___,--| upper width bound
218  // |--' |
219 
220  // find which is the wire with higher width:
221  // the last wire is highest if the wire coordinate direction (which
222  // is defined by what is first and what is last) is parallel to the
223  // width direction
224  std::size_t const iUpperWire
225  = (cosAngleDepth > 0)? kLastWireStart: kFirstWireStart;
226  // largest distance from upper depth bound of the two ends of wire
227  double const maxUpperDistance = activeArea.depth.upper
228  - std::min
229  (wireEnds[iUpperWire].Y(), wireEnds[iUpperWire ^ 0x1].Y())
230  ;
231  // set the upper side so that the maximum distance is p/2
232  // (it may be actually less if the wire is not perfectly horizontal)
233  activeArea.depth.upper += (hp - maxUpperDistance);
234 
235  // |--.___ |
236  // | `--| deal with the lower bound now
237  // +---------+
238 
239  std::size_t const iLowerWire
240  = (cosAngleDepth > 0)? kFirstWireStart: kLastWireStart;
241  // largest distance from lower depth bound of the two ends of wire
242  double const maxLowerDistance
243  = std::max
244  (wireEnds[iLowerWire].Y(), wireEnds[iLowerWire ^ 0x1].Y())
245  - activeArea.depth.lower
246  ;
247  // set the upper side so that the minimum distance is p/2
248  activeArea.depth.lower -= (hp - maxLowerDistance);
249 
250  } // horizontal wires
251  else if (bAlongDepth) { // vertical
252  // --,---+
253  // | |
254  // \ |
255  // | | upper depth bound
256  // \ |
257  // | |
258  // ------+
259 
260  // find which is the wire with higher depth:
261  // the last wire is highest if the wire coordinate direction (which
262  // is defined by what is first and what is last) is parallel to the
263  // depth direction
264  std::size_t const iUpperWire
265  = (cosAngleWidth > 0)? kLastWireStart: kFirstWireStart;
266  // largest distance from upper depth bound of the two ends of wire
267  double const maxUpperDistance = activeArea.width.upper
268  - std::min
269  (wireEnds[iUpperWire].X(), wireEnds[iUpperWire ^ 0x1].X())
270  ;
271  // set the upper side so that the minimum distance is p/2
272  activeArea.width.upper += (hp - maxUpperDistance);
273 
274  // +-,----
275  // | |
276  // | \ .
277  // | | deal with the lower bound now
278  // | \ .
279  // | |
280  // +------
281  std::size_t const iLowerWire
282  = (cosAngleWidth > 0)? kFirstWireStart: kLastWireStart;
283  // largest distance from lower width bound of the two ends of wire
284  double const maxLowerDistance
285  = std::max
286  (wireEnds[iLowerWire].X(), wireEnds[iLowerWire ^ 0x1].X())
287  - activeArea.width.lower
288  ;
289  // set the upper side so that the minimum distance is p/2
290  activeArea.width.lower -= (hp - maxLowerDistance);
291 
292  } // vertical wires
293  else if (bPositiveAngle) { // wires are not going across: corners!
294  // corners at (lower width, lower depth), (upper width, upper depth)
295 
296  // -._------+
297  // `-._ | upper width corner (upper depth)
298  // `-|
299 
300  // start of the wire on the upper corner
301  // (width coordinate is lower for start than for end)
302  std::size_t const iUpperWire
303  = (cosAngleWidth > 0)? kLastWireStart: kFirstWireStart;
304 
305  double const upperDistance = geo::vect::dot(
306  Vector_t(activeArea.width.upper - wireEnds[iUpperWire].X(), 0.0),
307  wireCoordDir
308  );
309  // make the upper distance become p/2
310  auto const upperDelta = (hp - upperDistance) * wireCoordDir;
311  activeArea.width.upper += upperDelta.X();
312  activeArea.depth.upper += upperDelta.Y();
313 
314  // |-._
315  // | `-._ lower width corner (lower depth)
316  // +-------`-
317 
318  // end of the wire on the lower corner
319  // (width coordinate is lower than the end)
320  std::size_t const iLowerWire
321  = (cosAngleWidth > 0)? kFirstWireEnd: kLastWireEnd;
322 
323  double const lowerDistance = geo::vect::dot(
324  Vector_t(wireEnds[iLowerWire].X() - activeArea.width.lower, 0.0),
325  wireCoordDir
326  );
327  // make the lower distance become p/2 (note direction of wire coord)
328  auto const lowerDelta = (hp - lowerDistance) * wireCoordDir;
329  activeArea.width.lower -= lowerDelta.X();
330  activeArea.depth.lower -= lowerDelta.Y();
331 
332  }
333  else { // !bPositiveAngle
334  // corners at (lower width, upper depth), (upper width, lower depth)
335 
336  // _,-|
337  // _,-' | upper width corner (lower depth)
338  // -'-------+
339 
340  // start of the wire on the upper corner
341  // (width coordinate is lower than the end)
342  std::size_t const iUpperWire
343  = (cosAngleWidth > 0)? kLastWireStart: kFirstWireStart;
344 
345  double const upperDistance = geo::vect::dot(
346  Vector_t(activeArea.width.upper - wireEnds[iUpperWire].X(), 0.0),
347  wireCoordDir
348  );
349  // make the upper distance become p/2
350  auto const upperDelta = (hp - upperDistance) * wireCoordDir;
351  activeArea.width.upper += upperDelta.X();
352  activeArea.depth.lower += upperDelta.Y();
353 
354  // +------_,-
355  // | _,-' lower width corner (upper depth)
356  // |-'
357 
358  // end of the wire on the lower corner
359  // (width coordinate is lower than the end)
360  std::size_t const iLowerWire
361  = (cosAngleWidth > 0)? kFirstWireEnd: kLastWireEnd;
362 
363  double const lowerDistance = geo::vect::dot(
364  Vector_t(wireEnds[iLowerWire].X() - activeArea.width.lower, 0.0),
365  wireCoordDir
366  );
367  // make the lower distance become p/2 (note direction of wire coord)
368  auto const lowerDelta = (hp - lowerDistance) * wireCoordDir;
369  activeArea.width.lower -= lowerDelta.X();
370  activeArea.depth.upper -= lowerDelta.Y();
371 
372  } // if ...
373 
374  } // adjustCorners()
375 
376 
377  void applyMargin()
378  {
379  if (wMargin != 0.0) {
380  activeArea.width.lower += wMargin;
381  activeArea.width.upper -= wMargin;
382  }
383  if (dMargin != 0.0) {
384  activeArea.depth.lower += dMargin;
385  activeArea.depth.upper -= dMargin;
386  }
387  } // applyMargin()
388 
389 
391  {
392  activeArea = {};
393 
394  //
395  // 0. collect the projections of the relevant point
396  //
398 
399  //
400  // 1. find the basic area containing all the coordinates
401  //
403 
404  //
405  // 2. adjust area so that no corner is father than half a wire pitch
406  //
407  adjustCorners();
408 
409  //
410  // 3. apply an absolute margin
411  //
412  applyMargin();
413 
414  return activeArea;
415  } // computeArea()
416 
417  /// Returns true if a and b are both true or both false (exclusive nor).
418  static bool none_or_both(bool a, bool b) { return a == b; }
419 
420  /// Returns whether the two numbers are the same, lest a tolerance.
421  template <typename T>
422  static bool equal(T a, T b, T tol = T(1e-5))
423  { return std::abs(a - b) <= tol; }
424 
425  }; // struct ActiveAreaCalculator
426 
427  //......................................................................
428 
429  } // namespace details
430 
431 
432  //----------------------------------------------------------------------------
433  //--- geo::PlaneGeo
434  //---
436  TGeoNode const& node,
438  WireCollection_t&& wires
439  )
440  : fTrans(std::move(trans))
441  , fVolume(node.GetVolume())
442  , fView(geo::kUnknown)
443  , fOrientation(geo::kVertical)
444  , fWire(std::move(wires))
445  , fWirePitch(0.)
446  , fSinPhiZ(0.)
447  , fCosPhiZ(0.)
448  , fDecompWire()
449  , fDecompFrame()
450  , fCenter()
451  {
452 
453  if (!fVolume) {
454  throw cet::exception("PlaneGeo")
455  << "Plane geometry node " << node.IsA()->GetName()
456  << "[" << node.GetName() << ", #" << node.GetNumber()
457  << "] has no volume!\n";
458  }
459 
460  // view is now set at TPC level with SetView
461 
464 
465  } // PlaneGeo::PlaneGeo()
466 
467  //......................................................................
468 
470 
471  //
472  // The algorithm is not very refined...
473  //
474 
475  TGeoBBox const* pShape = dynamic_cast<TGeoBBox const*>(fVolume->GetShape());
476  if (!pShape) {
477  throw cet::exception("PlaneGeo")
478  << "BoundingBox(): volume " << fVolume->IsA()->GetName()
479  << "['" << fVolume->GetName() << "'] has a shape which is a "
480  << pShape->IsA()->GetName()
481  << ", not a TGeoBBox!";
482  }
483 
484  geo::BoxBoundedGeo box;
485  unsigned int points = 0;
486  for (double dx: { -(pShape->GetDX()), +(pShape->GetDX()) }) {
487  for (double dy: { -(pShape->GetDY()), +(pShape->GetDY()) }) {
488  for (double dz: { -(pShape->GetDZ()), +(pShape->GetDZ()) }) {
489 
490  auto const p = toWorldCoords(LocalPoint_t{ dx, dy, dz });
491 
492  if (points++ == 0)
493  box.SetBoundaries(p, p);
494  else
495  box.ExtendToInclude(p);
496 
497  } // for z
498  } // for y
499  } // for x
500  return box;
501 
502  } // PlaneGeo::BoundingBox()
503 
504  //......................................................................
505 
506  geo::WireGeo const& PlaneGeo::Wire(unsigned int iwire) const {
507  geo::WireGeo const* pWire = WirePtr(iwire);
508  if (!pWire) {
509  throw cet::exception("WireOutOfRange")
510  << "Request for non-existant wire " << iwire << "\n";
511  }
512  return *pWire;
513  } // PlaneGeo::Wire(int)
514 
515  //......................................................................
516 
517  // sort the WireGeo objects
519  {
520  sorter.SortWires(fWire);
521  }
522 
523 
524  //......................................................................
528  } // PlaneGeo::WireIDincreasesWithZ()
529 
530 
531  //......................................................................
533 
534  // add both coordinates of first and last wire
535  std::array<double, 3> A, B;
536 
537  FirstWire().GetStart(A.data());
538  LastWire().GetEnd(B.data());
539 
540  return { A.data(), B.data() };
541  } // PlaneGeo::Coverage()
542 
543 
544  //......................................................................
546  (std::string indent /* = "" */, unsigned int verbosity /* = 1 */) const
547  {
548  std::ostringstream sstr;
549  PrintPlaneInfo(sstr, indent, verbosity);
550  return sstr.str();
551  } // PlaneGeo::PlaneInfo()
552 
553 
554  //......................................................................
556  (WidthDepthProjection_t const& proj, double wMargin, double dMargin) const
557  {
558 
559  return {
560  symmetricCapDelta(proj.X(), fFrameSize.HalfWidth() - wMargin),
561  symmetricCapDelta(proj.Y(), fFrameSize.HalfDepth() - dMargin)
562  };
563 
564  } // PlaneGeo::DeltaFromPlane()
565 
566 
567  //......................................................................
569  (WidthDepthProjection_t const& proj, double wMargin, double dMargin) const
570  {
571 
572  return {
573  fActiveArea.width.delta(proj.X(), wMargin),
574  fActiveArea.depth.delta(proj.Y(), dMargin)
575  };
576 
577  } // PlaneGeo::DeltaFromActivePlane()
578 
579 
580  //......................................................................
581  bool PlaneGeo::isProjectionOnPlane(geo::Point_t const& point) const {
582 
583  auto const deltaProj
585 
586  return (deltaProj.X() == 0.) && (deltaProj.Y() == 0.);
587 
588  } // PlaneGeo::isProjectionOnPlane()
589 
590 
591  //......................................................................
593  (WidthDepthProjection_t const& proj) const
594  {
595  //
596  // We have a more complicate implementation to avoid rounding errors.
597  // In this way, the result is really guaranteed to be exactly on the border.
598  //
599  auto const delta = DeltaFromPlane(proj);
600  return {
601  (delta.X() == 0.0)
602  ? proj.X()
603  : ((delta.X() > 0)
604  ? -fFrameSize.HalfWidth() // delta positive -> proj on negative side
606  ),
607  (delta.Y() == 0.0)
608  ? proj.Y()
609  : ((delta.Y() > 0)
610  ? -fFrameSize.HalfDepth() // delta positive -> proj on negative side
612  )
613  };
614 
615  } // PlaneGeo::MoveProjectionToPlane()
616 
617 
618  //......................................................................
619  TVector3 PlaneGeo::MovePointOverPlane(TVector3 const& point) const {
620 
621  //
622  // This implementation is subject to rounding errors, since the result of
623  // the addition might jitter above or below the border.
624  //
625 
626  auto const deltaProj
628 
629  return point + deltaProj.X() * WidthDir() + deltaProj.Y() * DepthDir();
630 
631  } // PlaneGeo::MovePointOverPlane()
632 
634 
635  //
636  // This implementation is subject to rounding errors, since the result of
637  // the addition might jitter above or below the border.
638  //
639 
640  auto const deltaProj
642 
643  return point + deltaProj.X() * WidthDir<geo::Vector_t>() + deltaProj.Y() * DepthDir<geo::Vector_t>();
644 
645  } // PlaneGeo::MovePointOverPlane()
646 
647 
648  //......................................................................
650 
651  //
652  // 1) compute the wire coordinate of the point
653  // 2) get the closest wire number
654  // 3) check if the wire does exist
655  // 4) build and return the wire ID
656  //
657 
658  // this line merges parts (1) and (2); add 0.5 to have the correct rounding:
659  int nearestWireNo = int(0.5 + WireCoordinate(pos));
660 
661  // if we are outside of the wireplane range, throw an exception
662  if ((nearestWireNo < 0) || ((unsigned int) nearestWireNo >= Nwires())) {
663 
664  auto wireNo = nearestWireNo; // save for the output
665 
666  if (nearestWireNo < 0 ) wireNo = 0;
667  else wireNo = Nwires() - 1;
668 
669  throw InvalidWireError("Geometry", ID(), nearestWireNo, wireNo)
670  << "Can't find nearest wire for position " << pos
671  << " in plane " << std::string(ID()) << " approx wire number # "
672  << wireNo << " (capped from " << nearestWireNo << ")\n";
673  } // if invalid
674 
675  return { ID(), (geo::WireID::WireID_t) nearestWireNo };
676 
677  } // PlaneGeo::NearestWireID()
678 
679 
680  //......................................................................
681  geo::WireGeo const& PlaneGeo::NearestWire(geo::Point_t const& point) const {
682 
683  //
684  // Note that this code is ready for when NearestWireID() will be changed
685  // to return an invalid ID instead of throwing.
686  // As things are now, `NearestWireID()` will never return an invalid ID,
687  // but it will throw an exception similar to this one.
688  //
689 
690  geo::WireID const wireID = NearestWireID(point);
691  if (wireID) return Wire(wireID); // we have that wire, so we return it
692 
693  // wire ID is invalid, meaning it's out of range. Throw an exception!
694  geo::WireID const closestID = ClosestWireID(wireID);
695  throw InvalidWireError("Geometry", ID(), closestID.Wire, wireID.Wire)
696  << "Can't find nearest wire for position " << point
697  << " in plane " << std::string(ID()) << " approx wire number # "
698  << closestID.Wire << " (capped from " << wireID.Wire << ")\n";
699 
700  } // PlaneGeo::NearestWire()
701 
702 
703  //......................................................................
705  (WireCoordProjection_t const& projDir) const
706  {
707  assert(lar::util::Vector2DComparison{1e-6}.nonZero(projDir));
708  return std::sqrt(cet::square(projDir.X() / projDir.Y()) + 1.0) * fWirePitch;
709  } // PlaneGeo::InterWireProjectedDistance()
710 
711 
712  //......................................................................
714  // the secondary component of the wire decomposition basis is wire coord.
715  double const r = dir.R();
716  assert(r >= 1.e-6);
717 
718  double const absWireCoordProj
720  return r / absWireCoordProj * fWirePitch;
721 
722  } // PlaneGeo::InterWireDistance()
723 
724 
725  //......................................................................
726  double PlaneGeo::ThetaZ() const { return FirstWire().ThetaZ(); }
727 
728 
729  //......................................................................
731  (geo::PlaneID planeid, geo::BoxBoundedGeo const& TPCbox)
732  {
733  // the order here matters
734 
735  // reset our ID
736  fID = planeid;
737 
738  UpdatePlaneNormal(TPCbox);
741 
742  // update wires
743  geo::WireID::WireID_t wireNo = 0;
744  for (auto& wire: fWire) {
745 
746  wire.UpdateAfterSorting(geo::WireID(fID, wireNo), shouldFlipWire(wire));
747 
748  ++wireNo;
749  } // for wires
750 
752  UpdateWireDir();
755  UpdateWirePitch();
757  UpdatePhiZ();
758  UpdateView();
759 
760  } // PlaneGeo::UpdateAfterSorting()
761 
762  //......................................................................
764  switch (view) {
765  case geo::kU: return "U";
766  case geo::kV: return "V";
767  case geo::kZ: return "Z";
768  case geo::kY: return "Y";
769  case geo::kX: return "X";
770  case geo::k3D: return "3D";
771  case geo::kUnknown: return "?";
772  default:
773  return "<UNSUPPORTED (" + std::to_string((int) view) + ")>";
774  } // switch
775  } // PlaneGeo::ViewName()
776 
777  //......................................................................
779  switch (orientation) {
780  case geo::kHorizontal: return "horizontal"; break;
781  case geo::kVertical: return "vertical"; break;
782  default: return "unexpected"; break;
783  } // switch
784  } // PlaneGeo::OrientationName()
785 
786 
787  //......................................................................
789 
790  //
791  // We need to identify which are the "long" directions of the plane.
792  // We assume it is a box, and the shortest side is excluded.
793  // The first direction ("width") is given by preference to z.
794  // If z is the direction of the normal to the plane... oh well.
795  // Let's say privilege to the one which comes from local z, then y.
796  // That means: undefined.
797  //
798  // Requirements:
799  // - ROOT geometry information (shapes and transformations)
800  // - the shape must be a box (an error is PRINTED if not)
801  // - center of the wire plane (not just the center of the plane box)
802  //
803 
804  //
805  // how do they look like in the world?
806  //
807  TGeoBBox const* pShape = dynamic_cast<TGeoBBox const*>(fVolume->GetShape());
808  if (!pShape) {
809  mf::LogError("BoxInfo")
810  << "Volume " << fVolume->IsA()->GetName() << "['" << fVolume->GetName()
811  << "'] has a shape which is a " << pShape->IsA()->GetName()
812  << ", not a TGeoBBox! Dimensions won't be available.";
813  // set it invalid
815  fDecompFrame.SetMainDir({ 0., 0., 0. });
816  fDecompFrame.SetSecondaryDir({ 0., 0., 0. });
817  fFrameSize = { 0.0, 0.0 };
818  return;
819  }
820 
821  std::array<geo::Vector_t, 3U> sides;
822  size_t iSmallest = 3;
823  {
824 
825  size_t iSide = 0;
826  TVector3 dir;
827 
828  sides[iSide] = toWorldCoords(LocalVector_t{ pShape->GetDX(), 0.0, 0.0 });
829  iSmallest = iSide;
830  ++iSide;
831 
832  sides[iSide] = toWorldCoords(LocalVector_t{ 0.0, pShape->GetDY(), 0.0 });
833  if (sides[iSide].Mag2() < sides[iSmallest].Mag2()) iSmallest = iSide;
834  ++iSide;
835 
836  sides[iSide] = toWorldCoords(LocalVector_t{ 0.0, 0.0, pShape->GetDZ() });
837  if (sides[iSide].Mag2() < sides[iSmallest].Mag2()) iSmallest = iSide;
838  ++iSide;
839 
840  }
841 
842  //
843  // which are the largest ones?
844  //
845  size_t kept[2];
846  {
847  size_t iKept = 0;
848  for (size_t i = 0; i < 3; ++i) if (i != iSmallest) kept[iKept++] = i;
849  }
850 
851  //
852  // which is which?
853  //
854  // Pick width as the most z-like.
855  //
856  size_t const iiWidth =
857  std::abs(sides[kept[0]].Unit().Z()) > std::abs(sides[kept[1]].Unit().Z())
858  ? 0: 1;
859  size_t const iWidth = kept[iiWidth];
860  size_t const iDepth = kept[1 - iiWidth]; // the other
861 
862  fDecompFrame.SetMainDir(geo::vect::rounded01(sides[iWidth].Unit(), 1e-4));
864  (geo::vect::rounded01(sides[iDepth].Unit(), 1e-4));
865  fFrameSize.halfWidth = sides[iWidth].R();
866  fFrameSize.halfDepth = sides[iDepth].R();
867 
868  } // PlaneGeo::DetectGeometryDirections()
869 
870  //......................................................................
872  const unsigned int NWires = Nwires();
873  if (NWires < 2) return {}; // why are we even here?
874 
875  // 1) get the direction of the middle wire
876  auto const WireDir = Wire(NWires / 2).Direction<geo::Vector_t>();
877 
878  // 2) get the direction between the middle wire and the next one
879  auto const ToNextWire = Wire(NWires / 2 + 1).GetCenter<geo::Point_t>()
880  - Wire(NWires / 2).GetCenter<geo::Point_t>();
881 
882  // 3) get the direction perpendicular to the plane
883  // 4) round it
884  // 5) return its norm
885  return geo::vect::rounded01(WireDir.Cross(ToNextWire).Unit(), 1e-4);
886 
887  } // PlaneGeo::GetNormalAxis()
888 
889 
890  //......................................................................
892 
893  //
894  // this algorithm needs to know about the axis;
895  // the normal is expected to be already updated.
896  //
897 
898  // sanity check
899  if (fWire.size() < 2) {
900  // this likely means construction is not complete yet
901  throw cet::exception("NoWireInPlane")
902  << "PlaneGeo::UpdateOrientation(): only " << fWire.size()
903  << " wires!\n";
904  } // if
905 
906  auto normal = GetNormalDirection<geo::Vector_t>();
907 
908  if (std::abs(std::abs(normal.X()) - 1.) < 1e-3)
910  else if (std::abs(std::abs(normal.Y()) - 1.) < 1e-3)
912  else {
913  // at this point, the only problem is the lack of a label for this
914  // orientation; probably introducing a geo::kOtherOrientation would
915  // suffice
916  throw cet::exception("Geometry")
917  << "Plane with unsupported orientation (normal: " << normal << ")\n";
918  }
919 
920  } // PlaneGeo::UpdateOrientation()
921 
922  //......................................................................
924  // pick long wires around the center of the detector,
925  // so that their coordinates are defined with better precision
926  assert(Nwires() > 1);
927 
928  auto const iWire = Nwires() / 2;
929 
930  fWirePitch = geo::WireGeo::WirePitch(Wire(iWire - 1), Wire(iWire));
931 
932  } // PlaneGeo::UpdateWirePitch()
933 
934  //......................................................................
936  TVector3 const& wire_coord_dir = GetIncreasingWireDirection();
937  /*
938  TVector3 const& normal = GetNormalDirection();
939  TVector3 z(0., 0., 1.);
940 
941  // being defined in absolute terms as angle respect to z axis,
942  // we take the z component as cosine, and all the rest as sine
943  fCosPhiZ = wire_coord_dir.Dot(z);
944  fSinPhiZ = wire_coord_dir.Cross(z).Dot(normal);
945  */
946  fCosPhiZ = wire_coord_dir.Z();
947  fSinPhiZ = wire_coord_dir.Y();
948  } // PlaneGeo::UpdatePhiZ()
949 
951  {
952  /*
953  * This algorithm assigns views according to the angle the wire axis cuts
954  * with y axis ("thetaY"), but from the point of view of the center of the
955  * TPC.
956  * A special case is when the drift axis is on y axis.
957  *
958  * In the normal case, the discrimination happens on the the arctangent of
959  * the point { (y,w), (y x n,w) }, where w is the wire direction, y is the
960  * coordinate axis and n the normal to the wire plane. This definition gives
961  * the same value regardless of the direction of w on its axis.
962  *
963  * If thetaY is 0, wires are parallel to the y axis:
964  * the view is assigned as kX or kZ depending on whether the plane normal is
965  * closer to the z axis or the x axis, respectively (the normal describes
966  * a direction _not_ measured by the wires).
967  *
968  * If thetaY is a right angle, the wires are orthogonal to y axis and view
969  * kY view is assigned.
970  * If thetaY is smaller than 0, the view is called "U".
971  * If thetaY is larger than 0, the view is called "V".
972  *
973  * The special case where the drift axis is on y axis is treated separately.
974  * In that case, the role of y axis is replaced by the z axis and the
975  * discriminating figure is equivalent to the usual ThetaZ().
976  *
977  * If thetaZ is 0, the wires are measuring x and kX view is chosen.
978  * If thetaZ is a right angle, the wires are measuring z and kZ view is
979  * chosen.
980  * If thetaZ is smaller than 0, the view is called "U".
981  * If thetaZ is larger than 0, the view is called "V".
982  *
983  */
984 
985  auto const& normalDir = GetNormalDirection<geo::Vector_t>();
986  auto const& wireDir = GetWireDirection<geo::Vector_t>();
987 
988  // normal direction has been rounded, so exact comparison can work
989  if (std::abs(normalDir.Y()) != 1.0) {
990  //
991  // normal case: drift direction is not along y (vertical)
992  //
993 
994  // yw is pretty much GetWireDirection().Y()...
995  // thetaY is related to atan2(ynw, yw)
996  double const yw = geo::vect::dot(wireDir, geo::Yaxis());
997  double const ynw = geo::vect::mixedProduct
998  (geo::Yaxis(), normalDir, wireDir);
999 
1000  if (std::abs(yw) < 1.0e-4) { // wires orthogonal to y axis
1001  double const closeToX
1002  = std::abs(geo::vect::dot(normalDir, geo::Xaxis()));
1003  double const closeToZ
1004  = std::abs(geo::vect::dot(normalDir, geo::Zaxis()));
1005  SetView((closeToZ > closeToX)? geo::kX: geo::kY);
1006  }
1007  else if (std::abs(ynw) < 1.0e-4) { // wires parallel to y axis
1008  SetView(geo::kZ);
1009  }
1010  else if ((ynw * yw) < 0) SetView(geo::kU); // different sign => thetaY > 0
1011  else if ((ynw * yw) > 0) SetView(geo::kV); // same sign => thetaY < 0
1012  else assert(false); // logic error?!
1013 
1014  }
1015  else { // if drift is vertical
1016  //
1017  // special case: drift direction is along y (vertical)
1018  //
1019 
1020  // zw is pretty much GetWireDirection().Z()...
1021  double const zw = geo::vect::dot(wireDir, geo::Zaxis());
1022  // while GetNormalDirection() axis is on y, its direction is not fixed:
1023  double const znw = geo::vect::mixedProduct
1024  (geo::Zaxis(), normalDir, wireDir);
1025 
1026  // thetaZ is std::atan(znw/zw)
1027 
1028  if (std::abs(zw) < 1.0e-4) { // orthogonal to z, orthogonal to y...
1029  // this is equivalent to thetaZ = +/- pi/2
1030  SetView(geo::kZ);
1031  }
1032  else if (std::abs(znw) < 1.0e-4) { // parallel to z, orthogonal to y...
1033  // this is equivalent to thetaZ = 0
1034  SetView(geo::kX);
1035  }
1036  else if ((znw * zw) < 0) SetView(geo::kU); // different sign => thetaZ > 0
1037  else if ((znw * zw) > 0) SetView(geo::kV); // same sign => thetaZ < 0
1038  else assert(false); // logic error?!
1039 
1040  } // if drift direction... else
1041 
1042  } // UpdateView()
1043 
1044 
1045  //......................................................................
1047 
1048  //
1049  // direction normal to the wire plane, points toward the center of TPC
1050  //
1051 
1052  // start from the axis
1053  fNormal = GetNormalAxis();
1054 
1055  // now evaluate where we are pointing
1056  auto const towardCenter
1057  = geo::vect::convertTo<TVector3>(TPCbox.Center()) - GetBoxCenter();
1058 
1059  // if they are pointing in opposite directions, flip the normal
1060  if (fNormal.Dot(towardCenter) < 0) fNormal = -fNormal;
1062 
1063  } // PlaneGeo::UpdatePlaneNormal()
1064 
1065 
1066  //......................................................................
1068 
1069  //
1070  // fix the positiveness of the width/depth/normal frame
1071  //
1072 
1073  // The basis is already set and orthonormal, with only the width
1074  // and depth directions arbitrary.
1075  // We choose the direction of the secondary axis ("depth")
1076  // so that the frame normal is oriented in the general direction of the
1077  // plane normal (the latter is computed independently).
1078  if (WidthDir().Cross(DepthDir()).Dot(GetNormalDirection()) < 0.0) {
1081  }
1082 
1083  } // PlaneGeo::UpdateWidthDepthDir()
1084 
1085 
1086  //......................................................................
1088 
1089  //
1090  // Direction measured by the wires, pointing toward increasing wire number;
1091  // requires:
1092  // - the normal to the plane to be correct
1093  // - wires to be sorted
1094  //
1095 
1096  // 1) get the direction of the middle wire
1097  auto refWireNo = Nwires() / 2;
1098  if (refWireNo == Nwires() - 1) --refWireNo;
1099  auto const& refWire = Wire(refWireNo);
1100  auto const& WireDir = geo::vect::toVector(refWire.Direction()); // we only rely on the axis
1101 
1102 
1103  // 2) get the axis perpendicular to it on the wire plane
1104  // (arbitrary direction)
1105  auto wireCoordDir = GetNormalDirection<geo::Vector_t>().Cross(WireDir).Unit();
1106 
1107  // 3) where is the next wire?
1108  auto toNextWire
1109  = geo::vect::toVector(Wire(refWireNo + 1).GetCenter() - refWire.GetCenter());
1110 
1111  // 4) if wireCoordDir is pointing away from the next wire, flip it
1112  if (wireCoordDir.Dot(toNextWire) < 0) {
1113  wireCoordDir = -wireCoordDir;
1114  }
1116 
1117  } // PlaneGeo::UpdateIncreasingWireDir()
1118 
1119 
1120  //......................................................................
1122 
1124 
1125  //
1126  // check that the resulting normal matches the plane one
1127  //
1129  .equal(fDecompWire.NormalDir(), GetNormalDirection<geo::Vector_t>()));
1130 
1131  } // PlaneGeo::UpdateWireDir()
1132 
1133 
1134  //......................................................................
1136 
1137  //
1138  // Compare one wire (the first one, for convenience) with all other wires;
1139  // the wire pitch is the smallest distance we find.
1140  //
1141  // This algorithm assumes wire pitch is constant, but it does not assume
1142  // wire ordering (which UpdateWirePitch() does).
1143  //
1144  auto firstWire = fWire.cbegin(), wire = firstWire, wend = fWire.cend();
1145  fWirePitch = geo::WireGeo::WirePitch(*firstWire, *(++wire));
1146 
1147  while (++wire != wend) {
1148  auto wirePitch = geo::WireGeo::WirePitch(*firstWire, *wire);
1149  if (wirePitch < 1e-4) continue; // it's 0!
1150  if (wirePitch < fWirePitch) fWirePitch = wirePitch;
1151  } // while
1152 
1153  } // PlaneGeo::UpdateWirePitchSlow()
1154 
1155 
1156  //......................................................................
1158 
1159  //
1160  // update the origin of the reference frame (the middle of the first wire)
1161  //
1163 
1164  } // PlaneGeo::UpdateDecompWireOrigin()
1165 
1166  //......................................................................
1168 
1169  //
1170  // The active area is defined in the width/depth space which include
1171  // approximatively all wires.
1172  //
1173  // See `ActiveAreaCalculator` for details of the algorithm.
1174  //
1175 
1176  // we scratch 1 um from each side to avoid rounding errors later
1177  fActiveArea = details::ActiveAreaCalculator(*this, 0.0001);
1178 
1179  } // PlaneGeo::UpdateActiveArea()
1180 
1181 
1182  //......................................................................
1184 
1185  //
1186  // The center of the wire plane is defined as the center of the plane box,
1187  // translated to the plane the wires lie on.
1188  // This assumes that the thickness direction of the box is aligned with
1189  // the drift direction, so that the translated point is still in the middle
1190  // of width and depth dimensions.
1191  // It is possible to remove that assumption by translating the center of the
1192  // box along the thickness direction enough to bring it to the wire plane.
1193  // The math is just a bit less straightforward, so we don't bother yet.
1194  //
1195  // Requirements:
1196  // * the wire decomposition frame must be set up (at least its origin and
1197  // normal direction)
1198  //
1199 
1200  fCenter = GetBoxCenter<geo::Point_t>();
1201 
1203 
1204  geo::vect::round0(fCenter, 1e-7); // round dimensions less than 1 nm to 0
1205 
1206  fDecompFrame.SetOrigin(fCenter); // equivalent to GetCenter() now
1207 
1208  } // PlaneGeo::UpdateWirePlaneCenter()
1209 
1210 
1211  //......................................................................
1212  bool PlaneGeo::shouldFlipWire(geo::WireGeo const& wire) const {
1213  //
1214  // The correct orientation is so that:
1215  //
1216  // (direction) x (wire coordinate direction) . (plane normal)
1217  //
1218  // is positive; it it's negative, then we should flip the wire.
1219  //
1220  // Note that the increasing wire direction comes from the wire frame, while
1221  // the normal direction is computed independently by geometry.
1222  // The resulting normal in the wire frame is expected to be the same as the
1223  // plane normal from GetNormalDirection(); if this is not the case, flipping
1224  // the wire direction should restore it.
1225  //
1226 
1227  return wire.Direction()
1228  .Cross(GetIncreasingWireDirection())
1229  .Dot(GetNormalDirection())
1230  < +0.5; // should be in fact exactly +1
1231 
1232  } // PlaneGeo::shouldFlipWire()
1233 
1234  //......................................................................
1235 
1236 
1237 } // namespace geo
1238 ////////////////////////////////////////////////////////////////////////
static std::string OrientationName(geo::Orient_t orientation)
Returns the name of the specified orientation.
Definition: PlaneGeo.cxx:778
geo::WirePtr WirePtr(unsigned int iwire) const
Returns the wire number iwire from this plane.
Definition: PlaneGeo.h:324
void round01(Vector &v, Scalar tol)
Returns a vector with all components rounded if close to 0, -1 or +1.
void GetStart(double *xyz) const
Definition: WireGeo.h:157
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:65
double HalfWidth() const
Definition: PlaneGeo.h:1472
Utilities to extend the interface of geometry vectors.
auto VectorSecondaryComponent(Vector_t const &v) const
Returns the secondary component of a vector.
Definition: Decomposer.h:531
void SetView(geo::View_t view)
Set the signal view (for TPCGeo).
Definition: PlaneGeo.h:1398
WidthDepthProjection_t VectorWidthDepthProjection(geo::Vector_t const &v) const
Returns the projection of the specified vector on the plane.
Definition: PlaneGeo.h:1127
geo::Point_t fCenter
Center of the plane, lying on the wire plane.
Definition: PlaneGeo.h:1500
constexpr auto dot(Vector const &a, Vector const &b)
Return cross product of two vectors.
static std::string ViewName(geo::View_t view)
Returns the name of the specified view.
Definition: PlaneGeo.cxx:763
std::string PlaneInfo(std::string indent="", unsigned int verbosity=1) const
Returns a string with plane information.
Definition: PlaneGeo.cxx:546
void UpdateIncreasingWireDir()
Updates the cached direction to increasing wires.
Definition: PlaneGeo.cxx:1087
double fWirePitch
Pitch of wires in this plane.
Definition: PlaneGeo.h:1483
void SetSecondaryDir(Vector_t const &dir)
Change the secondary direction of the projection base.
Definition: Decomposer.h:447
std::vector< geo::WireGeo > WireCollection_t
Definition: PlaneGeo.h:89
void UpdateWirePitch()
Updates the stored wire pitch.
Definition: PlaneGeo.cxx:923
void UpdateWidthDepthDir()
Updates the cached depth and width direction.
Definition: PlaneGeo.cxx:1067
double const dMargin
Margin subtracted from each side of depth.
Definition: PlaneGeo.cxx:118
static bool none_or_both(bool a, bool b)
Returns true if a and b are both true or both false (exclusive nor).
Definition: PlaneGeo.cxx:418
lar::util::simple_geo::Rectangle< double > Rect
Type for description of rectangles.
Definition: PlaneGeo.h:169
Vector_t const & NormalDir() const
Returns the plane normal axis direction.
Definition: Decomposer.h:469
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:506
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
Planes which measure V.
Definition: geo_types.h:130
auto mixedProduct(Vector const &a, Vector const &b, Vector const &c)
Unknown view.
Definition: geo_types.h:136
auto const tol
Definition: SurfXYZTest.cc:16
enum geo::_plane_orient Orient_t
Provides simple real number checks.
void UpdateOrientation()
Updates plane orientation.
Definition: PlaneGeo.cxx:891
geo::PlaneID fID
ID of this plane.
Definition: PlaneGeo.h:1502
Planes which measure X direction.
Definition: geo_types.h:134
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
Volume delimited by two points.
Definition: SimpleGeo.h:261
constexpr Vector Yaxis()
Returns a y axis vector of the specified type.
Definition: geo_vectors.h:219
geo::PlaneGeo::WidthDepthDisplacement_t Vector_t
Definition: PlaneGeo.cxx:104
::geo::Point_t toPoint(Point const &p)
Convert the specified point into a geo::Point_t.
Point GetBoxCenter() const
Returns the centre of the box representing the plane.
Definition: PlaneGeo.h:498
bool isProjectionOnPlane(geo::Point_t const &point) const
Returns if the projection of specified point is within the plane.
Definition: PlaneGeo.cxx:581
::geo::Vector_t toVector(Vector const &v)
Convert the specified vector into a geo::Vector_t.
static constexpr std::size_t kLastWireStart
Definition: PlaneGeo.cxx:113
WidthDepthProjection_t PointWidthDepthProjection(geo::Point_t const &point) const
Returns the projection of the specified point on the plane.
Definition: PlaneGeo.h:1107
STL namespace.
static constexpr std::size_t kFirstWireStart
Definition: PlaneGeo.cxx:111
Planes which measure Z direction.
Definition: geo_types.h:132
geo::WireGeo const & NearestWire(geo::Point_t const &pos) const
Returns the wire closest to the specified position.
Definition: PlaneGeo.cxx:681
Data_t delta(Data_t v, Data_t margin=0.0) const
Definition: SimpleGeo.h:443
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:164
string dir
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
bool shouldFlipWire(geo::WireGeo const &wire) const
Whether the specified wire should have start and end swapped.
Definition: PlaneGeo.cxx:1212
Vector GetNormalDirection() const
Returns the direction normal to the plane.
Definition: PlaneGeo.h:442
void round0(Vector &v, Scalar tol)
Returns a vector with all components rounded if close to 0.
static double WirePitch(geo::WireGeo const &w1, geo::WireGeo const &w2)
Returns the pitch (distance on y/z plane) between two wires, in cm.
Definition: WireGeo.h:476
constexpr T square(T x)
Definition: pow.h:21
PlaneGeo const & plane
Plane to work on.
Definition: PlaneGeo.cxx:116
WidthDepthProjection_t MoveProjectionToPlane(WidthDepthProjection_t const &proj) const
Returns the projection, moved onto the plane if necessary.
Definition: PlaneGeo.cxx:593
Vector GetIncreasingWireDirection() const
Returns the direction of increasing wires.
Definition: PlaneGeo.h:457
double ThetaZ() const
Returns angle of wire with respect to z axis in the Y-Z plane in radians.
Definition: WireGeo.h:250
geo::BoxBoundedGeo BoundingBox() const
Definition: PlaneGeo.cxx:469
Class for approximate comparisons.
Planes which measure Y direction.
Definition: geo_types.h:133
void DetectGeometryDirections()
Sets the geometry directions.
Definition: PlaneGeo.cxx:788
Projection_t wireEnds[4]
Cache: wire end projections.
Definition: PlaneGeo.cxx:122
double InterWireProjectedDistance(WireCoordProjection_t const &projDir) const
Returns the distance between wires along the specified direction.
Definition: PlaneGeo.cxx:705
void DriftPoint(geo::Point_t &position, double distance) const
Shifts the position of an electron drifted by a distance.
Definition: PlaneGeo.h:643
geo::Vector_t fNormal
Definition: PlaneGeo.h:1487
Rect fActiveArea
Area covered by wires in frame base.
Definition: PlaneGeo.h:1498
geo::PlaneGeo::Rect recomputeArea()
Definition: PlaneGeo.cxx:390
3-dimensional objects, potentially hits, clusters, prongs, etc.
Definition: geo_types.h:135
double ThetaZ() const
Angle of the wires from positive z axis; .
Definition: PlaneGeo.cxx:726
void UpdatePlaneNormal(geo::BoxBoundedGeo const &TPCbox)
Updates the cached normal to plane versor; needs the TPC box coordinates.
Definition: PlaneGeo.cxx:1046
TGeoVolume const * fVolume
Plane volume description.
Definition: PlaneGeo.h:1479
T abs(T value)
Planes which measure U.
Definition: geo_types.h:129
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WidthDepthReferenceTag > WidthDepthProjection_t
Definition: PlaneGeo.h:151
Planes that are in the horizontal plane.
Definition: geo_types.h:140
const double e
void extendToInclude(Data_t)
Extends the range to include the specified point.
Definition: SimpleGeo.h:456
lar::util::simple_geo::Volume Coverage() const
Returns a volume including all the wires in the plane.
Definition: PlaneGeo.cxx:532
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
geo::WireID NearestWireID(geo::Point_t const &pos) const
Returns the ID of wire closest to the specified position.
Definition: PlaneGeo.cxx:649
WidthDepthDecomposer_t fDecompFrame
Definition: PlaneGeo.h:1495
void UpdatePhiZ()
Updates the stored .
Definition: PlaneGeo.cxx:935
void swap(Handle< T > &a, Handle< T > &b)
Planes that are in the vertical plane (e.g. ArgoNeuT).
Definition: geo_types.h:141
Collection of exceptions for Geometry system.
geo::Point_t toWorldCoords(LocalPoint_t const &local) const
Transform point from local plane frame to world frame.
Definition: PlaneGeo.h:1351
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WireCoordinateReferenceTag > WireCoordProjection_t
Type for projections in the wire base representation.
Definition: PlaneGeo.h:130
WireCollection_t fWire
List of wires in this plane.
Definition: PlaneGeo.h:1482
const double a
def move(depos, offset)
Definition: depos.py:107
geo::Point_t MovePointOverPlane(geo::Point_t const &point) const
Returns the point, moved so that its projection is over the plane.
Definition: PlaneGeo.cxx:633
Point GetCenter() const
Returns the centre of the wire plane in world coordinates [cm].
Definition: PlaneGeo.h:479
double fSinPhiZ
Sine of .
Definition: PlaneGeo.h:1484
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:82
double InterWireDistance(geo::Vector_t const &dir) const
Returns the distance between wires along the specified direction.
Definition: PlaneGeo.cxx:713
p
Definition: test.py:223
constexpr Vector Xaxis()
Returns a x axis vector of the specified type.
Definition: geo_vectors.h:215
Class comparing 2D vectors.
Range_t width
Range along width direction.
Definition: SimpleGeo.h:393
void UpdateWirePitchSlow()
Updates the stored wire pitch with a slower, more robust algorithm.
Definition: PlaneGeo.cxx:1135
const WireGeo & FirstWire() const
Return the first wire in the plane.
Definition: PlaneGeo.h:344
RectSpecs fFrameSize
Definition: PlaneGeo.h:1496
static int max(int a, int b)
void UpdateAfterSorting(geo::PlaneID planeid, geo::BoxBoundedGeo const &TPCbox)
Performs all needed updates after the TPC has sorted the planes.
Definition: PlaneGeo.cxx:731
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WidthDepthReferenceTag > WidthDepthDisplacement_t
Type for vector projections in the plane frame base representation.
Definition: PlaneGeo.h:155
static constexpr std::size_t kLastWireEnd
Definition: PlaneGeo.cxx:114
void UpdateView()
Updates the stored view.
Definition: PlaneGeo.cxx:950
Vector Direction() const
Definition: WireGeo.h:587
Vector rounded01(Vector const &v, Scalar tol)
Returns a vector with all components rounded if close to 0, -1 or +1.
double HalfDepth() const
Definition: PlaneGeo.h:1473
Encapsulate the geometry of a wire.
Vector DepthDir() const
Return the direction of plane depth.
Definition: PlaneGeo.h:236
constexpr Vector Zaxis()
Returns a z axis vector of the specified type.
Definition: geo_vectors.h:223
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:184
Range_t depth
Range along depth direction.
Definition: SimpleGeo.h:394
Tag for plane frame base vectors.
Definition: PlaneGeo.h:146
ActiveAreaCalculator(geo::PlaneGeo const &plane, double margin=0.0)
Definition: PlaneGeo.cxx:94
void SetOrigin(Point_t const &point)
Change the 3D point of the reference frame origin.
Definition: Decomposer.h:441
Vector_t const & SecondaryDir() const
Returns the plane secondary axis direction.
Definition: Decomposer.h:466
WidthDepthProjection_t DeltaFromPlane(WidthDepthProjection_t const &proj, double wMargin, double dMargin) const
Returns a projection vector that, added to the argument, gives a projection inside (or at the border ...
Definition: PlaneGeo.cxx:556
WidthDepthProjection_t DeltaFromActivePlane(WidthDepthProjection_t const &proj, double wMargin, double dMargin) const
Returns a projection vector that, added to the argument, gives a projection inside (or at the border ...
Definition: PlaneGeo.cxx:569
A base class aware of world box coordinatesAn object describing a simple shape can inherit from this ...
Definition: BoxBoundedGeo.h:33
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
geo::Vector_t GetNormalAxis() const
Returns a direction normal to the plane (pointing is not defined).
Definition: PlaneGeo.cxx:871
Encapsulate the construction of a single detector plane.
void PrintPlaneInfo(Stream &&out, std::string indent="", unsigned int verbosity=1) const
Prints information about this plane.
Definition: PlaneGeo.h:1539
double DistanceFromPlane(geo::Point_t const &point) const
Returns the distance of the specified point from the wire plane.
Definition: PlaneGeo.h:621
void SetBoundaries(Coord_t x_min, Coord_t x_max, Coord_t y_min, Coord_t y_max, Coord_t z_min, Coord_t z_max)
Sets the boundaries in world coordinates as specified.
void GetEnd(double *xyz) const
Definition: WireGeo.h:163
constexpr bool nonNegative(Value_t value) const
Returns whether value is larger than or equal() to zero.
geo::PlaneID const & ID() const
Returns the identifier of this plane.
Definition: PlaneGeo.h:203
double const wMargin
Margin subtracted from each side of width.
Definition: PlaneGeo.cxx:117
ActiveAreaCalculator(geo::PlaneGeo const &plane, double wMargin, double dMargin)
Definition: PlaneGeo.cxx:88
unsigned int Nwires() const
Number of wires in this plane.
Definition: PlaneGeo.h:269
geo::WireID ClosestWireID(geo::WireID::WireID_t wireNo) const
Returns the closest valid wire ID to the specified wire.
Definition: PlaneGeo.h:1520
bool WireIDincreasesWithZ() const
Returns whether the higher z wires have higher wire ID.
Definition: PlaneGeo.cxx:525
void ExtendToInclude(Coord_t x, Coord_t y, Coord_t z)
Extends the current box to also include the specified point.
double fCosPhiZ
Cosine of .
Definition: PlaneGeo.h:1485
Data_t upper
Ending coordinate.
Definition: SimpleGeo.h:327
Vector WidthDir() const
Return the direction of plane width.
Definition: PlaneGeo.h:221
#define A
Definition: memgrp.cpp:38
Exception thrown on invalid wire number.
Definition: Exceptions.h:42
static bool * b
Definition: config.cpp:1043
static constexpr std::size_t kFirstWireEnd
Definition: PlaneGeo.cxx:112
unsigned int WireID_t
Type for the ID number.
Definition: geo_types.h:561
void UpdateWirePlaneCenter()
Updates the stored wire plane center.
Definition: PlaneGeo.cxx:1183
Direction
Definition: AssnsIter.h:13
WireDecomposer_t fDecompWire
Definition: PlaneGeo.h:1491
static bool equal(T a, T b, T tol=T(1e-5))
Returns whether the two numbers are the same, lest a tolerance.
Definition: PlaneGeo.cxx:422
virtual void SortWires(std::vector< geo::WireGeo > &wgeo) const =0
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:73
double WireCoordinate(Point const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:882
void UpdateDecompWireOrigin()
Updates the position of the wire coordinate decomposition.
Definition: PlaneGeo.cxx:1157
Class computing the active area of the plane.
Definition: PlaneGeo.cxx:85
void UpdateActiveArea()
Updates the internally used active area.
Definition: PlaneGeo.cxx:1167
Collection of Physical constants used in LArSoft.
geo::Vector3DBase_t< PlaneGeoCoordinatesTag > LocalVector_t
Type of displacement vectors in the local GDML wire plane frame.
Definition: PlaneGeo.h:118
Data_t lower
Starting coordinate.
Definition: SimpleGeo.h:326
const WireGeo & LastWire() const
Return the last wire in the plane.
Definition: PlaneGeo.h:350
LArSoft geometry interface.
Definition: ChannelGeo.h:16
void SortWires(geo::GeoObjectSorter const &sorter)
Apply sorting to WireGeo objects.
Definition: PlaneGeo.cxx:518
Orient_t fOrientation
Is the plane vertical or horizontal?
Definition: PlaneGeo.h:1481
ROOT::Math::PositionVector2D< ROOT::Math::Cartesian2D< double >, geo::PlaneGeo::WidthDepthReferenceTag > Projection_t
Definition: PlaneGeo.cxx:103
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
void UpdateWireDir()
Updates the cached direction to wire.
Definition: PlaneGeo.cxx:1121
geo::Point3DBase_t< PlaneGeoCoordinatesTag > LocalPoint_t
Type of points in the local GDML wire plane frame.
Definition: PlaneGeo.h:115
ROOT::Math::Transform3D TransformationMatrix
Type of transformation matrix used in geometry.
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
Definition: PlaneGeo.h:411
geo::PlaneGeo::Rect activeArea
Result.
Definition: PlaneGeo.cxx:119
PlaneGeo(TGeoNode const &node, geo::TransformationMatrix &&trans, WireCollection_t &&wires)
Construct a representation of a single plane of the detector.
Definition: PlaneGeo.cxx:435
void SetMainDir(Vector_t const &dir)
Change the main direction of the projection base.
Definition: Decomposer.h:444
geo::Point_t Center() const
Returns the center point of the box.