ATLAS Offline Software
Loading...
Searching...
No Matches
SimplePolygonBrepVolumeBounds.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6// SimplePolygonBrepVolumeBounds.cxx, (c) ATLAS Detector software
8
9// Trk
14#include "TrkVolumes/Volume.h"
16// TrkSurfaces
20// Gaudi
21#include "GaudiKernel/MsgStream.h"
22#include "GaudiKernel/SystemOfUnits.h"
23// STD
24#include <cmath>
25#include <iomanip>
26#include <iostream>
27
29 : VolumeBounds()
30 , m_halfX(0.)
31 , m_halfY(0.)
32 , m_halfZ(0.)
33 , m_ordering(-1)
34 , m_combinedVolume(nullptr)
35 , m_envelope(nullptr)
37{
38 //@TODO an object created by the default constructor cannot be copied or
39 //assigned.
40}
41
43 const std::vector<std::pair<float, float>>& xyVtx,
44 float halez)
45 : VolumeBounds()
46 , m_halfX(0.)
47 , m_halfY(0.)
48 , m_halfZ(halez)
49 , m_ordering(-1)
50 , m_combinedVolume(nullptr)
51 , m_envelope(nullptr)
53{
54 m_xyVtx.resize(xyVtx.size());
55 double xmin = xyVtx[0].first;
56 double xmax = xmin;
57 double ymin = xyVtx[0].second;
58 double ymax = ymin;
59 for (unsigned int i = 0; i < xyVtx.size(); i++) {
60 m_xyVtx[i] = xyVtx[i];
61 if (xyVtx[i].first < xmin)
62 xmin = xyVtx[i].first;
63 if (xyVtx[i].first > xmax)
64 xmax = xyVtx[i].first;
65 if (xyVtx[i].second < ymin)
66 ymin = xyVtx[i].second;
67 if (xyVtx[i].second > ymax)
68 ymax = xyVtx[i].second;
69 }
70 double ehalfX = 0.5 * (xmax - xmin);
71 double ehalfY = 0.5 * (ymax - ymin);
72 m_halfX = fmax(std::abs(xmax), fabs(xmin));
73 m_halfY = fmax(std::abs(ymax), fabs(ymin));
74 Amg::Transform3D transXY(
75 Amg::Translation3D(Amg::Vector3D(0.5 * (xmin + xmax), 0., 0.)) *
76 Amg::Translation3D(Amg::Vector3D(0., 0.5 * (ymin + ymax), 0.)));
78 std::make_unique<Amg::Transform3D>(transXY),
79 std::make_shared<Trk::CuboidVolumeBounds>(ehalfX, ehalfY, m_halfZ));
80
82}
83
85 const std::vector<std::pair<double, double>>& xyVtx,
86 double halez)
87 : VolumeBounds()
88 , m_halfX(0.)
89 , m_halfY(0.)
90 , m_halfZ(halez)
91 , m_ordering(-1)
92 , m_combinedVolume(nullptr)
93 , m_envelope(nullptr)
95{
96 m_xyVtx.resize(xyVtx.size());
97 double xmin = xyVtx[0].first;
98 double xmax = xmin;
99 double ymin = xyVtx[0].second;
100 double ymax = ymin;
101 for (unsigned int i = 0; i < xyVtx.size(); i++) {
102 m_xyVtx[i] = xyVtx[i];
103 if (xyVtx[i].first < xmin)
104 xmin = xyVtx[i].first;
105 if (xyVtx[i].first > xmax)
106 xmax = xyVtx[i].first;
107 if (xyVtx[i].second < ymin)
108 ymin = xyVtx[i].second;
109 if (xyVtx[i].second > ymax)
110 ymax = xyVtx[i].second;
111 }
112 double ehalfX = 0.5 * (xmax - xmin);
113 double ehalfY = 0.5 * (ymax - ymin);
114 m_halfX = fmax(std::abs(xmax), fabs(xmin));
115 m_halfY = fmax(std::abs(ymax), fabs(ymin));
116 Amg::Transform3D transXY(
117 Amg::Translation3D(Amg::Vector3D(0.5 * (xmin + xmax), 0., 0.)) *
118 Amg::Translation3D(Amg::Vector3D(0., 0.5 * (ymin + ymax), 0.)));
120 std::make_unique<Amg::Transform3D>(transXY),
121 std::make_shared<Trk::CuboidVolumeBounds>(ehalfX, ehalfY, m_halfZ));
122
124}
125
128 : VolumeBounds()
129 , m_halfX(trabo.m_halfX)
130 , m_halfY(trabo.m_halfY)
131 , m_halfZ(trabo.m_halfZ)
132 , m_ordering(trabo.m_ordering)
134 , m_envelope(trabo.m_envelope->clone())
136{
137 m_xyVtx.resize(trabo.m_xyVtx.size());
138 for (unsigned int i = 0; i < m_xyVtx.size(); i++)
139 m_xyVtx[i] = trabo.m_xyVtx[i];
140}
141
147
151{
152 if (this != &trabo) {
153 m_halfX = trabo.m_halfX;
154 m_halfY = trabo.m_halfY;
155 m_halfZ = trabo.m_halfZ;
157 m_xyVtx.resize(trabo.m_xyVtx.size());
158 for (unsigned int i = 0; i < m_xyVtx.size(); i++)
159 m_xyVtx[i] = trabo.m_xyVtx[i];
160 delete m_combinedVolume;
161 delete m_envelope;
163 m_envelope = trabo.m_envelope->clone();
164 m_ordering = trabo.m_ordering;
165 }
166 return *this;
167}
168
169std::vector<std::unique_ptr<Trk::Surface>>
171 (const Amg::Transform3D& transform)
172{
173 auto retsf = std::vector<std::unique_ptr<Trk::Surface>>();
174
175 // face surfaces xy
176 // (1) - at negative local z
177 Trk::PlaneSurface xymPlane(
178 Amg::Transform3D(transform *
180 std::make_shared<Trk::RectangleBounds>(m_halfX, m_halfY));
181 auto volExcl =
182 std::make_shared<const Trk::VolumeExcluder>(
183 std::make_unique<Trk::Volume>(
186 )
187 );
188
189 retsf.push_back(std::make_unique<Trk::SubtractedPlaneSurface>(xymPlane, std::move(volExcl), true));
190 // (2) - at positive local z
191 Trk::PlaneSurface xyPlane(
193 std::make_shared<Trk::RectangleBounds>(m_halfX, m_halfY)
194 );
195
196 volExcl = std::make_shared<const Trk::VolumeExcluder>(
197 std::make_unique<Trk::Volume>(*m_combinedVolume,
199 )
200 );
201 retsf.push_back(std::make_unique<Trk::SubtractedPlaneSurface>(xyPlane, std::move(volExcl), true));
202 // loop over xy vertices
203 // (3)
204 for (unsigned int iv = 0; iv < m_xyVtx.size(); iv++) {
205 if (iv != m_xyVtx.size() - 1)
206 retsf.push_back(sideSurf(transform, iv, iv + 1));
207 else
208 retsf.push_back(sideSurf(transform, iv, 0));
209 }
210
211 return retsf;
212}
213
214// faces in xy
215std::unique_ptr<Trk::PlaneSurface>
217 const Amg::Transform3D& transform,
218 unsigned int iv1,
219 unsigned int iv2) const
220{
221 std::unique_ptr<Trk::PlaneSurface> plane = nullptr;
222
223 double xdif = m_xyVtx[iv2].first - m_xyVtx[iv1].first;
224 double ydif = m_xyVtx[iv2].second - m_xyVtx[iv1].second;
225 double xsize = sqrt(xdif * xdif + ydif * ydif);
226
227 double ori = m_ordering > 0 ? -1. : 1.;
228
229 Amg::Vector3D pos(
230 0.5 * (m_xyVtx[iv1].first + m_xyVtx[iv2].first),
231 0.5 * (m_xyVtx[iv1].second + m_xyVtx[iv2].second),
232 0.);
233 double phi = ori * ydif < 0 ? M_PI / 2 : -M_PI / 2;
234 if (ori > 0 && ydif > 0)
235 phi = M_PI / 2;
236 if (std::abs(xdif) > 1e-6) {
237 phi = std::atan(ydif / xdif);
238 if (xdif < 0)
239 phi += M_PI;
240 }
241
243 transform * Amg::Translation3D(pos) *
244 Amg::AngleAxis3D(phi, Amg::Vector3D(0., 0., 1.)) *
245 Amg::AngleAxis3D(-ori * 90 * Gaudi::Units::deg, Amg::Vector3D(1., 0., 0.)));
246 plane = std::make_unique<Trk::PlaneSurface>(tr, std::make_shared<Trk::RectangleBounds>(0.5 * xsize, m_halfZ));
247
248 // verify position of vertices - uncomment for debugging
249 // if
250 // (!plane->isOnSurface(Trk::GlobalPosition(m_xyVtx[iv1].first,m_xyVtx[iv1].second,m_halfZ),true,0.001,0.001)
251 // ||
252 // !plane->isOnSurface(Trk::GlobalPosition(m_xyVtx[iv2].first,m_xyVtx[iv2].second,-m_halfZ),true,0.001,0.001)
253 // )
254 // std::cout << "ERROR in SIMPLEPGONBREP side boundary:vertices out of
255 // plane"<< std::endl;
256
257 return plane;
258}
259
260bool
262 const
263{
264 return (m_combinedVolume->inside(pos, tol));
265}
266
267void
269{
270 // translate into prisms (triangulate)
271 std::unique_ptr<Trk::Volume> cVol;
272 std::vector<std::pair<double, double>> triangles = TriangulatePolygonCheck(m_xyVtx);
273 std::vector<std::pair<double, double>> vertices;
274 for (unsigned int i = 0; i < triangles.size(); i = i + 3) {
275 vertices.push_back(triangles[i]);
276 vertices.push_back(triangles[i + 1]);
277 vertices.push_back(triangles[i + 2]);
278 auto newVol = std::make_unique<Trk::Volume>(nullptr, std::make_shared<Trk::PrismVolumeBounds>(vertices, m_halfZ));
279 if (cVol){
280 cVol = std::make_unique<Trk::Volume>(nullptr, std::make_shared<Trk::CombinedVolumeBounds>(std::move(cVol),
281 std::move(newVol),
282 false));
283 }
284 else{
285 cVol = std::move(newVol);
286 }
287 vertices.clear();
288 }
289 m_combinedVolume = cVol.release();
290}
291
292// ostream operator overload
293MsgStream&
295{
296 std::stringstream temp_sl;
297 temp_sl << std::setiosflags(std::ios::fixed);
298 temp_sl << std::setprecision(7);
299 temp_sl << "Trk::SimplePolygonBrepVolumeBounds: (halfZ, xy vertices) = ";
300 temp_sl << "( " << m_halfZ << ")";
301 for (const auto & xyVtx : m_xyVtx)
302 temp_sl << "(" << xyVtx.first << "," << xyVtx.second << ")";
303 sl << temp_sl.str();
304 return sl;
305}
306
307std::ostream&
309{
310 std::stringstream temp_sl;
311 temp_sl << std::setiosflags(std::ios::fixed);
312 temp_sl << std::setprecision(7);
313 temp_sl << "Trk::SimplePolygonBrepVolumeBounds: (halfZ, xy vertices) = ";
314 temp_sl << "( " << m_halfZ << ")";
315 for (const auto & myVtx : m_xyVtx)
316 temp_sl << "(" << myVtx.first << "," << myVtx.second << ")";
317 sl << temp_sl.str();
318 return sl;
319}
320
322// Triangulate Polygon
323// M. Wolter
325
326bool
328// XOR: Arguments are negated to ensure that they are 0/1. Then the bitwise Xor
329// operator may apply.
330{
331 return !x ^ !y;
332}
333
334#ifdef TRKDETDESCR_USEFLOATPRECISON
335#define double float
336#endif
337
338bool
340 std::pair<double, double> a,
341 std::pair<double, double> b,
342 std::pair<double, double> c) const
343// Returns true iff c is strictly to the left of the directed line through a to
344// b.
345{
346 double CrossZ = (b.first - a.first) * (c.second - a.second) -
347 (c.first - a.first) * (b.second - a.second);
348 if (m_ordering == 1)
349 return (CrossZ >= 0.);
350 if (m_ordering == 0)
351 return (CrossZ < 0.);
352 return false;
353}
354
355bool
357 std::pair<double, double> a,
358 std::pair<double, double> b,
359 std::pair<double, double> c,
360 std::pair<double, double> d) const
361// Returns true iff segments ab and cd intersect
362{
363
364 return Xor(Left(a, b, c), Left(a, b, d)) && Xor(Left(c, d, a), Left(c, d, b));
365}
366
367bool
369 int i,
370 int j,
371 const std::vector<std::pair<double, double>>& inputVertices) const
372// Returns true iff the diagonal (i,j) is internal to the polygon in
373// the neighborhood of the i endpoint.
374{
375 int iPlus1 = (i + 1) % inputVertices.size();
376 int iMinus1 = (i + inputVertices.size() - 1) % inputVertices.size();
377
378 /* If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. */
379 if (Left(inputVertices[iMinus1], inputVertices[i], inputVertices[iPlus1]))
380 return Left(inputVertices[i], inputVertices[j], inputVertices[iMinus1]) &&
381 Left(inputVertices[j], inputVertices[i], inputVertices[iPlus1]);
382
383 /* Assume (i-1,i,i+1) not collinear. */
384 /* else v_i is reflex. */
385 else
386 return !(
387 Left(inputVertices[i], inputVertices[j], inputVertices[iPlus1]) &&
388 Left(inputVertices[j], inputVertices[i], inputVertices[iMinus1]));
389}
390
391bool
393 int i,
394 int j,
395 const std::vector<std::pair<double, double>>& inputVertices) const
396{
397 // Returns TRUE iff (v_i, v_j) is a proper internal *or* external diagonal of
398 // this polygon, *ignoring edges incident to v_i and v_j*.
399
400 /* For each edge (k,k+1) of P */
401 for (int k = 0; k < (int)inputVertices.size(); k++) {
402
403 int kPlus1 = (k + 1) % inputVertices.size();
404
405 /* Skip edges incident to i or j */
406 if ((k != i) && (kPlus1 != i) && (k != j) && (kPlus1 != j))
407 if (Intersect(
408 inputVertices[i],
409 inputVertices[j],
410 inputVertices[k],
411 inputVertices[kPlus1]))
412 return false;
413 }
414 return true;
415}
416
417bool
419 int i,
420 int j,
421 const std::vector<std::pair<double, double>>& inputVertices) const
422// Returns TRUE iff (v_i, v_j) is a proper internal diagonal of P.
423{
424 // std::cout<<"MW Diagonal "<<i<<" "<<j<<" "<<InCone(i,j, inputVertices)<<"
425 // "<<Diagonalie(i,j, inputVertices)<<std::endl;
426 return InCone(i, j, inputVertices) && Diagonalie(i, j, inputVertices);
427}
428
429std::vector<std::pair<double, double>>
431 const std::vector<std::pair<double, double>>& Vertices) const
432{
433 // Subtracting ears method
434 //
435 // One way to triangulate a simple polygon is by using the assertion that any
436 // simple polygon without holes
437 // has at least two so called 'ears'. An ear is a triangle with two sides on
438 // the edge of the polygon and the other one completely inside it. The
439 // algorithm then consists of finding such an ear, removing it from the
440 // polygon (which results in a new polygon that still meets the conditions)
441 // and repeating until there is only one triangle left.
442 //
443
444 int NSize = Vertices.size();
445 std::vector<std::pair<double, double>> outTriangles;
446 std::vector<std::pair<double, double>> inputVertices;
447 inputVertices.reserve(NSize);
448 for (int i = 0; i < NSize; i++)
449 inputVertices.push_back((Vertices)[i]);
450
451 // for (int i; i<NSize;i++) std::cout<<"MW input vertices:
452 // "<<inputVertices[i].first<<" "<<inputVertices[i].second<<std::endl;
453 // Triangulates this polygon and saves triangle edges in TriPoly.
454 // Triangles are stored CCW, with each set of 3 consecutive points in TriPoly
455 // representing 1 triangle.
456 // Assumes this polygon is closed.
457
458 if (NSize < 4)
459 return inputVertices;
460
461 // Start triangulating
462 int VerticesLeft = NSize;
463 while (VerticesLeft > 3) {
464 // std::cout<<"MW vertices left "<<VerticesLeft<<std::endl;
465 bool bCornerCut = false;
466 for (int i = 0; i < VerticesLeft; i++) {
467
468 int iPlus1 = i + 1;
469 if (iPlus1 == VerticesLeft)
470 iPlus1 = 0;
471 int iPlus2 = (iPlus1 + 1);
472 if (iPlus2 == VerticesLeft)
473 iPlus2 = 0;
474
475 if (Diagonal(i, iPlus2, inputVertices)) {
476
477 outTriangles.push_back(inputVertices[i]);
478 outTriangles.push_back(inputVertices[iPlus1]);
479 outTriangles.push_back(inputVertices[iPlus2]);
480
481 inputVertices.erase(inputVertices.begin() + iPlus1);
482 VerticesLeft--;
483 bCornerCut = true;
484 break;
485 }
486 }
487 if (!bCornerCut) { // Error - bad poly
488 // std::cout<<"MW Error - bad poly"<<std::endl;
489 std::vector<std::pair<double, double>> out;
490 return out;
491 }
492 }
493
494 if (VerticesLeft == 3) {
495 outTriangles.push_back(inputVertices[0]);
496 outTriangles.push_back(inputVertices[1]);
497 outTriangles.push_back(inputVertices[2]);
498 inputVertices.erase(inputVertices.begin() + 1);
499 VerticesLeft--;
500 }
501
502 return outTriangles;
503}
504
505std::vector<std::pair<double, double>>
507 const std::vector<std::pair<double, double>>& Vertices)
508{
509 // Perform triangulation. Check the orientation of the verices in the polygon
510 // m_ordering = -1 not set
511 // m_ordering = 1 anticlockwise
512 // m_ordering = 0 clockwise
513
514 if (m_ordering == -1)
515 m_ordering = 1;
516 std::vector<std::pair<double, double>> outTriangles =
517 TriangulatePolygon(Vertices);
518 if (outTriangles.empty()) {
519 m_ordering = -m_ordering + 1;
520 outTriangles = TriangulatePolygon(Vertices);
521 }
522
523 return outTriangles;
524}
525#ifdef TRKDETDESCR_USEFLOATPRECISON
526#undef double
527#endif
528
#define M_PI
static Double_t a
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
Bounds for the exact transcript of the GeoSimplePolygonBrep; volume defined by combination of symm....
double m_halfX
halflength in x - to define enclosing rectangle
int m_ordering
-1 not set/ 1 anticlockwise / 0 clockwise
SimplePolygonBrepVolumeBounds * clone() const override final
Virtual constructor.
std::vector< std::pair< double, double > > TriangulatePolygon(const std::vector< std::pair< double, double > > &Vertices) const
std::unique_ptr< Trk::PlaneSurface > sideSurf(const Amg::Transform3D &, unsigned int, unsigned int) const
virtual std::vector< std::unique_ptr< Trk::Surface > > decomposeToSurfaces(const Amg::Transform3D &transform) override final
Method to decompose the Bounds into Surfaces.
MsgStream & dump(MsgStream &sl) const override
Output Method for MsgStream.
bool Diagonalie(int i, int j, const std::vector< std::pair< double, double > > &inputVertices) const
bool Diagonal(int i, int j, const std::vector< std::pair< double, double > > &inputVertices) const
bool Left(std::pair< double, double > a, std::pair< double, double > b, std::pair< double, double > c) const
Trk::EightObjectsAccessor m_objectAccessor
There's only one single object Acessor for the moment has to be implemented if Cuboids are used more ...
const Trk::Volume * m_envelope
simplified envelope
const Trk::Volume * m_combinedVolume
triangulated polygon
bool inside(const Amg::Vector3D &, double tol=0.) const override final
This method checks if position in the 3D volume frame is inside the volume.
std::vector< std::pair< double, double > > TriangulatePolygonCheck(const std::vector< std::pair< double, double > > &Vertices)
double m_halfY
halflength in y - to define enclosing rectangle
std::vector< std::pair< double, double > > m_xyVtx
generating xy vertices
SimplePolygonBrepVolumeBounds & operator=(const SimplePolygonBrepVolumeBounds &bobo)
Assignment operator.
bool InCone(int i, int j, const std::vector< std::pair< double, double > > &inputVertices) const
bool Intersect(std::pair< double, double > a, std::pair< double, double > b, std::pair< double, double > c, std::pair< double, double > d) const
VolumeBounds()
Default Constructor.
Base class for all volumes inside the tracking realm, it defines the interface for inherited Volume c...
Definition Volume.h:36
virtual Volume * clone() const
polymorpic deep copy
Definition Volume.cxx:60
double xmax
Definition listroot.cxx:61
double ymin
Definition listroot.cxx:63
double xmin
Definition listroot.cxx:60
double ymax
Definition listroot.cxx:64
Eigen::AngleAxisd AngleAxis3D
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
Eigen::Translation< double, 3 > Translation3D
@ x
Definition ParamDefs.h:55
@ y
Definition ParamDefs.h:56
@ phi
Definition ParamDefs.h:75