Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PlaneSurface.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PlaneSurface.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2020 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
22 
23 #include <cmath>
24 #include <stdexcept>
25 #include <utility>
26 #include <vector>
27 
29  : GeometryObject(), Surface(other), m_bounds(other.m_bounds) {}
30 
32  const PlaneSurface& other,
33  const Transform3& transform)
34  : GeometryObject(),
35  Surface(gctx, other, transform),
36  m_bounds(other.m_bounds) {}
37 
38 Acts::PlaneSurface::PlaneSurface(const Vector3& center, const Vector3& normal)
39  : Surface(), m_bounds(nullptr) {
44  Vector3 T = normal.normalized();
45  Vector3 U = std::abs(T.dot(Vector3::UnitZ())) < s_curvilinearProjTolerance
46  ? Vector3::UnitZ().cross(T).normalized()
47  : Vector3::UnitX().cross(T).normalized();
48  Vector3 V = T.cross(U);
49  RotationMatrix3 curvilinearRotation;
50  curvilinearRotation.col(0) = U;
51  curvilinearRotation.col(1) = V;
52  curvilinearRotation.col(2) = T;
53 
54  // curvilinear surfaces are boundless
55  m_transform = Transform3{curvilinearRotation};
56  m_transform.pretranslate(center);
57 }
58 
59 Acts::PlaneSurface::PlaneSurface(std::shared_ptr<const PlanarBounds> pbounds,
60  const Acts::DetectorElementBase& detelement)
61  : Surface(detelement), m_bounds(std::move(pbounds)) {
63  throw_assert(m_bounds, "PlaneBounds must not be nullptr");
64 }
65 
67  std::shared_ptr<const PlanarBounds> pbounds)
68  : Surface(transform), m_bounds(std::move(pbounds)) {}
69 
71  if (this != &other) {
72  Surface::operator=(other);
73  m_bounds = other.m_bounds;
74  }
75  return *this;
76 }
77 
79  return Surface::Plane;
80 }
81 
83  const GeometryContext& gctx, const Vector2& lposition,
84  const Vector3& /*direction*/) const {
85  return transform(gctx) *
86  Vector3(lposition[Acts::eBoundLoc0], lposition[Acts::eBoundLoc1], 0.);
87 }
88 
90  const GeometryContext& gctx, const Vector3& position,
91  const Vector3& /*direction*/, double tolerance) const {
92  Vector3 loc3Dframe = transform(gctx).inverse() * position;
93  if (std::abs(loc3Dframe.z()) > std::abs(tolerance)) {
94  return Result<Vector2>::failure(SurfaceError::GlobalPositionNotOnSurface);
95  }
96  return Result<Vector2>::success({loc3Dframe.x(), loc3Dframe.y()});
97 }
98 
100  return "Acts::PlaneSurface";
101 }
102 
104  if (m_bounds) {
105  return (*m_bounds.get());
106  }
107  return s_noBounds;
108 }
109 
111  const GeometryContext& gctx, size_t lseg) const {
112  // Prepare vertices and faces
113  std::vector<Vector3> vertices;
114  std::vector<Polyhedron::FaceType> faces;
115  std::vector<Polyhedron::FaceType> triangularMesh;
116  bool exactPolyhedron = true;
117 
118  // If you have bounds you can create a polyhedron representation
119  if (m_bounds) {
120  auto vertices2D = m_bounds->vertices(lseg);
121  vertices.reserve(vertices2D.size() + 1);
122  for (const auto& v2D : vertices2D) {
123  vertices.push_back(transform(gctx) * Vector3(v2D.x(), v2D.y(), 0.));
124  }
125  bool isEllipse = bounds().type() == SurfaceBounds::eEllipse;
126  bool innerExists = false, coversFull = false;
127  if (isEllipse) {
128  exactPolyhedron = false;
129  auto vStore = bounds().values();
130  innerExists = vStore[EllipseBounds::eInnerRx] > s_epsilon and
132  coversFull =
133  std::abs(vStore[EllipseBounds::eHalfPhiSector] - M_PI) < s_epsilon;
134  }
135  // All of those can be described as convex
136  // @todo same as for Discs: coversFull is not the right criterium
137  // for triangulation
138  if (not isEllipse or not innerExists or not coversFull) {
139  auto facesMesh = detail::FacesHelper::convexFaceMesh(vertices);
140  faces = facesMesh.first;
141  triangularMesh = facesMesh.second;
142  } else {
143  // Two concentric rings, we use the pure concentric method momentarily,
144  // but that creates too many unneccesarry faces, when only two
145  // are needed to describe the mesh, @todo investigate merging flag
146  auto facesMesh = detail::FacesHelper::cylindricalFaceMesh(vertices, true);
147  faces = facesMesh.first;
148  triangularMesh = facesMesh.second;
149  }
150  } else {
151  throw std::domain_error(
152  "Polyhedron repr of boundless surface not possible.");
153  }
154  return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron);
155 }
156 
158  const Vector2& /*lpos*/) const {
159  // fast access via transform matrix (and not rotation())
160  const auto& tMatrix = transform(gctx).matrix();
161  return Vector3(tMatrix(0, 2), tMatrix(1, 2), tMatrix(2, 2));
162 }
163 
165  const GeometryContext& gctx, BinningValue /*bValue*/) const {
166  return center(gctx);
167 }
168 
170  const Vector3& position,
171  const Vector3& direction) const {
172  // We can ignore the global position here
173  return 1. / std::abs(Surface::normal(gctx, position).dot(direction));
174 }
175 
177  const GeometryContext& gctx, const Vector3& position,
178  const Vector3& direction, const BoundaryCheck& bcheck,
179  ActsScalar tolerance) const {
180  // Get the contextual transform
181  const auto& gctxTransform = transform(gctx);
182  // Use the intersection helper for planar surfaces
183  auto intersection =
184  PlanarHelper::intersect(gctxTransform, position, direction, tolerance);
185  auto status = intersection.status();
186  // Evaluate boundary check if requested (and reachable)
187  if (intersection.status() != Intersection3D::Status::unreachable and bcheck) {
188  // Built-in local to global for speed reasons
189  const auto& tMatrix = gctxTransform.matrix();
190  // Create the reference vector in local
191  const Vector3 vecLocal(intersection.position() - tMatrix.block<3, 1>(0, 3));
192  if (not insideBounds(tMatrix.block<3, 2>(0, 0).transpose() * vecLocal,
193  bcheck)) {
194  status = Intersection3D::Status::missed;
195  }
196  }
197  return {{Intersection3D(intersection.position(), intersection.pathLength(),
198  status),
200  this};
201 }
202 
204  const GeometryContext& /*gctx*/, const Vector3& /*position*/) const {
205  const ActsMatrix<2, 3> loc3DToLocBound = ActsMatrix<2, 3>::Identity();
206  return loc3DToLocBound;
207 }