Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PlanarSurfaceMask.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PlanarSurfaceMask.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 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 <algorithm>
24 #include <cmath>
25 #include <cstddef>
26 #include <memory>
27 
28 namespace {
29 
38 void checkIntersection(std::vector<Acts::Intersection2D>& intersections,
39  const Acts::Intersection2D& candidate, double sLength) {
40  if (candidate and candidate.pathLength() > 0 and
41  candidate.pathLength() < sLength) {
42  intersections.push_back(candidate);
43  }
44 }
45 
58  std::vector<Acts::Intersection2D>& intersections,
59  const ActsFatras::PlanarSurfaceMask::Segment2D& segment, bool firstInside) {
60  std::sort(intersections.begin(), intersections.end(),
62  if (intersections.size() >= 2) {
64  intersections[0].position(), intersections[1].position()};
65  } else if (intersections.size() == 1) {
66  return (not firstInside
68  .position(),
69  segment[1]}
71  segment[0], intersections[0].position()});
72  }
73  return ActsFatras::DigitizationError::MaskingError;
74 }
75 
76 } // anonymous namespace
77 
80  const Segment2D& segment) const {
81  auto surfaceType = surface.type();
82  Segment2D clipped(segment);
83 
84  // Plane surface section -------------------
85  if (surfaceType == Acts::Surface::Plane or
87  Acts::Vector2 localStart =
88  (surfaceType == Acts::Surface::Plane)
89  ? segment[0]
91  Acts::VectorHelpers::phi(segment[0]));
92 
93  Acts::Vector2 localEnd =
94  (surfaceType == Acts::Surface::Plane)
95  ? segment[1]
97  Acts::VectorHelpers::phi(segment[1]));
98 
99  bool startInside = surface.bounds().inside(localStart, true);
100  bool endInside = surface.bounds().inside(localEnd, true);
101 
102  // Fast exit, both inside
103  if (startInside and endInside) {
104  return segment;
105  }
106 
107  // It's either planar or disc trapezoid bounds
108  const Acts::PlanarBounds* planarBounds = nullptr;
109  const Acts::DiscTrapezoidBounds* dtbBounds = nullptr;
110  if (surfaceType == Acts::Surface::Plane) {
111  planarBounds =
112  static_cast<const Acts::PlanarBounds*>(&(surface.bounds()));
113  if (planarBounds->type() == Acts::SurfaceBounds::eEllipse) {
114  return DigitizationError::UndefinedSurface;
115  }
116  } else {
117  dtbBounds =
118  static_cast<const Acts::DiscTrapezoidBounds*>(&(surface.bounds()));
119  }
120  auto vertices = planarBounds != nullptr ? planarBounds->vertices(1)
121  : dtbBounds->vertices(1);
122 
123  return polygonMask(vertices, segment, startInside);
124 
125  } else if (surfaceType == Acts::Surface::Disc) {
126  // Polar coordinates
127  Acts::Vector2 sPolar(Acts::VectorHelpers::perp(segment[0]),
128  Acts::VectorHelpers::phi(segment[0]));
129  Acts::Vector2 ePolar(Acts::VectorHelpers::perp(segment[1]),
130  Acts::VectorHelpers::phi(segment[1]));
131 
132  bool startInside = surface.bounds().inside(sPolar, true);
133  bool endInside = surface.bounds().inside(ePolar, true);
134 
135  // Fast exit for both inside
136  if (startInside and endInside) {
137  return segment;
138  }
139 
140  auto boundsType = surface.bounds().type();
141  if (boundsType == Acts::SurfaceBounds::eDisc) {
142  auto rBounds =
143  static_cast<const Acts::RadialBounds*>(&(surface.bounds()));
144  return radialMask(*rBounds, segment, {sPolar, ePolar}, startInside);
145 
146  } else if (boundsType == Acts::SurfaceBounds::eAnnulus) {
147  auto aBounds =
148  static_cast<const Acts::AnnulusBounds*>(&(surface.bounds()));
149  return annulusMask(*aBounds, segment, startInside);
150  }
151  }
152  return DigitizationError::UndefinedSurface;
153 }
154 
157  const std::vector<Acts::Vector2>& vertices, const Segment2D& segment,
158  bool firstInside) const {
159  std::vector<Acts::Intersection2D> intersections;
160  Acts::Vector2 sVector(segment[1] - segment[0]);
161  Acts::Vector2 sDir = sVector.normalized();
162  double sLength = sVector.norm();
163 
164  for (size_t iv = 0; iv < vertices.size(); ++iv) {
165  const Acts::Vector2& s0 = vertices[iv];
166  const Acts::Vector2& s1 =
167  (iv + 1) < vertices.size() ? vertices[iv + 1] : vertices[0];
169  intersections,
170  intersector.intersectSegment(s0, s1, segment[0], sDir, true), sLength);
171  }
172  return maskAndReturn(intersections, segment, firstInside);
173 }
174 
177  const Segment2D& segment,
178  const Segment2D& polarSegment,
179  bool firstInside) const {
180  double rMin = rBounds.get(Acts::RadialBounds::eMinR);
181  double rMax = rBounds.get(Acts::RadialBounds::eMaxR);
182  double hPhi = rBounds.get(Acts::RadialBounds::eHalfPhiSector);
183  double aPhi = rBounds.get(Acts::RadialBounds::eAveragePhi);
184 
185  std::array<double, 2> radii = {rMin, rMax};
186  std::array<double, 2> phii = {aPhi - hPhi, aPhi + hPhi};
187 
188  std::vector<Acts::Intersection2D> intersections;
189  Acts::Vector2 sVector(segment[1] - segment[0]);
190  Acts::Vector2 sDir = sVector.normalized();
191  double sLength = sVector.norm();
192 
193  double sR = polarSegment[0][Acts::eBoundLoc0];
194  double eR = polarSegment[1][Acts::eBoundLoc0];
195  double sPhi = polarSegment[0][Acts::eBoundLoc1];
196  double ePhi = polarSegment[1][Acts::eBoundLoc1];
197 
198  // Helper method to intersect phi boundaries
199  auto intersectPhiLine = [&](double phi) -> void {
200  Acts::Vector2 s0(rMin * std::cos(phi), rMin * std::sin(phi));
201  Acts::Vector2 s1(rMax * std::cos(phi), rMax * std::sin(phi));
203  intersections,
204  intersector.intersectSegment(s0, s1, segment[0], sDir, true), sLength);
205  };
206 
207  // Helper method to intersect radial full boundaries
208  auto intersectCircle = [&](double r) -> void {
209  auto cIntersections = intersector.intersectCircle(r, segment[0], sDir);
210  for (const auto& intersection : cIntersections) {
211  checkIntersection(intersections, intersection, sLength);
212  }
213  };
214 
215  // Intersect phi lines
216  if ((M_PI - hPhi) > Acts::s_epsilon) {
217  if (sPhi < phii[0] or ePhi < phii[0]) {
218  intersectPhiLine(phii[0]);
219  }
220  if (sPhi > phii[1] or ePhi > phii[1]) {
221  intersectPhiLine(phii[1]);
222  }
223  // Intersect radial segments
224  if (sR < radii[0] or eR < radii[0]) {
225  checkIntersection(intersections,
226  intersector.intersectCircleSegment(
227  radii[0], phii[0], phii[1], segment[0], sDir),
228  sLength);
229  }
230  if (sR > radii[1] or eR > radii[1]) {
231  checkIntersection(intersections,
232  intersector.intersectCircleSegment(
233  radii[1], phii[0], phii[1], segment[0], sDir),
234  sLength);
235  }
236  } else {
237  // Full radial set
238  // Intersect radial segments
239  if (sR < radii[0] or eR < radii[0]) {
240  intersectCircle(radii[0]);
241  }
242  if (sR > radii[1] or eR > radii[1]) {
243  intersectCircle(radii[1]);
244  }
245  }
246  return maskAndReturn(intersections, segment, firstInside);
247 }
248 
251  const Segment2D& segment,
252  bool firstInside) const {
253  auto vertices = aBounds.vertices(0);
254  Acts::Vector2 moduleOrigin = aBounds.moduleOrigin();
255 
256  std::array<std::array<unsigned int, 2>, 2> edgeCombos = {
257  std::array<unsigned int, 2>{0, 3}, std::array<unsigned int, 2>{1, 2}};
258 
259  std::vector<Acts::Intersection2D> intersections;
260  Acts::Vector2 sVector(segment[1] - segment[0]);
261  Acts::Vector2 sDir = sVector.normalized();
262  double sLength = sVector.norm();
263  // First the phi edges in strip system
264  for (const auto& ec : edgeCombos) {
266  intersections,
267  intersector.intersectSegment(vertices[ec[0]], vertices[ec[1]],
268  segment[0], sDir, true),
269  sLength);
270  }
271 
272  // Shift them to get the module phi and intersect
273  std::array<unsigned int, 4> phii = {1, 0, 2, 3};
274  for (unsigned int iarc = 0; iarc < 2; ++iarc) {
275  Acts::Intersection2D intersection = intersector.intersectCircleSegment(
276  aBounds.get(static_cast<Acts::AnnulusBounds::BoundValues>(iarc)),
277  Acts::VectorHelpers::phi(vertices[phii[iarc * 2]] - moduleOrigin),
278  Acts::VectorHelpers::phi(vertices[phii[iarc * 2 + 1]] - moduleOrigin),
279  segment[0] - moduleOrigin, sDir);
280  if (intersection) {
281  checkIntersection(intersections,
283  intersection.position() + moduleOrigin,
284  intersection.pathLength(), intersection.status()),
285  sLength);
286  }
287  }
288  return maskAndReturn(intersections, segment, firstInside);
289 }