25#include "G4GenericTrap.hh"
26#include "G4MultiUnion.hh"
27#include "G4QuadrangularFacet.hh"
28#include "G4ReflectedSolid.hh"
29#include "G4TessellatedSolid.hh"
30#include "G4TriangularFacet.hh"
36const int Geant4GM::Arb8::fgkNofVertices = 8;
37const double Geant4GM::Arb8::fgkTolerance = 1E-3;
39const double Geant4GM::Arb8::fgkMaxTwistAngle = 90.;
42double Geant4GM::Arb8::TwistAngleOfFace(
43 const std::vector<VGM::TwoVector>& vertices,
int index)
50 int nv = fgkNofVertices / 2;
52 int j = (index + 1) % nv;
54 double dx1 = vertices[j].first - vertices[i].first;
55 double dy1 = vertices[j].second - vertices[i].second;
56 double dx2 = vertices[nv + j].first - vertices[nv + i].first;
57 double dy2 = vertices[nv + j].second - vertices[nv + i].second;
59 if ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0))
return 0.;
61 return atan2(dx1 * dy2 - dy1 * dx2, dx1 * dx2 + dy1 * dy2);
66 const std::vector<VGM::TwoVector>& vertices)
73 for (
int i = 0; i < 4; i++) {
74 double angle = fabs(TwistAngleOfFace(vertices, i)) * 180. /
M_PI;
75 if (angle > maxAngle) maxAngle = angle;
88 double dx1, dy1, dx2, dy2;
89 int nv = fgkNofVertices / 2;
90 for (
int i = 0; i < 4; i++) {
92 dx1 = vertices[(i + 1) % nv].first - vertices[i].first;
93 dy1 = vertices[(i + 1) % nv].second - vertices[i].second;
94 if (dx1 == 0 && dy1 == 0)
continue;
96 dx2 = vertices[nv + (i + 1) % nv].first - vertices[nv + i].first;
97 dy2 = vertices[nv + (i + 1) % nv].second - vertices[nv + i].second;
98 if (dx2 == 0 && dy2 == 0)
continue;
100 if (fabs(dy1 * dx2 - dx1 * dy2) < fgkTolerance)
continue;
109 const std::string& name,
double hz, std::vector<VGM::TwoVector> vertices)
115 fTessellatedSolid(0),
139 auto faceSpan = [&vertices](G4int first) {
141 for (G4int i = first + 1; i < first + 4; ++i) {
142 for (G4int j = first; j < i; ++j) {
143 double dx = vertices[i].first - vertices[j].first;
144 double dy = vertices[i].second - vertices[j].second;
145 span = std::max(span, std::sqrt(dx * dx + dy * dy));
150 double downSpan = faceSpan(0);
151 double upSpan = faceSpan(4);
152 bool hasCollapsedFace =
153 std::min(downSpan, upSpan) < 1.e-7 * std::max(downSpan, upSpan);
158 if (
IsTwisted(vertices) || hasCollapsedFace) {
159 auto makeGenericTrap = [&name](
const std::string& suffix,
double halfLength,
160 const std::vector<VGM::TwoVector>& trapVertices) {
161 std::vector<G4TwoVector> g4Vertices;
162 g4Vertices.reserve(trapVertices.size());
163 for (
const auto& vertex : trapVertices) {
164 g4Vertices.push_back(
168 return new G4GenericTrap(
173 if (maxTwist > fgkMaxTwistAngle) {
177 std::cerr <<
"+++ Error +++" << std::endl;
178 std::cerr <<
" Arb8 \"" << name
179 <<
"\" cannot be divided into two G4GenericTrap solids."
181 std::cerr <<
" Its maximum lateral-face twist is " << maxTwist
182 <<
" degrees." << std::endl;
186 G4GenericTrap* lower =
188 G4GenericTrap* upper =
191 G4MultiUnion* combined =
new G4MultiUnion(name);
192 G4RotationMatrix rotation;
194 *lower, G4Transform3D(
195 rotation, G4ThreeVector(0., 0.,
198 *upper, G4Transform3D(
199 rotation, G4ThreeVector(0., 0.,
201 combined->Voxelize();
205 fSolid = makeGenericTrap(
"", hz, vertices);
212 G4int nv = fgkNofVertices / 2;
213 std::vector<G4ThreeVector> downVertices;
214 for (G4int i = 0; i < nv; i++)
215 downVertices.push_back(
220 std::vector<G4ThreeVector> upVertices;
221 for (G4int i = nv; i < 2 * nv; i++)
222 upVertices.push_back(
228 G4ThreeVector cross = (downVertices[1] - downVertices[0])
229 .cross(downVertices[2] - downVertices[1]);
230 if (cross.z() > 0.0) {
231 ReorderVertices(downVertices);
232 ReorderVertices(upVertices);
235 fTessellatedSolid =
new G4TessellatedSolid(name);
238 facet = MakeDownFacet(downVertices, 0, 1, 2);
239 if (facet) fTessellatedSolid->AddFacet(facet);
241 facet = MakeDownFacet(downVertices, 0, 2, 3);
242 if (facet) fTessellatedSolid->AddFacet(facet);
244 facet = MakeUpFacet(upVertices, 0, 2, 1);
245 if (facet) fTessellatedSolid->AddFacet(facet);
247 facet = MakeUpFacet(upVertices, 0, 3, 2);
248 if (facet) fTessellatedSolid->AddFacet(facet);
251 for (G4int i = 0; i < nv; ++i) {
252 G4int j = (i + 1) % nv;
253 facet = MakeSideFacet(
254 downVertices[j], downVertices[i], upVertices[i], upVertices[j]);
256 if (facet) fTessellatedSolid->AddFacet(facet);
259 fTessellatedSolid->SetSolidClosed(
true);
264 fSolid = fTessellatedSolid;
270 G4GenericTrap* genericTrap, G4ReflectedSolid* reflected)
274 fHz(genericTrap->GetZHalfLength() *
ClhepVGM::Units::Length()),
276 fTessellatedSolid(0),
281 const std::vector<G4TwoVector>& vertices = genericTrap->GetVertices();
282 fVertices.reserve(vertices.size());
284 for (G4int i = 0; i < G4int(vertices.size()); ++i) {
286 G4int source = reflected ? (i + fgkNofVertices / 2) % fgkNofVertices : i;
305 fTessellatedSolid(0),
318 fTessellatedSolid(0),
331void Geant4GM::Arb8::ReorderVertices(std::vector<G4ThreeVector>& vertices)
335 std::vector<G4ThreeVector> oldVertices(vertices);
337 for (
unsigned int i = 0; i < oldVertices.size(); ++i) {
338 vertices[i] = oldVertices[oldVertices.size() - 1 - i];
343G4VFacet* Geant4GM::Arb8::MakeDownFacet(
344 std::vector<G4ThreeVector> fromVertices,
int ind1,
int ind2,
int ind3)
const
350 if (fromVertices[ind1] == fromVertices[ind2] ||
351 fromVertices[ind2] == fromVertices[ind3] ||
352 fromVertices[ind1] == fromVertices[ind3])
355 std::vector<G4ThreeVector> vertices;
356 vertices.push_back(fromVertices[ind1]);
357 vertices.push_back(fromVertices[ind2]);
358 vertices.push_back(fromVertices[ind3]);
362 G4ThreeVector cross =
363 (vertices[1] - vertices[0]).cross(vertices[2] - vertices[1]);
365 if (cross.z() > 0.0) {
368 std::cerr <<
" Geant4GM::Arb8::MakeDownFacet:" << std::endl;
369 std::cerr <<
" Vertices in wrong order." << std::endl;
370 std::cerr <<
"*** Error: Aborting execution ***" << std::endl;
374 return new G4TriangularFacet(vertices[0], vertices[1], vertices[2], ABSOLUTE);
378G4VFacet* Geant4GM::Arb8::MakeUpFacet(
379 std::vector<G4ThreeVector> fromVertices,
int ind1,
int ind2,
int ind3)
const
385 if (fromVertices[ind1] == fromVertices[ind2] ||
386 fromVertices[ind2] == fromVertices[ind3] ||
387 fromVertices[ind1] == fromVertices[ind3])
390 std::vector<G4ThreeVector> vertices;
391 vertices.push_back(fromVertices[ind1]);
392 vertices.push_back(fromVertices[ind2]);
393 vertices.push_back(fromVertices[ind3]);
397 G4ThreeVector cross =
398 (vertices[1] - vertices[0]).cross(vertices[2] - vertices[1]);
400 if (cross.z() < 0.0) {
403 std::cerr <<
" Geant4GM::Arb8::MakeUpFacet:" << std::endl;
404 std::cerr <<
" Vertices in wrong order." << std::endl;
405 std::cerr <<
"*** Error: Aborting execution ***" << std::endl;
409 return new G4TriangularFacet(vertices[0], vertices[1], vertices[2], ABSOLUTE);
413G4VFacet* Geant4GM::Arb8::MakeSideFacet(G4ThreeVector downVertex0,
414 G4ThreeVector downVertex1, G4ThreeVector upVertex1,
415 G4ThreeVector upVertex0)
const
420 if (downVertex0 == downVertex1 && upVertex0 == upVertex1)
return 0;
422 if (downVertex0 == downVertex1)
423 return new G4TriangularFacet(downVertex0, upVertex1, upVertex0, ABSOLUTE);
425 if (upVertex0 == upVertex1)
426 return new G4TriangularFacet(downVertex0, downVertex1, upVertex0, ABSOLUTE);
428 return new G4QuadrangularFacet(
429 downVertex0, downVertex1, upVertex1, upVertex0, ABSOLUTE);
435 return fSolid->GetName();
445 std::cerr <<
"+++ Error +++" << std::endl;
446 std::cerr <<
" Wrong vertex index: " << index << std::endl;
450 return fVertices[index];
456 if (index < 0 || index >= 4) {
457 std::cerr <<
"+++ Error +++" << std::endl;
458 std::cerr <<
" Wrong twist angle index: " << index << std::endl;
static double Length()
Return CLHEP default length unit in VGM units.
static double Angle()
Return CLHEP default angle unit in VGM units.
static bool IsTwisted(std::vector< VGM::TwoVector > vertices)
virtual int NofVertices() const
Return the number of vertices.
virtual double ZHalfLength() const
Return the half-length along the z axis in mm.
virtual VGM::TwoVector Vertex(int index) const
Return the index-th vertex.
Arb8(const std::string &name, double hz, std::vector< VGM::TwoVector > vertices)
static double MaxTwistAngle(const std::vector< VGM::TwoVector > &vertices)
virtual double TwistAngle(int index) const
Return the index-th twist angle.
virtual std::string Name() const
Return the name of this solid.
static SolidMap * Instance()
void AddSolid(VGM::ISolid *, G4VSolid *)
#define M_PI
Definition of math constant M_PI not available on Win32.
Arb8SplitResult SplitArb8ForGenericTrap(double halfLength, const std::vector< VGM::TwoVector > &vertices, Arb8Split &split)
Split an Arb8 whose corresponding end edges form angles greater than 90 degrees into two pieces accep...
std::pair< double, double > TwoVector
Parameters of two G4GenericTrap-compatible pieces obtained by cutting an Arb8 with a plane perpendicu...
std::vector< VGM::TwoVector > upperVertices
std::vector< VGM::TwoVector > lowerVertices