LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
PlaneGeo.cxx
Go to the documentation of this file.
1 
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()
15 #include "larcorealg/CoreUtils/SortByPointers.h" // util::makePointerVector()
17 
18 // Framework includes
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 <array>
33 #include <functional> // std::less<>, std::greater<>, std::transform()
34 #include <iterator> // std::back_inserter()
35 #include <type_traits> // std::is_same<>, std::decay_t<>
36 #include <cassert>
37 
38 
39 namespace {
40 
42  template <typename T>
43  T symmetricCapDelta(T value, T limit) {
44 
45  return (value < -limit)
46  ? -limit - value
47  : (value > +limit)
48  ? +limit - value
49  : 0.0
50  ;
51 
52  } // symmetricCapDelta()
53 
54 
56  template <typename T>
57  T symmetricCap(T value, T limit) {
58 
59  return value + symmetricCapDelta(value, limit);
60 
61  } // symmetricCap()
62 
63 } // local namespace
64 
65 
66 
67 namespace geo{
68 
69  namespace details {
70 
71  //......................................................................
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;
117  double const wMargin = 0.0;
118  double const dMargin = 0.0;
120 
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 
418  static bool none_or_both(bool a, bool b) { return a == b; }
419 
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  //---
435  PlaneGeo::PlaneGeo(GeoNodePath_t& path, size_t depth)
436  : fTrans(path, depth)
437  , fVolume(path[depth]->GetVolume())
438  , fView(geo::kUnknown)
439  , fOrientation(geo::kVertical)
440  , fWirePitch(0.)
441  , fSinPhiZ(0.)
442  , fCosPhiZ(0.)
443  , fDecompWire()
444  , fDecompFrame()
445  , fCenter()
446  {
447  assert(depth < path.size());
448 
449  if (!fVolume) {
450  TGeoNode const* pNode = path[depth];
451  throw cet::exception("PlaneGeo")
452  << "Plane geometry node " << pNode->IsA()->GetName()
453  << "[" << pNode->GetName() << ", #" << pNode->GetNumber()
454  << "] has no volume!\n";
455  }
456 
457  // find the wires for the plane so that you can use them later
458  FindWire(path, depth);
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  void PlaneGeo::FindWire(GeoNodePath_t& path, size_t depth)
518  {
519  // Check if the current node is a wire
520  const char* wireLabel = "volTPCWire";
521  auto const labelLength = strlen(wireLabel);
522  if(strncmp(path[depth]->GetName(), wireLabel, labelLength) == 0){
523  MakeWire(path, depth);
524  return;
525  }
526 
527  // Explore the next layer down
528  unsigned int deeper = depth+1;
529  if (deeper>=path.size()) {
530  throw cet::exception("ExceededMaxDepth") << "Exceeded maximum depth\n";
531  }
532  const TGeoVolume* v = path[depth]->GetVolume();
533  int nd = v->GetNdaughters();
534  for (int i=0; i<nd; ++i) {
535  path[deeper] = v->GetNode(i);
536  FindWire(path, deeper);
537  }
538  }
539 
540  //......................................................................
541 
542  void PlaneGeo::MakeWire(GeoNodePath_t& path, size_t depth)
543  {
544  fWire.emplace_back(path, depth);
545  }
546 
547  //......................................................................
548 
549  // sort the WireGeo objects
551  {
552  // the sorter interface requires a vector of pointers;
553  // sorting is faster, but some gymnastics is required:
555  (fWire, [&sorter](auto& coll){ sorter.SortWires(coll); });
556  }
557 
558 
559  //......................................................................
561  return GetIncreasingWireDirection().Z() > 0.;
562  } // PlaneGeo::WireIDincreasesWithZ()
563 
564 
565  //......................................................................
567 
568  // add both coordinates of first and last wire
569  std::array<double, 3> A, B;
570 
571  FirstWire().GetStart(A.data());
572  LastWire().GetEnd(B.data());
573 
574  return { A.data(), B.data() };
575  } // PlaneGeo::Coverage()
576 
577 
578  //......................................................................
580  (WidthDepthProjection_t const& proj, double wMargin, double dMargin) const
581  {
582 
583  return {
584  symmetricCapDelta(proj.X(), fFrameSize.HalfWidth() - wMargin),
585  symmetricCapDelta(proj.Y(), fFrameSize.HalfDepth() - dMargin)
586  };
587 
588  } // PlaneGeo::DeltaFromPlane()
589 
590 
591  //......................................................................
593  (WidthDepthProjection_t const& proj, double wMargin, double dMargin) const
594  {
595 
596  return {
597  fActiveArea.width.delta(proj.X(), wMargin),
598  fActiveArea.depth.delta(proj.Y(), dMargin)
599  };
600 
601  } // PlaneGeo::DeltaFromActivePlane()
602 
603 
604  //......................................................................
605  bool PlaneGeo::isProjectionOnPlane(geo::Point_t const& point) const {
606 
607  auto const deltaProj
609 
610  return (deltaProj.X() == 0.) && (deltaProj.Y() == 0.);
611 
612  } // PlaneGeo::isProjectionOnPlane()
613 
614 
615  //......................................................................
617  (WidthDepthProjection_t const& proj) const
618  {
619  //
620  // We have a more complicate implementation to avoid rounding errors.
621  // In this way, the result is really guaranteed to be exactly on the border.
622  //
623  auto const delta = DeltaFromPlane(proj);
624  return {
625  (delta.X() == 0.0)
626  ? proj.X()
627  : ((delta.X() > 0)
628  ? -fFrameSize.HalfWidth() // delta positive -> proj on negative side
630  ),
631  (delta.Y() == 0.0)
632  ? proj.Y()
633  : ((delta.Y() > 0)
634  ? -fFrameSize.HalfDepth() // delta positive -> proj on negative side
636  )
637  };
638 
639  } // PlaneGeo::MoveProjectionToPlane()
640 
641 
642  //......................................................................
643  TVector3 PlaneGeo::MovePointOverPlane(TVector3 const& point) const {
644 
645  //
646  // This implementation is subject to rounding errors, since the result of
647  // the addition might jitter above or below the border.
648  //
649 
650  auto const deltaProj
652 
653  return point + deltaProj.X() * WidthDir() + deltaProj.Y() * DepthDir();
654 
655  } // PlaneGeo::MovePointOverPlane()
656 
658 
659  //
660  // This implementation is subject to rounding errors, since the result of
661  // the addition might jitter above or below the border.
662  //
663 
664  auto const deltaProj
666 
667  return point + deltaProj.X() * WidthDir<geo::Vector_t>() + deltaProj.Y() * DepthDir<geo::Vector_t>();
668 
669  } // PlaneGeo::MovePointOverPlane()
670 
671 
672  //......................................................................
674 
675  //
676  // 1) compute the wire coordinate of the point
677  // 2) get the closest wire number
678  // 3) check if the wire does exist
679  // 4) build and return the wire ID
680  //
681 
682  // this line merges parts (1) and (2); add 0.5 to have the correct rounding:
683  int nearestWireNo = int(0.5 + WireCoordinate(pos));
684 
685  // if we are outside of the wireplane range, throw an exception
686  if ((nearestWireNo < 0) || ((unsigned int) nearestWireNo >= Nwires())) {
687 
688  auto wireNo = nearestWireNo; // save for the output
689 
690  if (nearestWireNo < 0 ) wireNo = 0;
691  else wireNo = Nwires() - 1;
692 
693  throw InvalidWireError("Geometry", ID(), nearestWireNo, wireNo)
694  << "Can't find nearest wire for position " << pos
695  << " in plane " << std::string(ID()) << " approx wire number # "
696  << wireNo << " (capped from " << nearestWireNo << ")\n";
697  } // if invalid
698 
699  return { ID(), (geo::WireID::WireID_t) nearestWireNo };
700 
701  } // PlaneGeo::NearestWireID()
702 
703 
704  //......................................................................
705  geo::WireGeo const& PlaneGeo::NearestWire(geo::Point_t const& point) const {
706 
707  //
708  // Note that this code is ready for when NearestWireID() will be changed
709  // to return an invalid ID instead of throwing.
710  // As things are now, `NearestWireID()` will never return an invalid ID,
711  // but it will throw an exception similar to this one.
712  //
713 
714  geo::WireID const wireID = NearestWireID(point);
715  if (wireID) return Wire(wireID); // we have that wire, so we return it
716 
717  // wire ID is invalid, meaning it's out of range. Throw an exception!
718  geo::WireID const closestID = ClosestWireID(wireID);
719  throw InvalidWireError("Geometry", ID(), closestID.Wire, wireID.Wire)
720  << "Can't find nearest wire for position " << point
721  << " in plane " << std::string(ID()) << " approx wire number # "
722  << closestID.Wire << " (capped from " << wireID.Wire << ")\n";
723 
724  } // PlaneGeo::NearestWire()
725 
726 
727  //......................................................................
728  double PlaneGeo::ThetaZ() const { return FirstWire().ThetaZ(); }
729 
730 
731  //......................................................................
733  (geo::PlaneID planeid, geo::BoxBoundedGeo const& TPCbox)
734  {
735  // the order here matters
736 
737  // reset our ID
738  fID = planeid;
739 
740  UpdatePlaneNormal(TPCbox);
743 
744  // update wires
745  geo::WireID::WireID_t wireNo = 0;
746  for (auto& wire: fWire) {
747 
748  wire.UpdateAfterSorting(geo::WireID(fID, wireNo), shouldFlipWire(wire));
749 
750  ++wireNo;
751  } // for wires
752 
754  UpdateWireDir();
757  UpdateWirePitch();
759  UpdatePhiZ();
760  UpdateView();
761 
762  } // PlaneGeo::UpdateAfterSorting()
763 
764  //......................................................................
765  std::string PlaneGeo::ViewName(geo::View_t view) {
766  switch (view) {
767  case geo::kU: return "U";
768  case geo::kV: return "V";
769  case geo::kZ: return "Z";
770  case geo::kY: return "Y";
771  case geo::kX: return "X";
772  case geo::k3D: return "3D";
773  case geo::kUnknown: return "?";
774  default:
775  return "<UNSUPPORTED (" + std::to_string((int) view) + ")>";
776  } // switch
777  } // PlaneGeo::ViewName()
778 
779  //......................................................................
780  std::string PlaneGeo::OrientationName(geo::Orient_t orientation) {
781  switch (orientation) {
782  case geo::kHorizontal: return "horizontal"; break;
783  case geo::kVertical: return "vertical"; break;
784  default: return "unexpected"; break;
785  } // switch
786  } // PlaneGeo::OrientationName()
787 
788 
789  //......................................................................
791 
792  //
793  // We need to identify which are the "long" directions of the plane.
794  // We assume it is a box, and the shortest side is excluded.
795  // The first direction ("width") is given by preference to z.
796  // If z is the direction of the normal to the plane... oh well.
797  // Let's say privilege to the one which comes from local z, then y.
798  // That means: undefined.
799  //
800  // Requirements:
801  // - ROOT geometry information (shapes and transformations)
802  // - the shape must be a box (an error is PRINTED if not)
803  // - center of the wire plane (not just the center of the plane box)
804  //
805 
806  //
807  // how do they look like in the world?
808  //
809  TGeoBBox const* pShape = dynamic_cast<TGeoBBox const*>(fVolume->GetShape());
810  if (!pShape) {
811  mf::LogError("BoxInfo")
812  << "Volume " << fVolume->IsA()->GetName() << "['" << fVolume->GetName()
813  << "'] has a shape which is a " << pShape->IsA()->GetName()
814  << ", not a TGeoBBox! Dimensions won't be available.";
815  // set it invalid
817  fDecompFrame.SetMainDir({ 0., 0., 0. });
818  fDecompFrame.SetSecondaryDir({ 0., 0., 0. });
819  fFrameSize = { 0.0, 0.0 };
820  return;
821  }
822 
823  std::array<geo::Vector_t, 3U> sides;
824  size_t iSmallest = 3;
825  {
826 
827  size_t iSide = 0;
828  TVector3 dir;
829 
830  sides[iSide] = toWorldCoords(LocalVector_t{ pShape->GetDX(), 0.0, 0.0 });
831  iSmallest = iSide;
832  ++iSide;
833 
834  sides[iSide] = toWorldCoords(LocalVector_t{ 0.0, pShape->GetDY(), 0.0 });
835  if (sides[iSide].Mag2() < sides[iSmallest].Mag2()) iSmallest = iSide;
836  ++iSide;
837 
838  sides[iSide] = toWorldCoords(LocalVector_t{ 0.0, 0.0, pShape->GetDZ() });
839  if (sides[iSide].Mag2() < sides[iSmallest].Mag2()) iSmallest = iSide;
840  ++iSide;
841 
842  }
843 
844  //
845  // which are the largest ones?
846  //
847  size_t kept[2];
848  {
849  size_t iKept = 0;
850  for (size_t i = 0; i < 3; ++i) if (i != iSmallest) kept[iKept++] = i;
851  }
852 
853  //
854  // which is which?
855  //
856  // Pick width as the most z-like.
857  //
858  size_t const iiWidth =
859  std::abs(sides[kept[0]].Unit().Z()) > std::abs(sides[kept[1]].Unit().Z())
860  ? 0: 1;
861  size_t const iWidth = kept[iiWidth];
862  size_t const iDepth = kept[1 - iiWidth]; // the other
863 
864  fDecompFrame.SetMainDir(geo::vect::rounded01(sides[iWidth].Unit(), 1e-4));
866  (geo::vect::rounded01(sides[iDepth].Unit(), 1e-4));
867  fFrameSize.halfWidth = sides[iWidth].R();
868  fFrameSize.halfDepth = sides[iDepth].R();
869 
870  } // PlaneGeo::DetectGeometryDirections()
871 
872  //......................................................................
874  const unsigned int NWires = Nwires();
875  if (NWires < 2) return {}; // why are we even here?
876 
877  // 1) get the direction of the middle wire
878  auto const WireDir = Wire(NWires / 2).Direction<geo::Vector_t>();
879 
880  // 2) get the direction between the middle wire and the next one
881  auto const ToNextWire = Wire(NWires / 2 + 1).GetCenter<geo::Point_t>()
882  - Wire(NWires / 2).GetCenter<geo::Point_t>();
883 
884  // 3) get the direction perpendicular to the plane
885  // 4) round it
886  // 5) return its norm
887  return geo::vect::rounded01(WireDir.Cross(ToNextWire).Unit(), 1e-4);
888 
889  } // PlaneGeo::GetNormalAxis()
890 
891 
892  //......................................................................
894 
895  //
896  // this algorithm needs to know about the axis;
897  // the normal is expected to be already updated.
898  //
899 
900  // sanity check
901  if (fWire.size() < 2) {
902  // this likely means construction is not complete yet
903  throw cet::exception("NoWireInPlane")
904  << "PlaneGeo::UpdateOrientation(): only " << fWire.size()
905  << " wires!\n";
906  } // if
907 
908  auto normal = GetNormalDirection<geo::Vector_t>();
909 
910  if (std::abs(std::abs(normal.X()) - 1.) < 1e-3)
912  else if (std::abs(std::abs(normal.Y()) - 1.) < 1e-3)
914  else {
915  // at this point, the only problem is the lack of a label for this
916  // orientation; probably introducing a geo::kOtherOrientation would
917  // suffice
918  throw cet::exception("Geometry")
919  << "Plane with unsupported orientation (normal: " << normal << ")\n";
920  }
921 
922  } // PlaneGeo::UpdateOrientation()
923 
924  //......................................................................
927  } // PlaneGeo::UpdateWirePitch()
928 
929  //......................................................................
931  TVector3 const& wire_coord_dir = GetIncreasingWireDirection();
932  /*
933  TVector3 const& normal = GetNormalDirection();
934  TVector3 z(0., 0., 1.);
935 
936  // being defined in absolute terms as angle respect to z axis,
937  // we take the z component as cosine, and all the rest as sine
938  fCosPhiZ = wire_coord_dir.Dot(z);
939  fSinPhiZ = wire_coord_dir.Cross(z).Dot(normal);
940  */
941  fCosPhiZ = wire_coord_dir.Z();
942  fSinPhiZ = wire_coord_dir.Y();
943  } // PlaneGeo::UpdatePhiZ()
944 
946  {
947  /*
948  * This algorithm assigns views according to the angle the wire axis cuts
949  * with y axis ("thetaY"), but from the point of view of the center of the
950  * TPC.
951  * A special case is when the drift axis is on y axis.
952  *
953  * In the normal case, the discrimination happens on the the arctangent of
954  * the point { (y,w), (y x n,w) }, where w is the wire direction, y is the
955  * coordinate axis and n the normal to the wire plane. This definition gives
956  * the same value regardless of the direction of w on its axis.
957  *
958  * If thetaY is 0, wires are parallel to the y axis:
959  * the view is assigned as kX or kZ depending on whether the plane normal is
960  * closer to the z axis or the x axis, respectively (the normal describes
961  * a direction _not_ measured by the wires).
962  *
963  * If thetaY is a right angle, the wires are orthogonal to y axis and view
964  * kY view is assigned.
965  * If thetaY is smaller than 0, the view is called "U".
966  * If thetaY is larger than 0, the view is called "V".
967  *
968  * The special case where the drift axis is on y axis is treated separately.
969  * In that case, the role of y axis is replaced by the z axis and the
970  * discriminating figure is equivalent to the usual ThetaZ().
971  *
972  * If thetaZ is 0, the wires are measuring x and kX view is chosen.
973  * If thetaZ is a right angle, the wires are measuring z and kZ view is
974  * chosen.
975  * If thetaZ is smaller than 0, the view is called "U".
976  * If thetaZ is larger than 0, the view is called "V".
977  *
978  */
979 
980  auto const& normalDir = GetNormalDirection<geo::Vector_t>();
981  auto const& wireDir = GetWireDirection<geo::Vector_t>();
982 
983  // normal direction has been rounded, so exact comparison can work
984  if (std::abs(normalDir.Y()) != 1.0) {
985  //
986  // normal case: drift direction is not along y (vertical)
987  //
988 
989  // yw is pretty much GetWireDirection().Y()...
990  // thetaY is related to atan2(ynw, yw)
991  double const yw = geo::vect::dot(wireDir, geo::Yaxis());
992  double const ynw = geo::vect::mixedProduct
993  (geo::Yaxis(), normalDir, wireDir);
994 
995  if (std::abs(yw) < 1.0e-4) { // wires orthogonal to y axis
996  double const closeToX
997  = std::abs(geo::vect::dot(normalDir, geo::Xaxis()));
998  double const closeToZ
999  = std::abs(geo::vect::dot(normalDir, geo::Zaxis()));
1000  SetView((closeToZ > closeToX)? geo::kX: geo::kY);
1001  }
1002  else if (std::abs(ynw) < 1.0e-4) { // wires parallel to y axis
1003  SetView(geo::kZ);
1004  }
1005  else if ((ynw * yw) < 0) SetView(geo::kU); // different sign => thetaY > 0
1006  else if ((ynw * yw) > 0) SetView(geo::kV); // same sign => thetaY < 0
1007  else assert(false); // logic error?!
1008 
1009  }
1010  else { // if drift is vertical
1011  //
1012  // special case: drift direction is along y (vertical)
1013  //
1014 
1015  // zw is pretty much GetWireDirection().Z()...
1016  double const zw = geo::vect::dot(wireDir, geo::Zaxis());
1017  // while GetNormalDirection() axis is on y, its direction is not fixed:
1018  double const znw = geo::vect::mixedProduct
1019  (geo::Zaxis(), normalDir, wireDir);
1020 
1021  // thetaZ is std::atan(znw/zw)
1022 
1023  if (std::abs(zw) < 1.0e-4) { // orthogonal to z, orthogonal to y...
1024  // this is equivalent to thetaZ = +/- pi/2
1025  SetView(geo::kZ);
1026  }
1027  else if (std::abs(znw) < 1.0e-4) { // parallel to z, orthogonal to y...
1028  // this is equivalent to thetaZ = 0
1029  SetView(geo::kX);
1030  }
1031  else if ((znw * zw) < 0) SetView(geo::kU); // different sign => thetaZ > 0
1032  else if ((znw * zw) > 0) SetView(geo::kV); // same sign => thetaZ < 0
1033  else assert(false); // logic error?!
1034 
1035  } // if drift direction... else
1036 
1037  } // UpdateView()
1038 
1039 
1040  //......................................................................
1042 
1043  //
1044  // direction normal to the wire plane, points toward the center of TPC
1045  //
1046 
1047  // start from the axis
1048  fNormal = GetNormalAxis();
1049 
1050  // now evaluate where we are pointing
1051  auto const towardCenter
1052  = geo::vect::convertTo<TVector3>(TPCbox.Center()) - GetBoxCenter();
1053 
1054  // if they are pointing in opposite directions, flip the normal
1055  if (fNormal.Dot(towardCenter) < 0) fNormal = -fNormal;
1057 
1058  } // PlaneGeo::UpdatePlaneNormal()
1059 
1060 
1061  //......................................................................
1063 
1064  //
1065  // fix the positiveness of the width/depth/normal frame
1066  //
1067 
1068  // The basis is already set and orthonormal, with only the width
1069  // and depth directions arbitrary.
1070  // We choose the direction of the secondary axis ("depth")
1071  // so that the frame normal is oriented in the general direction of the
1072  // plane normal (the latter is computed independently).
1073  if (WidthDir().Cross(DepthDir()).Dot(GetNormalDirection()) < 0.0) {
1076  }
1077 
1078  } // PlaneGeo::UpdateWidthDepthDir()
1079 
1080 
1081  //......................................................................
1083 
1084  //
1085  // Direction measured by the wires, pointing toward increasing wire number;
1086  // requires:
1087  // - the normal to the plane to be correct
1088  // - wires to be sorted
1089  //
1090 
1091  // 1) get the direction of the middle wire
1092  auto refWireNo = Nwires() / 2;
1093  if (refWireNo == Nwires() - 1) --refWireNo;
1094  auto const& refWire = Wire(refWireNo);
1095  auto const& WireDir = geo::vect::toVector(refWire.Direction()); // we only rely on the axis
1096 
1097 
1098  // 2) get the axis perpendicular to it on the wire plane
1099  // (arbitrary direction)
1100  auto wireCoordDir = GetNormalDirection<geo::Vector_t>().Cross(WireDir).Unit();
1101 
1102  // 3) where is the next wire?
1103  auto toNextWire
1104  = geo::vect::toVector(Wire(refWireNo + 1).GetCenter() - refWire.GetCenter());
1105 
1106  // 4) if wireCoordDir is pointing away from the next wire, flip it
1107  if (wireCoordDir.Dot(toNextWire) < 0) {
1108  wireCoordDir = -wireCoordDir;
1109  }
1111 
1112  } // PlaneGeo::UpdateIncreasingWireDir()
1113 
1114 
1115  //......................................................................
1117 
1119 
1120  //
1121  // check that the resulting normal matches the plane one
1122  //
1124  .equal(fDecompWire.NormalDir(), GetNormalDirection<geo::Vector_t>()));
1125 
1126  } // PlaneGeo::UpdateWireDir()
1127 
1128 
1129  //......................................................................
1131 
1132  //
1133  // Compare one wire (the first one, for convenience) with all other wires;
1134  // the wire pitch is the smallest distance we find.
1135  //
1136  // This algorithm assumes wire pitch is constant, but it does not assume
1137  // wire ordering (which UpdateWirePitch() does).
1138  //
1139  auto firstWire = fWire.cbegin(), wire = firstWire, wend = fWire.cend();
1140  fWirePitch = geo::WireGeo::WirePitch(*firstWire, *(++wire));
1141 
1142  while (++wire != wend) {
1143  auto wirePitch = geo::WireGeo::WirePitch(*firstWire, *wire);
1144  if (wirePitch < 1e-4) continue; // it's 0!
1145  if (wirePitch < fWirePitch) fWirePitch = wirePitch;
1146  } // while
1147 
1148  } // PlaneGeo::UpdateWirePitchSlow()
1149 
1150 
1151  //......................................................................
1153 
1154  //
1155  // update the origin of the reference frame (the middle of the first wire)
1156  //
1158 
1159  } // PlaneGeo::UpdateDecompWireOrigin()
1160 
1161  //......................................................................
1163 
1164  //
1165  // The active area is defined in the width/depth space which include
1166  // approximatively all wires.
1167  //
1168  // See `ActiveAreaCalculator` for details of the algorithm.
1169  //
1170 
1171  // we scratch 1 um from each side to avoid rounding errors later
1172  fActiveArea = details::ActiveAreaCalculator(*this, 0.0001);
1173 
1174  } // PlaneGeo::UpdateActiveArea()
1175 
1176 
1177  //......................................................................
1179 
1180  //
1181  // The center of the wire plane is defined as the center of the plane box,
1182  // translated to the plane the wires lie on.
1183  // This assumes that the thickness direction of the box is aligned with
1184  // the drift direction, so that the translated point is still in the middle
1185  // of width and depth dimensions.
1186  // It is possible to remove that assumption by translating the center of the
1187  // box along the thickness direction enough to bring it to the wire plane.
1188  // The math is just a bit less straightforward, so we don't bother yet.
1189  //
1190  // Requirements:
1191  // * the wire decomposition frame must be set up (at least its origin and
1192  // normal direction)
1193  //
1194 
1195  fCenter = GetBoxCenter<geo::Point_t>();
1196 
1198 
1199  fDecompFrame.SetOrigin(fCenter); // equivalent to GetCenter() now
1200 
1201  } // PlaneGeo::UpdateWirePlaneCenter()
1202 
1203 
1204  //......................................................................
1205  bool PlaneGeo::shouldFlipWire(geo::WireGeo const& wire) const {
1206  //
1207  // The correct orientation is so that:
1208  //
1209  // (direction) x (wire coordinate direction) . (plane normal)
1210  //
1211  // is positive; it it's negative, then we should flip the wire.
1212  //
1213  // Note that the increasing wire direction comes from the wire frame, while
1214  // the normal direction is computed independently by geometry.
1215  // The resulting normal in the wire frame is expected to be the same as the
1216  // plane normal from GetNormalDirection(); if this is not the case, flipping
1217  // the wire direction should restore it.
1218  //
1219 
1220  return wire.Direction()
1221  .Cross(GetIncreasingWireDirection())
1222  .Dot(GetNormalDirection())
1223  < +0.5; // should be in fact exactly +1
1224 
1225  } // PlaneGeo::shouldFlipWire()
1226 
1227  //......................................................................
1228 
1229 
1230 } // namespace geo
static std::string OrientationName(geo::Orient_t orientation)
Returns the name of the specified orientation.
Definition: PlaneGeo.cxx:780
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:129
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:61
double HalfWidth() const
Definition: PlaneGeo.h:1257
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:167
void SetView(geo::View_t view)
Set the signal view (for TPCGeo).
Definition: PlaneGeo.h:1179
WidthDepthProjection_t VectorWidthDepthProjection(geo::Vector_t const &v) const
Returns the projection of the specified vector on the plane.
Definition: PlaneGeo.h:917
geo::Point_t fCenter
Center of the plane, lying on the wire plane.
Definition: PlaneGeo.h:1285
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:765
void UpdateIncreasingWireDir()
Updates the cached direction to increasing wires.
Definition: PlaneGeo.cxx:1082
double fWirePitch
Pitch of wires in this plane.
Definition: PlaneGeo.h:1268
void SetSecondaryDir(Vector_t const &dir)
Change the secondary direction of the projection base.
Definition: Decomposer.h:447
void UpdateWirePitch()
Updates the stored wire pitch.
Definition: PlaneGeo.cxx:925
void UpdateWidthDepthDir()
Updates the cached depth and width direction.
Definition: PlaneGeo.cxx:1062
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:160
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.
Planes which measure V.
Definition: geo_types.h:77
auto mixedProduct(Vector const &a, Vector const &b, Vector const &c)
Unknown view.
Definition: geo_types.h:83
enum geo::_plane_orient Orient_t
Enumerate the possible plane projections.
Float_t x1[n_points_granero]
Definition: compare.C:5
void MakeWire(GeoNodePath_t &path, size_t depth)
Definition: PlaneGeo.cxx:542
void UpdateOrientation()
Updates plane orientation.
Definition: PlaneGeo.cxx:893
Int_t B
Definition: plot.C:25
Float_t Y
Definition: plot.C:39
geo::PlaneID fID
ID of this plane.
Definition: PlaneGeo.h:1287
Planes which measure X direction.
Definition: geo_types.h:81
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
Silly utility to sort vectors indirectly.
void extendToInclude(Data_t)
Extends the range to include the specified point.
Definition: SimpleGeo.h:456
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:222
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:441
bool isProjectionOnPlane(geo::Point_t const &point) const
Returns if the projection of specified point is within the plane.
Definition: PlaneGeo.cxx:605
::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:897
static constexpr std::size_t kFirstWireStart
Definition: PlaneGeo.cxx:111
Planes which measure Z direction.
Definition: geo_types.h:79
geo::WireGeo const & NearestWire(geo::Point_t const &pos) const
Returns the wire closest to the specified position.
Definition: PlaneGeo.cxx:705
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
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:1205
Vector GetNormalDirection() const
Returns the direction normal to the plane.
Definition: PlaneGeo.h:397
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:325
PlaneGeo const & plane
Plane to work on.
Definition: PlaneGeo.cxx:116
void FindWire(GeoNodePath_t &path, size_t depth)
Definition: PlaneGeo.cxx:517
WidthDepthProjection_t MoveProjectionToPlane(WidthDepthProjection_t const &proj) const
Returns the projection, moved onto the plane if necessary.
Definition: PlaneGeo.cxx:617
Vector GetIncreasingWireDirection() const
Returns the direction of increasing wires.
Definition: PlaneGeo.h:408
double ThetaZ() const
Returns angle of wire with respect to z axis in the Y-Z plane in radians.
Definition: WireGeo.h:192
geo::BoxBoundedGeo BoundingBox() const
Definition: PlaneGeo.cxx:469
Class for approximate comparisons.
Planes which measure Y direction.
Definition: geo_types.h:80
void DetectGeometryDirections()
Sets the geometry directions.
Definition: PlaneGeo.cxx:790
Projection_t wireEnds[4]
Cache: wire end projections.
Definition: PlaneGeo.cxx:122
void DriftPoint(geo::Point_t &position, double distance) const
Shifts the position of an electron drifted by a distance.
Definition: PlaneGeo.h:579
geo::Vector_t fNormal
Definition: PlaneGeo.h:1272
Rect fActiveArea
Area covered by wires in frame base.
Definition: PlaneGeo.h:1283
geo::PlaneGeo::Rect recomputeArea()
Definition: PlaneGeo.cxx:390
3-dimensional objects, potentially hits, clusters, prongs, etc.
Definition: geo_types.h:82
double ThetaZ() const
Angle of the wires from positive z axis; .
Definition: PlaneGeo.cxx:728
Float_t Z
Definition: plot.C:39
void UpdatePlaneNormal(geo::BoxBoundedGeo const &TPCbox)
Updates the cached normal to plane versor; needs the TPC box coordinates.
Definition: PlaneGeo.cxx:1041
TGeoVolume const * fVolume
Plane volume description.
Definition: PlaneGeo.h:1264
Planes which measure U.
Definition: geo_types.h:76
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WidthDepthReferenceTag > WidthDepthProjection_t
Definition: PlaneGeo.h:142
Int_t max
Definition: plot.C:27
Planes that are in the horizontal plane.
Definition: geo_types.h:87
Collection of exceptions for Geometry system.
lar::util::simple_geo::Volume Coverage() const
Returns a volume including all the wires in the plane.
Definition: PlaneGeo.cxx:566
void SortByPointers(Coll &coll, Sorter sorter)
Applies sorting indirectly, minimizing data copy.
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:673
WidthDepthDecomposer_t fDecompFrame
Definition: PlaneGeo.h:1280
void UpdatePhiZ()
Updates the stored .
Definition: PlaneGeo.cxx:930
Planes that are in the vertical plane (e.g. ArgoNeuT).
Definition: geo_types.h:88
geo::Point_t toWorldCoords(LocalPoint_t const &local) const
Transform point from local plane frame to world frame.
Definition: PlaneGeo.h:1132
WireCollection_t fWire
List of wires in this plane.
Definition: PlaneGeo.h:1267
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:657
Point GetCenter() const
Returns the centre of the wire plane in world coordinates [cm].
Definition: PlaneGeo.h:426
double fSinPhiZ
Sine of .
Definition: PlaneGeo.h:1269
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:78
Utilities to extend the interface of geometry vectors.
constexpr Vector Xaxis()
Returns a x axis vector of the specified type.
Definition: geo_vectors.h:218
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:1130
const WireGeo & FirstWire() const
Return the first wire in the plane.
Definition: PlaneGeo.h:325
RectSpecs fFrameSize
Definition: PlaneGeo.h:1281
void UpdateAfterSorting(geo::PlaneID planeid, geo::BoxBoundedGeo const &TPCbox)
Performs all needed updates after the TPC has sorted the planes.
Definition: PlaneGeo.cxx:733
virtual void SortWires(std::vector< geo::WireGeo * > &wgeo) const =0
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WidthDepthReferenceTag > WidthDepthDisplacement_t
Type for vector projections in the plane frame base representation.
Definition: PlaneGeo.h:146
static constexpr std::size_t kLastWireEnd
Definition: PlaneGeo.cxx:114
std::vector< TGeoNode const * > GeoNodePath_t
Definition: PlaneGeo.h:85
void UpdateView()
Updates the stored view.
Definition: PlaneGeo.cxx:945
Vector Direction() const
Returns the wire direction as a norm-one vector.
Definition: WireGeo.h:377
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:1258
Encapsulate the geometry of a wire.
Vector DepthDir() const
Return the direction of plane depth.
Definition: PlaneGeo.h:219
constexpr Vector Zaxis()
Returns a z axis vector of the specified type.
Definition: geo_vectors.h:226
unsigned int WireID_t
Type for the ID number.
Definition: geo_types.h:306
Range_t depth
Range along depth direction.
Definition: SimpleGeo.h:394
Tag for plane frame base vectors.
Definition: PlaneGeo.h:137
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
std::string value(boost::any const &)
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:580
Data_t delta(Data_t v, Data_t margin=0.0) const
Definition: SimpleGeo.h:443
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:593
A base class aware of world box coordinatesAn object describing a simple shape can inherit from this ...
Definition: BoxBoundedGeo.h:35
geo::Vector_t GetNormalAxis() const
Returns a direction normal to the plane (pointing is not defined).
Definition: PlaneGeo.cxx:873
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
Encapsulate the construction of a single detector plane.
double DistanceFromPlane(geo::Point_t const &point) const
Returns the distance of the specified point from the wire plane.
Definition: PlaneGeo.h:557
TDirectory * dir
Definition: macro.C:5
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:133
Int_t min
Definition: plot.C:26
geo::PlaneID const & ID() const
Returns the identifier of this plane.
Definition: PlaneGeo.h:190
double const wMargin
Margin subtracted from each side of width.
Definition: PlaneGeo.cxx:117
WireGeo const * WirePtr(unsigned int iwire) const
Returns the wire number iwire from this plane.
Definition: PlaneGeo.h:305
ActiveAreaCalculator(geo::PlaneGeo const &plane, double wMargin, double dMargin)
Definition: PlaneGeo.cxx:88
Float_t proj
Definition: plot.C:34
unsigned int Nwires() const
Number of wires in this plane.
Definition: PlaneGeo.h:250
geo::WireID ClosestWireID(geo::WireID::WireID_t wireNo) const
Returns the closest valid wire ID to the specified wire.
Definition: PlaneGeo.h:1305
bool WireIDincreasesWithZ() const
Returns whether the higher z wires have higher wire ID.
Definition: PlaneGeo.cxx:560
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:1270
Data_t upper
Ending coordinate.
Definition: SimpleGeo.h:327
Vector WidthDir() const
Return the direction of plane width.
Definition: PlaneGeo.h:207
Exception thrown on invalid wire number.
Definition: Exceptions.h:42
static constexpr std::size_t kFirstWireEnd
Definition: PlaneGeo.cxx:112
void UpdateWirePlaneCenter()
Updates the stored wire plane center.
Definition: PlaneGeo.cxx:1178
Direction
Definition: AssnsIter.h:24
WireDecomposer_t fDecompWire
Definition: PlaneGeo.h:1276
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
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:68
double WireCoordinate(Point const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:725
void UpdateDecompWireOrigin()
Updates the position of the wire coordinate decomposition.
Definition: PlaneGeo.cxx:1152
Class computing the active area of the plane.
Definition: PlaneGeo.cxx:85
void UpdateActiveArea()
Updates the internally used active area.
Definition: PlaneGeo.cxx:1162
Float_t e
Definition: plot.C:34
geo::Vector3DBase_t< PlaneGeoCoordinatesTag > LocalVector_t
Type of displacement vectors in the local GDML wire plane frame.
Definition: PlaneGeo.h:109
Data_t lower
Starting coordinate.
Definition: SimpleGeo.h:326
const WireGeo & LastWire() const
Return the last wire in the plane.
Definition: PlaneGeo.h:331
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:187
Float_t X
Definition: plot.C:39
Namespace collecting geometry-related classes utilities.
void SortWires(geo::GeoObjectSorter const &sorter)
Apply sorting to WireGeo objects.
Definition: PlaneGeo.cxx:550
PlaneGeo(GeoNodePath_t &path, size_t depth)
Construct a representation of a single plane of the detector.
Definition: PlaneGeo.cxx:435
Orient_t fOrientation
Is the plane vertical or horizontal?
Definition: PlaneGeo.h:1266
ROOT::Math::PositionVector2D< ROOT::Math::Cartesian2D< double >, geo::PlaneGeo::WidthDepthReferenceTag > Projection_t
Definition: PlaneGeo.cxx:103
void UpdateWireDir()
Updates the cached direction to wire.
Definition: PlaneGeo.cxx:1116
geo::Point3DBase_t< PlaneGeoCoordinatesTag > LocalPoint_t
Type of points in the local GDML wire plane frame.
Definition: PlaneGeo.h:106
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:230
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:367
geo::PlaneGeo::Rect activeArea
Result.
Definition: PlaneGeo.cxx:119
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.