LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
PlaneGeo.cxx
Go to the documentation of this file.
1 
5 // class header
7 
8 // LArSoft includes
10 #include "larcorealg/Geometry/Exceptions.h" // geo::InvalidWireError
12 #include "larcorealg/Geometry/geo_vectors_utils.h" // geo::vect::convertTo()
14 
15 // Framework includes
16 #include "cetlib/pow.h"
17 #include "cetlib_except/exception.h"
19 
20 // ROOT includes
21 #include "TClass.h"
22 #include "TGeoBBox.h"
23 #include "TGeoManager.h"
24 #include "TGeoMatrix.h"
25 #include "TGeoNode.h"
26 #include "TMath.h"
27 
28 // C/C++ standard library
29 #include <algorithm>
30 #include <array>
31 #include <cassert>
32 #include <functional> // std::less<>, std::greater<>, std::transform()
33 #include <iterator> // std::back_inserter()
34 #include <sstream> // std::ostringstream
35 #include <type_traits> // std::is_same<>, std::decay_t<>
36 
37 using namespace geo;
38 
39 namespace {
41  template <typename T>
42  T symmetricCapDelta(T value, T limit)
43  {
44  return (value < -limit) ? -limit - value : (value > +limit) ? +limit - value : 0.0;
45  }
46 
47  //......................................................................
60  struct ActiveAreaCalculator {
61 
62  ActiveAreaCalculator(PlaneGeo const& plane, double margin)
63  : plane(plane), wMargin(margin), dMargin(margin)
64  {}
65 
66  operator PlaneGeo::Rect() { return recomputeArea(); }
67 
68  private:
69  using Projection_t = ROOT::Math::PositionVector2D<ROOT::Math::Cartesian2D<double>,
72 
74  "Necessary maintenance: remove the now optional conversions");
75 
76  static constexpr std::size_t kFirstWireStart = 0;
77  static constexpr std::size_t kFirstWireEnd = 1;
78  static constexpr std::size_t kLastWireStart = 2;
79  static constexpr std::size_t kLastWireEnd = 3;
80 
81  PlaneGeo const& plane;
82  double const wMargin;
83  double const dMargin;
84  PlaneGeo::Rect activeArea;
85 
87  Projection_t wireEnds[4];
88 
89  void initializeWireEnds()
90  {
91  // Collect the projections of the relevant points.
92  //
93  // Sorted so that start points have width not larger than end points.
94  //
95  // PointWidthDepthProjection() erroneously returns a vector rather
96  // than a point, so a conversion is required
97  auto project = [](auto v) -> Projection_t { return {v.X(), v.Y()}; };
98 
99  wireEnds[kFirstWireStart] =
100  project(plane.PointWidthDepthProjection(plane.FirstWire().GetStart()));
101  wireEnds[kFirstWireEnd] =
102  project(plane.PointWidthDepthProjection(plane.FirstWire().GetEnd()));
103  if (wireEnds[kFirstWireStart].X() > wireEnds[kFirstWireEnd].X())
104  std::swap(wireEnds[kFirstWireStart], wireEnds[kFirstWireEnd]);
105  wireEnds[kLastWireStart] =
106  project(plane.PointWidthDepthProjection(plane.LastWire().GetStart()));
107  wireEnds[kLastWireEnd] = project(plane.PointWidthDepthProjection(plane.LastWire().GetEnd()));
108  if (wireEnds[kLastWireStart].X() > wireEnds[kLastWireEnd].X())
109  std::swap(wireEnds[kLastWireStart], wireEnds[kLastWireEnd]);
110  } // initializeWireEnds()
111 
112  void includeAllWireEnds()
113  {
114  //
115  // Find the basic area containing all the coordinates.
116  //
117 
118  // include all the coordinates of the first and last wire
119  for (auto const& aWireEnd : wireEnds) {
120  activeArea.width.extendToInclude(aWireEnd.X());
121  activeArea.depth.extendToInclude(aWireEnd.Y());
122  }
123 
124  } // includeAllWireEnds()
125 
126  void adjustCorners()
127  {
128  // Modify the corners so that none is father than half a pitch from all wires.
129  //
130  // directions in wire/depth plane
131  Vector_t const widthDir = {1.0, 0.0};
132  Vector_t const depthDir = {0.0, 1.0};
133  Vector_t wireCoordDir = plane.VectorWidthDepthProjection(plane.GetIncreasingWireDirection());
134  double const hp = plane.WirePitch() / 2.0; // half pitch
135 
136  // The plan: identify if wires are across or corner, and then:
137  // - across:
138  // - identify which sides
139  // - set the farther end of the wire from the side to be p/2 from its corner
140 
141  // - corner:
142  // - identify which corners
143  // - move the corners to p/2 from the wires
144 
145  // are the wires crossing side to side, as opposed to cutting corners?
146 
147  // these are the angles of the original wire coordinate direction
148  double const cosAngleWidth = vect::dot(wireCoordDir, widthDir);
149  double const cosAngleDepth = vect::dot(wireCoordDir, depthDir);
150  // if the wire coordinate direction is on first or third quadrant:
151  bool const bPositiveAngle = none_or_both((wireCoordDir.X() >= 0), (wireCoordDir.Y() >= 0));
152 
153  // now we readjust the wire coordinate direction to always point toward positive
154  // width; this breaks the relation between wireCoordDir and which is the first/last
155  // wire
156  if (cosAngleWidth < 0) wireCoordDir = -wireCoordDir;
157 
158  // let's study the first wire (ends are sorted by width)
159  assert(wireEnds[kFirstWireEnd].X() >= wireEnds[kFirstWireStart].X());
160  bool const bAlongWidth // horizontal
161  = equal(wireEnds[kFirstWireEnd].X(), activeArea.width.upper) &&
162  equal(wireEnds[kFirstWireStart].X(), activeArea.width.lower);
163  bool const bAlongDepth =
164  !bAlongWidth && // vertical
165  equal(std::max(wireEnds[kFirstWireStart].Y(), wireEnds[kFirstWireEnd].Y()),
166  activeArea.depth.upper) &&
167  equal(std::min(wireEnds[kFirstWireStart].Y(), wireEnds[kFirstWireEnd].Y()),
168  activeArea.depth.lower);
169  assert(!(bAlongWidth && bAlongDepth));
170 
171  if (bAlongWidth) { // horizontal
172 
173  // +---------+
174  // | ___,--| upper width bound
175  // |--' |
176 
177  // find which is the wire with higher width:
178  // the last wire is highest if the wire coordinate direction (which is defined by
179  // what is first and what is last) is parallel to the width direction
180  std::size_t const iUpperWire = (cosAngleDepth > 0) ? kLastWireStart : kFirstWireStart;
181  // largest distance from upper depth bound of the two ends of wire
182  double const maxUpperDistance =
183  activeArea.depth.upper -
184  std::min(wireEnds[iUpperWire].Y(), wireEnds[iUpperWire ^ 0x1].Y());
185  // set the upper side so that the maximum distance is p/2 (it may be actually less
186  // if the wire is not perfectly horizontal)
187  activeArea.depth.upper += (hp - maxUpperDistance);
188 
189  // |--.___ |
190  // | `--| deal with the lower bound now
191  // +---------+
192 
193  std::size_t const iLowerWire = (cosAngleDepth > 0) ? kFirstWireStart : kLastWireStart;
194  // largest distance from lower depth bound of the two ends of wire
195  double const maxLowerDistance =
196  std::max(wireEnds[iLowerWire].Y(), wireEnds[iLowerWire ^ 0x1].Y()) -
197  activeArea.depth.lower;
198  // set the upper side so that the minimum distance is p/2
199  activeArea.depth.lower -= (hp - maxLowerDistance);
200  } // horizontal wires
201  else if (bAlongDepth) { // vertical
202  // --,---+
203  // | |
204  // \ |
205  // | | upper depth bound
206  // \ |
207  // | |
208  // ------+
209 
210  // find which is the wire with higher depth:
211  // the last wire is highest if the wire coordinate direction (which is defined by
212  // what is first and what is last) is parallel to the depth direction
213  std::size_t const iUpperWire = (cosAngleWidth > 0) ? kLastWireStart : kFirstWireStart;
214  // largest distance from upper depth bound of the two ends of wire
215  double const maxUpperDistance =
216  activeArea.width.upper -
217  std::min(wireEnds[iUpperWire].X(), wireEnds[iUpperWire ^ 0x1].X());
218  // set the upper side so that the minimum distance is p/2
219  activeArea.width.upper += (hp - maxUpperDistance);
220 
221  // +-,----
222  // | |
223  // | \ .
224  // | | deal with the lower bound now
225  // | \ .
226  // | |
227  // +------
228  std::size_t const iLowerWire = (cosAngleWidth > 0) ? kFirstWireStart : kLastWireStart;
229  // largest distance from lower width bound of the two ends of wire
230  double const maxLowerDistance =
231  std::max(wireEnds[iLowerWire].X(), wireEnds[iLowerWire ^ 0x1].X()) -
232  activeArea.width.lower;
233  // set the upper side so that the minimum distance is p/2
234  activeArea.width.lower -= (hp - maxLowerDistance);
235 
236  } // vertical wires
237  else if (bPositiveAngle) { // wires are not going across: corners!
238  // corners at (lower width, lower depth), (upper width, upper depth)
239 
240  // -._------+
241  // `-._ | upper width corner (upper depth)
242  // `-|
243 
244  // start of the wire on the upper corner (width coordinate is lower for start than
245  // for end)
246  std::size_t const iUpperWire = (cosAngleWidth > 0) ? kLastWireStart : kFirstWireStart;
247 
248  double const upperDistance =
249  vect::dot(Vector_t(activeArea.width.upper - wireEnds[iUpperWire].X(), 0.0), wireCoordDir);
250  // make the upper distance become p/2
251  auto const upperDelta = (hp - upperDistance) * wireCoordDir;
252  activeArea.width.upper += upperDelta.X();
253  activeArea.depth.upper += upperDelta.Y();
254 
255  // |-._
256  // | `-._ lower width corner (lower depth)
257  // +-------`-
258 
259  // end of the wire on the lower corner (width coordinate is lower than the end)
260  std::size_t const iLowerWire = (cosAngleWidth > 0) ? kFirstWireEnd : kLastWireEnd;
261 
262  double const lowerDistance =
263  vect::dot(Vector_t(wireEnds[iLowerWire].X() - activeArea.width.lower, 0.0), wireCoordDir);
264  // make the lower distance become p/2 (note direction of wire coord)
265  auto const lowerDelta = (hp - lowerDistance) * wireCoordDir;
266  activeArea.width.lower -= lowerDelta.X();
267  activeArea.depth.lower -= lowerDelta.Y();
268  }
269  else { // !bPositiveAngle
270  // corners at (lower width, upper depth), (upper width, lower depth)
271 
272  // _,-|
273  // _,-' | upper width corner (lower depth)
274  // -'-------+
275 
276  // start of the wire on the upper corner (width coordinate is lower than the end)
277  std::size_t const iUpperWire = (cosAngleWidth > 0) ? kLastWireStart : kFirstWireStart;
278 
279  double const upperDistance =
280  vect::dot(Vector_t(activeArea.width.upper - wireEnds[iUpperWire].X(), 0.0), wireCoordDir);
281  // make the upper distance become p/2
282  auto const upperDelta = (hp - upperDistance) * wireCoordDir;
283  activeArea.width.upper += upperDelta.X();
284  activeArea.depth.lower += upperDelta.Y();
285 
286  // +------_,-
287  // | _,-' lower width corner (upper depth)
288  // |-'
289 
290  // end of the wire on the lower corner (width coordinate is lower than the end)
291  std::size_t const iLowerWire = (cosAngleWidth > 0) ? kFirstWireEnd : kLastWireEnd;
292 
293  double const lowerDistance =
294  vect::dot(Vector_t(wireEnds[iLowerWire].X() - activeArea.width.lower, 0.0), wireCoordDir);
295  // make the lower distance become p/2 (note direction of wire coord)
296  auto const lowerDelta = (hp - lowerDistance) * wireCoordDir;
297  activeArea.width.lower -= lowerDelta.X();
298  activeArea.depth.upper -= lowerDelta.Y();
299 
300  } // if ...
301 
302  } // adjustCorners()
303 
304  void applyMargin()
305  {
306  if (wMargin != 0.0) {
307  activeArea.width.lower += wMargin;
308  activeArea.width.upper -= wMargin;
309  }
310  if (dMargin != 0.0) {
311  activeArea.depth.lower += dMargin;
312  activeArea.depth.upper -= dMargin;
313  }
314  } // applyMargin()
315 
316  PlaneGeo::Rect recomputeArea()
317  {
318  activeArea = {};
319 
320  // 0. collect the projections of the relevant point
321  initializeWireEnds();
322 
323  // 1. find the basic area containing all the coordinates
324  includeAllWireEnds();
325 
326  // 2. adjust area so that no corner is father than half a wire pitch
327  adjustCorners();
328 
329  // 3. apply an absolute margin
330  applyMargin();
331 
332  return activeArea;
333  } // computeArea()
334 
336  static bool none_or_both(bool a, bool b) { return a == b; }
337 
339  template <typename T>
340  static bool equal(T a, T b, T tol = T(1e-5))
341  {
342  return std::abs(a - b) <= tol;
343  }
344 
345  }; // struct ActiveAreaCalculator
346 }
347 
348 namespace geo {
349 
350  //----------------------------------------------------------------------------
351  //--- geo::PlaneGeo
352  //---
353  PlaneGeo::PlaneGeo(TGeoNode const* node, TransformationMatrix&& trans, WireCollection_t&& wires)
354  : fNode(node), fTrans(std::move(trans)), fWire(std::move(wires))
355  {
356  if (!fNode->GetVolume()) {
357  throw cet::exception("PlaneGeo")
358  << "Plane geometry node " << fNode->IsA()->GetName() << "[" << fNode->GetName() << ", #"
359  << fNode->GetNumber() << "] has no volume!\n";
360  }
361 
362  // view is now set at TPC level with SetView
363 
366  }
367 
368  //......................................................................
369 
371  {
372  //
373  // The algorithm is not very refined...
374  //
375 
376  TGeoBBox const* pShape = dynamic_cast<TGeoBBox const*>(Volume().GetShape());
377  if (!pShape) {
378  throw cet::exception("PlaneGeo")
379  << "BoundingBox(): volume " << Volume().IsA()->GetName() << " is not a TGeoBBox!";
380  }
381 
382  BoxBoundedGeo box;
383  unsigned int points = 0;
384  for (double dx : {-(pShape->GetDX()), +(pShape->GetDX())}) {
385  for (double dy : {-(pShape->GetDY()), +(pShape->GetDY())}) {
386  for (double dz : {-(pShape->GetDZ()), +(pShape->GetDZ())}) {
387 
388  auto const p = toWorldCoords(LocalPoint_t{dx, dy, dz});
389 
390  if (points++ == 0)
391  box.SetBoundaries(p, p);
392  else
393  box.ExtendToInclude(p);
394 
395  } // for z
396  } // for y
397  } // for x
398  return box;
399  }
400 
401  //......................................................................
402 
403  WireGeo const& PlaneGeo::Wire(unsigned int iwire) const
404  {
405  if (WireGeo const* pWire = WirePtr(iwire)) { return *pWire; }
406  throw cet::exception("WireOutOfRange") << "Request for non-existant wire " << iwire << "\n";
407  }
408 
409  //......................................................................
411  {
412  std::sort(fWire.begin(), fWire.end(), cmp);
413  }
414 
415  //......................................................................
417  {
419  }
420 
421  //......................................................................
422  std::string PlaneGeo::PlaneInfo(std::string indent /* = "" */,
423  unsigned int verbosity /* = 1 */) const
424  {
425  std::ostringstream sstr;
426  PrintPlaneInfo(sstr, indent, verbosity);
427  return sstr.str();
428  }
429 
430  //......................................................................
432  double wMargin,
433  double dMargin) const
434  {
435  return {symmetricCapDelta(proj.X(), fFrameSize.HalfWidth() - wMargin),
436  symmetricCapDelta(proj.Y(), fFrameSize.HalfDepth() - dMargin)};
437  }
438 
439  //......................................................................
442  double wMargin,
443  double dMargin) const
444  {
445  return {fActiveArea.width.delta(proj.X(), wMargin), fActiveArea.depth.delta(proj.Y(), dMargin)};
446  }
447 
448  //......................................................................
449  bool PlaneGeo::isProjectionOnPlane(Point_t const& point) const
450  {
451  auto const deltaProj = DeltaFromPlane(PointWidthDepthProjection(point));
452  return (deltaProj.X() == 0.) && (deltaProj.Y() == 0.);
453  }
454 
455  //......................................................................
457  WidthDepthProjection_t const& proj) const
458  {
459  // We have a more complicated implementation to avoid rounding errors. In this way,
460  // the result is really guaranteed to be exactly on the border.
461  auto const delta = DeltaFromPlane(proj);
462  return {(delta.X() == 0.0) ?
463  proj.X() :
464  ((delta.X() > 0) ? -fFrameSize.HalfWidth() // delta positive -> proj on negative side
465  :
467  (delta.Y() == 0.0) ?
468  proj.Y() :
469  ((delta.Y() > 0) ? -fFrameSize.HalfDepth() // delta positive -> proj on negative side
470  :
471  fFrameSize.HalfDepth())};
472  }
473 
474  //......................................................................
476  {
477  // This implementation is subject to rounding errors, since the result of the addition
478  // might jitter above or below the border.
479 
480  auto const deltaProj = DeltaFromPlane(PointWidthDepthProjection(point));
481  return point + deltaProj.X() * WidthDir() + deltaProj.Y() * DepthDir();
482  }
483 
484  //......................................................................
486  {
487  // 1) compute the wire coordinate of the point
488  // 2) get the closest wire number
489  // 3) check if the wire does exist
490  // 4) build and return the wire ID
491 
492  // this line merges parts (1) and (2); add 0.5 to have the correct rounding:
493  int nearestWireNo = int(0.5 + WireCoordinate(pos));
494 
495  // if we are outside of the wireplane range, throw an exception
496  if ((nearestWireNo < 0) || ((unsigned int)nearestWireNo >= Nwires())) {
497 
498  auto wireNo = nearestWireNo; // save for the output
499 
500  if (nearestWireNo < 0)
501  wireNo = 0;
502  else
503  wireNo = Nwires() - 1;
504 
505  throw InvalidWireError("Geometry", ID(), nearestWireNo, wireNo)
506  << "Can't find nearest wire for position " << pos << " in plane " << std::string(ID())
507  << " approx wire number # " << wireNo << " (capped from " << nearestWireNo << ")\n";
508  } // if invalid
509 
510  return {ID(), (WireID::WireID_t)nearestWireNo};
511  }
512 
513  //......................................................................
514  WireGeo const& PlaneGeo::NearestWire(Point_t const& point) const
515  {
516  // Note that this code is ready for when NearestWireID() will be changed to return an
517  // invalid ID instead of throwing. As things are now, `NearestWireID()` will never
518  // return an invalid ID, but it will throw an exception similar to this one.
519 
520  WireID const wireID = NearestWireID(point);
521  if (wireID) return Wire(wireID); // we have that wire, so we return it
522 
523  // wire ID is invalid, meaning it's out of range. Throw an exception!
524  WireID const closestID = ClosestWireID(wireID);
525  throw InvalidWireError("Geometry", ID(), closestID.Wire, wireID.Wire)
526  << "Can't find nearest wire for position " << point << " in plane " << std::string(ID())
527  << " approx wire number # " << closestID.Wire << " (capped from " << wireID.Wire << ")\n";
528  }
529 
530  //......................................................................
532  {
533  assert(lar::util::Vector2DComparison{1e-6}.nonZero(projDir));
534  return std::sqrt(cet::square(projDir.X() / projDir.Y()) + 1.0) * fWirePitch;
535  }
536 
537  //......................................................................
539  {
540  // the secondary component of the wire decomposition basis is wire coord.
541  double const r = dir.R();
542  assert(r >= 1.e-6);
543 
544  double const absWireCoordProj = std::abs(fDecompWire.VectorSecondaryComponent(dir));
545  return r / absWireCoordProj * fWirePitch;
546  }
547 
548  //......................................................................
549  double PlaneGeo::ThetaZ() const
550  {
551  return FirstWire().ThetaZ();
552  }
553 
554  //......................................................................
556  {
557  // the order here matters
558 
559  // reset our ID
560  fID = planeid;
561 
562  UpdatePlaneNormal(TPCbox);
565 
566  // update wires
567  WireID::WireID_t wireNo = 0;
568  for (auto& wire : fWire) {
569  wire.UpdateAfterSorting(WireID(fID, wireNo), shouldFlipWire(wire));
570  ++wireNo;
571  } // for wires
572 
574  UpdateWireDir();
577  UpdateWirePitch();
579  UpdatePhiZ();
580  UpdateView();
581  }
582 
583  //......................................................................
584  std::string PlaneGeo::ViewName(View_t view)
585  {
586  switch (view) {
587  case kU: return "U";
588  case kV: return "V";
589  case kZ: return "Z";
590  case kY: return "Y";
591  case kX: return "X";
592  case k3D: return "3D";
593  case kUnknown: return "?";
594  default: return "<UNSUPPORTED (" + std::to_string((int)view) + ")>";
595  }
596  }
597 
598  //......................................................................
599  std::string PlaneGeo::OrientationName(Orient_t orientation)
600  {
601  switch (orientation) {
602  case kHorizontal: return "horizontal"; break;
603  case kVertical: return "vertical"; break;
604  default: return "unexpected"; break;
605  }
606  }
607 
608  //......................................................................
610  {
611  // We need to identify which are the "long" directions of the plane. We assume it is
612  // a box, and the shortest side is excluded. The first direction ("width") is given
613  // by preference to z. If z is the direction of the normal to the plane... oh well.
614  // Let's say privilege to the one which comes from local z, then y. That means:
615  // undefined.
616  //
617  // Requirements:
618  // - ROOT geometry information (shapes and transformations)
619  // - the shape must be a box (an error is PRINTED if not)
620  // - center of the wire plane (not just the center of the plane box)
621 
622  // how do they look like in the world?
623  TGeoBBox const* pShape = dynamic_cast<TGeoBBox const*>(Volume().GetShape());
624  if (!pShape) {
625  mf::LogError("BoxInfo") << "Volume " << Volume().IsA()->GetName()
626  << " is not a TGeoBBox! Dimensions won't be available.";
627  // set it invalid
629  fDecompFrame.SetMainDir({0., 0., 0.});
630  fDecompFrame.SetSecondaryDir({0., 0., 0.});
631  fFrameSize = {0.0, 0.0};
632  return;
633  }
634 
635  std::array<Vector_t, 3U> sides;
636  size_t iSmallest = 3;
637  {
638  size_t iSide = 0;
639 
640  sides[iSide] = toWorldCoords(LocalVector_t{pShape->GetDX(), 0.0, 0.0});
641  iSmallest = iSide;
642  ++iSide;
643 
644  sides[iSide] = toWorldCoords(LocalVector_t{0.0, pShape->GetDY(), 0.0});
645  if (sides[iSide].Mag2() < sides[iSmallest].Mag2()) iSmallest = iSide;
646  ++iSide;
647 
648  sides[iSide] = toWorldCoords(LocalVector_t{0.0, 0.0, pShape->GetDZ()});
649  if (sides[iSide].Mag2() < sides[iSmallest].Mag2()) iSmallest = iSide;
650  ++iSide;
651  }
652 
653  // which are the largest ones?
654  size_t kept[2];
655  {
656  size_t iKept = 0;
657  for (size_t i = 0; i < 3; ++i)
658  if (i != iSmallest) kept[iKept++] = i;
659  }
660 
661  // which is which?
662  //
663  // Pick width as the most z-like.
664  size_t const iiWidth =
665  std::abs(sides[kept[0]].Unit().Z()) > std::abs(sides[kept[1]].Unit().Z()) ? 0 : 1;
666  size_t const iWidth = kept[iiWidth];
667  size_t const iDepth = kept[1 - iiWidth]; // the other
668 
669  fDecompFrame.SetMainDir(vect::rounded01(sides[iWidth].Unit(), 1e-4));
670  fDecompFrame.SetSecondaryDir(vect::rounded01(sides[iDepth].Unit(), 1e-4));
671  fFrameSize.halfWidth = sides[iWidth].R();
672  fFrameSize.halfDepth = sides[iDepth].R();
673  }
674 
675  //......................................................................
677  {
678  unsigned const int NWires = Nwires();
679  if (NWires < 2) return {}; // why are we even here?
680 
681  // 1) get the direction of the middle wire
682  auto const WireDir = Wire(NWires / 2).Direction();
683 
684  // 2) get the direction between the middle wire and the next one
685  auto const ToNextWire = Wire(NWires / 2 + 1).GetCenter() - Wire(NWires / 2).GetCenter();
686 
687  // 3) get the direction perpendicular to the plane
688  // 4) round it
689  // 5) return its norm
690  return vect::rounded01(WireDir.Cross(ToNextWire).Unit(), 1e-4);
691  }
692 
693  //......................................................................
695  {
696  // this algorithm needs to know about the axis; the normal is expected to be already
697  // updated.
698 
699  // sanity check
700  if (fWire.size() < 2) {
701  // this likely means construction is not complete yet
702  throw cet::exception("NoWireInPlane")
703  << "PlaneGeo::UpdateOrientation(): only " << fWire.size() << " wires!\n";
704  } // if
705 
706  auto normal = GetNormalDirection();
707 
708  if (std::abs(std::abs(normal.X()) - 1.) < 1e-3)
710  else if (std::abs(std::abs(normal.Y()) - 1.) < 1e-3)
712  else {
713  // at this point, the only problem is the lack of a label for this orientation;
714  // probably introducing a geo::kOtherOrientation would suffice
715  throw cet::exception("Geometry")
716  << "Plane with unsupported orientation (normal: " << normal << ")\n";
717  }
718  }
719 
720  //......................................................................
722  {
723  // pick long wires around the center of the detector, so that their coordinates are
724  // defined with better precision
725  assert(Nwires() > 1);
726 
727  auto const iWire = Nwires() / 2;
728 
729  fWirePitch = WireGeo::WirePitch(Wire(iWire - 1), Wire(iWire));
730  }
731 
732  //......................................................................
734  {
735  auto const& wire_coord_dir = GetIncreasingWireDirection();
736  fCosPhiZ = wire_coord_dir.Z();
737  fSinPhiZ = wire_coord_dir.Y();
738  }
739 
741  {
771  auto const& normalDir = GetNormalDirection();
772  auto const& wireDir = GetWireDirection();
773 
774  // normal direction has been rounded, so exact comparison can work
775  if (std::abs(normalDir.Y()) != 1.0) {
776  // normal case: drift direction is not along y (vertical)
777 
778  // yw is pretty much GetWireDirection().Y()... thetaY is related to atan2(ynw, yw)
779  double const yw = vect::dot(wireDir, Yaxis());
780  double const ynw = vect::mixedProduct(Yaxis(), normalDir, wireDir);
781 
782  if (std::abs(yw) < 1.0e-4) { // wires orthogonal to y axis
783  double const closeToX = std::abs(vect::dot(normalDir, Xaxis()));
784  double const closeToZ = std::abs(vect::dot(normalDir, Zaxis()));
785  SetView((closeToZ > closeToX) ? kX : kY);
786  }
787  else if (std::abs(ynw) < 1.0e-4) { // wires parallel to y axis
788  SetView(kZ);
789  }
790  else if ((ynw * yw) < 0)
791  SetView(kU); // different sign => thetaY > 0
792  else if ((ynw * yw) > 0)
793  SetView(kV); // same sign => thetaY < 0
794  else
795  assert(false); // logic error?!
796  }
797  else { // if drift is vertical
798  // special case: drift direction is along y (vertical)
799 
800  // zw is pretty much GetWireDirection().Z()...
801  double const zw = vect::dot(wireDir, Zaxis());
802  // while GetNormalDirection() axis is on y, its direction is not fixed:
803  double const znw = vect::mixedProduct(Zaxis(), normalDir, wireDir);
804 
805  // thetaZ is std::atan(znw/zw)
806 
807  if (std::abs(zw) < 1.0e-4) { // orthogonal to z, orthogonal to y...
808  // this is equivalent to thetaZ = +/- pi/2
809  SetView(kZ);
810  }
811  else if (std::abs(znw) < 1.0e-4) { // parallel to z, orthogonal to y...
812  // this is equivalent to thetaZ = 0
813  SetView(kX);
814  }
815  else if ((znw * zw) < 0)
816  SetView(kU); // different sign => thetaZ > 0
817  else if ((znw * zw) > 0)
818  SetView(kV); // same sign => thetaZ < 0
819  else
820  assert(false); // logic error?!
821 
822  } // if drift direction... else
823  }
824 
825  //......................................................................
827  {
828  // direction normal to the wire plane, points toward the center of TPC
829 
830  // start from the axis
832 
833  // now evaluate where we are pointing
834  auto const towardCenter = TPCbox.Center() - GetBoxCenter();
835 
836  // if they are pointing in opposite directions, flip the normal
837  if (fNormal.Dot(towardCenter) < 0) fNormal = -fNormal;
838  vect::round01(fNormal, 1e-3);
839  }
840 
841  //......................................................................
843  {
844  // fix the positiveness of the width/depth/normal frame
845 
846  // The basis is already set and orthonormal, with only the width and depth directions
847  // arbitrary. We choose the direction of the secondary axis ("depth") so that the
848  // frame normal is oriented in the general direction of the plane normal (the latter
849  // is computed independently).
850  if (WidthDir().Cross(DepthDir()).Dot(GetNormalDirection()) < 0.0) {
852  }
853  }
854 
855  //......................................................................
857  {
858  // Direction measured by the wires, pointing toward increasing wire number; requires:
859  // - the normal to the plane to be correct
860  // - wires to be sorted
861 
862  // 1) get the direction of the middle wire
863  auto refWireNo = Nwires() / 2;
864  if (refWireNo == Nwires() - 1) --refWireNo;
865  auto const& refWire = Wire(refWireNo);
866  auto const& WireDir = refWire.Direction(); // we only rely on the axis
867 
868  // 2) get the axis perpendicular to it on the wire plane (arbitrary direction)
869  auto wireCoordDir = GetNormalDirection().Cross(WireDir).Unit();
870 
871  // 3) where is the next wire?
872  auto toNextWire = Wire(refWireNo + 1).GetCenter() - refWire.GetCenter();
873 
874  // 4) if wireCoordDir is pointing away from the next wire, flip it
875  if (wireCoordDir.Dot(toNextWire) < 0) { wireCoordDir = -wireCoordDir; }
876  fDecompWire.SetSecondaryDir(vect::rounded01(wireCoordDir, 1e-4));
877  }
878 
879  //......................................................................
881  {
883 
884  // check that the resulting normal matches the plane one
885  assert(
887  }
888 
889  //......................................................................
891  {
892  if (fWire.empty()) { return; }
893 
894  // Compare one wire (the first one, for convenience) with all other wires; the wire
895  // pitch is the smallest distance we find.
896  //
897  // This algorithm assumes wire pitch is constant, but it does not assume wire ordering
898  auto firstWire = fWire.cbegin(), wire = firstWire, wend = fWire.cend();
899  fWirePitch = WireGeo::WirePitch(*firstWire, *(++wire));
900 
901  while (++wire != wend) {
902  auto wirePitch = WireGeo::WirePitch(*firstWire, *wire);
903  if (wirePitch < 1e-4) continue; // it's 0!
904  if (wirePitch < fWirePitch) fWirePitch = wirePitch;
905  }
906  }
907 
908  //......................................................................
910  {
911  // update the origin of the reference frame (the middle of the first wire)
913  }
914 
915  //......................................................................
917  {
918  // The active area is defined in the width/depth space which include approximatively
919  // all wires.
920  //
921  // See `ActiveAreaCalculator` for details of the algorithm.
922 
923  // we scratch 1 um from each side to avoid rounding errors later
924  fActiveArea = ActiveAreaCalculator(*this, 0.0001);
925  }
926 
927  //......................................................................
929  {
930  // The center of the wire plane is defined as the center of the plane box, translated
931  // to the plane the wires lie on. This assumes that the thickness direction of the
932  // box is aligned with the drift direction, so that the translated point is still in
933  // the middle of width and depth dimensions. It is possible to remove that assumption
934  // by translating the center of the box along the thickness direction enough to bring
935  // it to the wire plane. The math is just a bit less straightforward, so we don't
936  // bother yet.
937  //
938  // Requirements:
939  // * the wire decomposition frame must be set up (at least its origin and normal
940  // direction)
941 
942  fCenter = GetBoxCenter();
943 
945 
946  vect::round0(fCenter, 1e-7); // round dimensions less than 1 nm to 0
947 
948  fDecompFrame.SetOrigin(fCenter); // equivalent to GetCenter() now
949 
950  } // PlaneGeo::UpdateWirePlaneCenter()
951 
952  //......................................................................
953  bool PlaneGeo::shouldFlipWire(WireGeo const& wire) const
954  {
955  // The correct orientation is so that:
956  //
957  // (direction) x (wire coordinate direction) . (plane normal)
958  //
959  // is positive; it it's negative, then we should flip the wire.
960  //
961  // Note that the increasing wire direction comes from the wire frame, while the normal
962  // direction is computed independently by geometry. The resulting normal in the wire
963  // frame is expected to be the same as the plane normal from GetNormalDirection(); if
964  // this is not the case, flipping the wire direction should restore it.
965 
966  return wire.Direction().Cross(GetIncreasingWireDirection()).Dot(GetNormalDirection()) <
967  +0.5; // should be in fact exactly +1
968  }
969 
970 } // namespace geo
TRandom r
Definition: spectrum.C:23
void round01(Vector &v, Scalar tol)
Returns a vector with all components rounded if close to 0, -1 or +1.
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:112
Vector_t GetNormalAxis() const
Returns a direction normal to the plane (pointing is not defined).
Definition: PlaneGeo.cxx:676
double HalfWidth() const
Definition: PlaneGeo.h:1199
TGeoNode const * fNode
Node within full geometry.
Definition: PlaneGeo.h:1205
auto VectorSecondaryComponent(Vector_t const &v) const
Returns the secondary component of a vector.
Definition: Decomposer.h:525
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WidthDepthReferenceTag > WidthDepthDisplacement_t
Type for vector projections in the plane frame base representation.
Definition: PlaneGeo.h:132
Point_t const & GetCenter() const
Returns the world coordinate of the center of the wire [cm].
Definition: WireGeo.h:219
BoxBoundedGeo BoundingBox() const
Definition: PlaneGeo.cxx:370
std::string PlaneInfo(std::string indent="", unsigned int verbosity=1) const
Returns a string with plane information.
Definition: PlaneGeo.cxx:422
void UpdateIncreasingWireDir()
Updates the cached direction to increasing wires.
Definition: PlaneGeo.cxx:856
double fWirePitch
Pitch of wires in this plane.
Definition: PlaneGeo.h:1210
TGeoVolume const & Volume() const
Definition: PlaneGeo.h:1145
void SetSecondaryDir(Vector_t const &dir)
Change the secondary direction of the projection base.
Definition: Decomposer.h:436
static std::string ViewName(View_t view)
Returns the name of the specified view.
Definition: PlaneGeo.cxx:584
void UpdateWirePitch()
Updates the stored wire pitch.
Definition: PlaneGeo.cxx:721
void UpdateWidthDepthDir()
Updates the cached depth and width direction.
Definition: PlaneGeo.cxx:842
Point_t Center() const
Returns the center point of the box.
Vector_t const & DepthDir() const
Return the direction of plane depth.
Definition: PlaneGeo.h:201
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:160
Point_t const & GetCenter() const
Returns the centre of the wire plane in world coordinates [cm].
Definition: PlaneGeo.h:366
lar::util::simple_geo::Rectangle< double > Rect
Type for description of rectangles.
Definition: PlaneGeo.h:144
double WireCoordinate(Point_t const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:704
Vector_t const & NormalDir() const
Returns the plane normal axis direction.
Definition: Decomposer.h:456
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
WireID NearestWireID(Point_t const &pos) const
Returns the ID of wire closest to the specified position.
Definition: PlaneGeo.cxx:485
Planes which measure V.
Definition: geo_types.h:132
auto mixedProduct(Vector const &a, Vector const &b, Vector const &c)
Unknown view.
Definition: geo_types.h:138
enum geo::_plane_orient Orient_t
Enumerate the possible plane projections.
Float_t x1[n_points_granero]
Definition: compare.C:5
Provides simple real number checks.
void UpdateOrientation()
Updates plane orientation.
Definition: PlaneGeo.cxx:694
void UpdateAfterSorting(PlaneID planeid, BoxBoundedGeo const &TPCbox)
Performs all needed updates after the TPC has sorted the planes.
Definition: PlaneGeo.cxx:555
Planes which measure X direction.
Definition: geo_types.h:136
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
void extendToInclude(Data_t)
Extends the range to include the specified point.
Definition: SimpleGeo.h:483
Point_t fCenter
Center of the plane, lying on the wire plane.
Definition: PlaneGeo.h:1227
constexpr Vector Yaxis()
Returns a y axis vector of the specified type.
Definition: geo_vectors.h:215
bool isProjectionOnPlane(Point_t const &point) const
Returns if the projection of specified point is within the plane.
Definition: PlaneGeo.cxx:449
constexpr auto abs(T v)
Returns the absolute value of the argument.
Point_t toWorldCoords(LocalPoint_t const &local) const
Transform point from local plane frame to world frame.
Definition: PlaneGeo.h:1111
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:403
STL namespace.
Planes which measure Z direction.
Definition: geo_types.h:134
double DistanceFromPlane(Point_t const &point) const
Returns the distance of the specified point from the wire plane.
Definition: PlaneGeo.h:484
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
PlaneID fID
ID of this plane.
Definition: PlaneGeo.h:1229
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
void round0(Vector &v, Scalar tol)
Returns a vector with all components rounded if close to 0.
WidthDepthProjection_t VectorWidthDepthProjection(Vector_t const &v) const
Returns the projection of the specified vector on the plane.
Definition: PlaneGeo.h:914
Vector_t fNormal
Definition: PlaneGeo.h:1214
Point_t GetStart() const
Returns the world coordinate of one end of the wire [cm].
Definition: WireGeo.h:224
Point_t GetEnd() const
Returns the world coordinate of one end of the wire [cm].
Definition: WireGeo.h:229
void UpdatePlaneNormal(BoxBoundedGeo const &TPCbox)
Updates the cached normal to plane versor; needs the TPC box coordinates.
Definition: PlaneGeo.cxx:826
WidthDepthProjection_t MoveProjectionToPlane(WidthDepthProjection_t const &proj) const
Returns the projection, moved onto the plane if necessary.
Definition: PlaneGeo.cxx:456
double ThetaZ() const
Returns angle of wire with respect to z axis in the Y-Z plane in radians.
Definition: WireGeo.h:246
Class for approximate comparisons.
Planes which measure Y direction.
Definition: geo_types.h:135
void DetectGeometryDirections()
Sets the geometry directions.
Definition: PlaneGeo.cxx:609
WireGeo const & NearestWire(Point_t const &pos) const
Returns the wire closest to the specified position.
Definition: PlaneGeo.cxx:514
double InterWireProjectedDistance(WireCoordProjection_t const &projDir) const
Returns the distance between wires along the specified direction.
Definition: PlaneGeo.cxx:531
Rect fActiveArea
Area covered by wires in frame base.
Definition: PlaneGeo.h:1225
void DriftPoint(Point_t &position, double distance) const
Shifts the position of an electron drifted by a distance.
Definition: PlaneGeo.h:503
3-dimensional objects, potentially hits, clusters, prongs, etc.
Definition: geo_types.h:137
double ThetaZ() const
Angle of the wires from positive z axis; .
Definition: PlaneGeo.cxx:549
Planes which measure U.
Definition: geo_types.h:131
Planes that are in the horizontal plane.
Definition: geo_types.h:142
Collection of exceptions for Geometry system.
Point_t GetBoxCenter() const
Returns the centre of the box representing the plane.
Definition: PlaneGeo.h:380
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
double InterWireDistance(Vector_t const &dir) const
Returns the distance between wires along the specified direction.
Definition: PlaneGeo.cxx:538
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
WidthDepthDecomposer_t fDecompFrame
Definition: PlaneGeo.h:1222
std::function< bool(T const &, T const &)> Compare
Definition: fwd.h:22
void UpdatePhiZ()
Updates the stored .
Definition: PlaneGeo.cxx:733
Vector_t Direction() const
Definition: WireGeo.h:287
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
Planes that are in the vertical plane (e.g. ArgoNeuT).
Definition: geo_types.h:143
Vector_t const & GetWireDirection() const
Returns the direction of the wires.
Definition: PlaneGeo.h:390
WireCollection_t fWire
List of wires in this plane.
Definition: PlaneGeo.h:1209
std::string indent(std::size_t const i)
double fSinPhiZ
Sine of .
Definition: PlaneGeo.h:1211
WidthDepthProjection_t PointWidthDepthProjection(Point_t const &point) const
Returns the projection of the specified point on the plane.
Definition: PlaneGeo.h:897
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:67
Utilities to extend the interface of geometry vectors.This library provides facilities that can be us...
std::vector< WireGeo > WireCollection_t
Definition: PlaneGeo.h:70
WireGeo const & FirstWire() const
Return the first wire in the plane.
Definition: PlaneGeo.h:298
constexpr Vector Xaxis()
Returns a x axis vector of the specified type.
Definition: geo_vectors.h:208
void SortWires(Compare< WireGeo > cmp)
Apply sorting to WireGeo objects.
Definition: PlaneGeo.cxx:410
Point_t toPoint(Point const &p)
Convert the specified point into a geo::Point_t.
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WireCoordinateReferenceTag > WireCoordProjection_t
Type for projections in the wire base representation.
Definition: PlaneGeo.h:109
Class comparing 2D vectors.
Range_t width
Range along width direction.
Definition: SimpleGeo.h:428
void UpdateWirePitchSlow()
Updates the stored wire pitch with a slower, more robust algorithm.
Definition: PlaneGeo.cxx:890
RectSpecs fFrameSize
Definition: PlaneGeo.h:1223
constexpr auto dot(Vector const &a, OtherVector const &b)
Return cross product of two vectors.
void SetView(View_t view)
Set the signal view (for TPCGeo).
Definition: PlaneGeo.h:1128
double value
Definition: spectrum.C:18
void UpdateView()
Updates the stored view.
Definition: PlaneGeo.cxx:740
static std::string OrientationName(Orient_t orientation)
Returns the name of the specified orientation.
Definition: PlaneGeo.cxx:599
Vector rounded01(Vector const &v, Scalar tol)
Returns a vector with all components rounded if close to 0, -1 or +1.
PlaneGeo(TGeoNode const *node, TransformationMatrix &&trans, WireCollection_t &&wires)
Construct a representation of a single plane of the detector.
Definition: PlaneGeo.cxx:353
double HalfDepth() const
Definition: PlaneGeo.h:1200
Encapsulate the geometry of a wire .
ROOT::Math::DisplacementVector2D< ROOT::Math::Cartesian2D< double >, WidthDepthReferenceTag > WidthDepthProjection_t
Definition: PlaneGeo.h:128
constexpr Vector Zaxis()
Returns a z axis vector of the specified type.
Definition: geo_vectors.h:222
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:180
Range_t depth
Range along depth direction.
Definition: SimpleGeo.h:429
Tag for plane frame base vectors.
Definition: PlaneGeo.h:123
void SetOrigin(Point_t const &point)
Change the 3D point of the reference frame origin.
Definition: Decomposer.h:430
Vector_t const & SecondaryDir() const
Returns the plane secondary axis direction.
Definition: Decomposer.h:453
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:431
Data_t delta(Data_t v, Data_t margin=0.0) const
Definition: SimpleGeo.h:472
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:440
WireID ClosestWireID(WireID::WireID_t wireNo) const
Returns the closest valid wire ID to the specified wire.
Definition: PlaneGeo.h:1243
Vector3DBase_t< PlaneGeoCoordinatesTag > LocalVector_t
Type of displacement vectors in the local GDML wire plane frame.
Definition: PlaneGeo.h:97
A base class aware of world box coordinatesAn object describing a simple shape can inherit from this ...
Definition: BoxBoundedGeo.h:31
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:1258
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.
auto WirePtr(unsigned int iwire) const
Returns the wire number iwire from this plane.
Definition: PlaneGeo.h:282
constexpr bool nonNegative(Value_t value) const
Returns whether value is larger than or equal() to zero.
Vector_t const & WidthDir() const
Return the direction of plane width.
Definition: PlaneGeo.h:189
WireGeo const & LastWire() const
Return the last wire in the plane.
Definition: PlaneGeo.h:304
Float_t proj
Definition: plot.C:35
unsigned int Nwires() const
Number of wires in this plane.
Definition: PlaneGeo.h:231
bool WireIDincreasesWithZ() const
Returns whether the higher z wires have higher wire ID.
Definition: PlaneGeo.cxx:416
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:1212
Data_t upper
Ending coordinate.
Definition: SimpleGeo.h:358
Vector_t const & GetIncreasingWireDirection() const
Returns the direction of increasing wires.
Definition: PlaneGeo.h:350
Exception thrown on invalid wire number.
Definition: Exceptions.h:37
Vector_t const & GetNormalDirection() const
Returns the direction normal to the plane.
Definition: PlaneGeo.h:339
static double WirePitch(WireGeo const &w1, WireGeo const &w2)
Returns the pitch (distance on y/z plane) between two wires, in cm.
Definition: WireGeo.h:447
void swap(lar::deep_const_fwd_iterator_nested< CITER, INNERCONTEXTRACT > &a, lar::deep_const_fwd_iterator_nested< CITER, INNERCONTEXTRACT > &b)
unsigned int WireID_t
Type for the ID number.
Definition: geo_types.h:422
void UpdateWirePlaneCenter()
Updates the stored wire plane center.
Definition: PlaneGeo.cxx:928
bool shouldFlipWire(WireGeo const &wire) const
Whether the specified wire should have start and end swapped.
Definition: PlaneGeo.cxx:953
Direction
Definition: types.h:12
WireDecomposer_t fDecompWire
Definition: PlaneGeo.h:1218
void UpdateDecompWireOrigin()
Updates the position of the wire coordinate decomposition.
Definition: PlaneGeo.cxx:909
void UpdateActiveArea()
Updates the internally used active area.
Definition: PlaneGeo.cxx:916
Collection of Physical constants used in LArSoft.
Point_t MovePointOverPlane(Point_t const &point) const
Returns the point, moved so that its projection is over the plane.
Definition: PlaneGeo.cxx:475
Float_t e
Definition: plot.C:35
Data_t lower
Starting coordinate.
Definition: SimpleGeo.h:357
ROOT libraries.
Point3DBase_t< PlaneGeoCoordinatesTag > LocalPoint_t
Type of points in the local GDML wire plane frame.
Definition: PlaneGeo.h:94
PlaneID const & ID() const
Returns the identifier of this plane.
Definition: PlaneGeo.h:173
Orient_t fOrientation
Is the plane vertical or horizontal?
Definition: PlaneGeo.h:1208
void UpdateWireDir()
Updates the cached direction to wire.
Definition: PlaneGeo.cxx:880
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:229
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:312
void SetMainDir(Vector_t const &dir)
Change the main direction of the projection base.
Definition: Decomposer.h:433