10#include <ecl/geometry/BelleCrystal.h>
13#include <G4AffineTransform.hh>
14#include <G4VoxelLimits.hh>
15#include <G4VGraphicsScene.hh>
16#include <G4VPVParameterisation.hh>
19#include <CLHEP/Random/RandFlat.h>
26#define QUOTE(X) DO_QUOTE(X)
33# define COUNTER(x) counter[x]++
39# define MATCHOUT(x) if(fmatch) cout<<x<<"\n";
41# define MATCHOUT(x) {}
45const G4double kCoplanar_Tolerance = 1
E-4;
48 const G4ThreeVector* pt)
49 : G4CSGSolid(pName), nsides(n), fPlanes(nsides), fx(2 * nsides)
52 memset(fcounter, 0,
sizeof(fcounter));
56 fmatch = GetName() == QUOTE(MATCHNAME);
61 for (
unsigned int i = 0; i < 2 *
nsides; i++) {
68 auto isConvex = [](std::vector<Point_t>::const_iterator begin, std::vector<Point_t>::const_iterator end) ->
bool {
71 for (
int i0 = 0; i0 < np; i0++)
73 int i1 = (i0 + 1) % np, i2 = (i0 + 2) % np;
74 const Point_t& r2 = *(begin + i2), &r1 = *(begin + i1), &r0 = *(begin + i0);
75 double dx1 = r2.
x - r1.x, dy1 = r2.
y - r1.y;
76 double dx2 = r0.x - r1.x, dy2 = r0.y - r1.y;
77 double x = dx1 * dy2 - dy1 * dx2;
78 if (i0 == 0) sign = x > 0;
80 if (sign != (x > 0))
return false;
86 auto isClockwise = [](std::vector<Point_t>::const_iterator begin, std::vector<Point_t>::const_iterator end) ->
bool {
87 std::vector<Point_t>::const_iterator it = begin;
92 Point_t r1 = *it++; sum += (r1.x - r0.
x) * (r1.y + r0.
y);
95 Point_t r1 = *begin; sum += (r1.x - r0.
x) * (r1.y + r0.
y);
99 if (!isConvex(
fx.begin(),
fx.begin() +
nsides)) {
100 std::ostringstream message;
101 message <<
"At -z polygon is not convex: " << GetName();
102 G4Exception(
"BelleCrystal::BelleCrystal()",
"BelleCrystal", FatalException, message);
104 if (!isConvex(
fx.begin() +
nsides,
fx.end())) {
105 std::ostringstream message;
106 message <<
"At +z polygon is not convex: " << GetName();
107 G4Exception(
"BelleCrystal::BelleCrystal()",
"BelleCrystal", FatalException, message);
110 if (isClockwise(
fx.begin(),
fx.begin() +
nsides)) {
111 std::ostringstream message;
112 message <<
"At -z polygon is not in anti-clockwise order: " << GetName();
113 G4Exception(
"BelleCrystal::BelleCrystal()",
"BelleCrystal", FatalException, message);
115 if (isClockwise(
fx.begin() +
nsides,
fx.end())) {
116 std::ostringstream message;
117 message <<
"At +z polygon is not in anti-clockwise order: " << GetName();
118 G4Exception(
"BelleCrystal::BelleCrystal()",
"BelleCrystal", FatalException, message);
122 const G4ThreeVector* pm = pt, *pp = pt +
nsides;
123 bool zm = pm[0].z() < 0, zp = pp[0].z() > 0;
124 for (
unsigned int i = 1; i <
nsides; i++) {
125 zm = zm && (pm[i - 1].z() - pm[i].z()) < kCarTolerance;
126 zp = zp && (pp[i - 1].z() - pp[i].z()) < kCarTolerance;
128 bool zpm = abs(pm[0].z() + pp[0].z()) < kCarTolerance;
129 if (!(zm && zp && zpm)) {
130 std::ostringstream message;
131 message <<
"Invalid vertice coordinates for Solid: " << GetName() <<
" " << zp <<
" " << zm <<
" " << zpm;
132 G4Exception(
"BelleCrystal::BelleCrystal()",
"BelleCrystal", FatalException, message);
135 for (
unsigned int i = 0; i <
nsides; i++)
138 std::ostringstream message;
139 message <<
"Wrong number of sides for Belle Crystal: " << GetName() <<
" nsides = " <<
nsides;
140 G4Exception(
"BelleCrystal::BelleCrystal()",
"BelleCrystal", FatalException, message);
146 : G4CSGSolid(pName), nsides(0), fDz(0)
153 : G4CSGSolid(a), nsides(0), fDz(0)
161 cout << GetName() <<
" ";
162 for (
int i = 0; i < 6; i++) cout << counter[i] <<
" "; cout << endl;
170 : G4CSGSolid(rhs), nsides(rhs.nsides), fDz(rhs.fDz), fPlanes(rhs.fPlanes), fx(rhs.fx)
178 if (
this == &rhs) {
return *
this; }
181 G4CSGSolid::operator=(rhs);
199 const G4ThreeVector& p3,
const G4ThreeVector& p4,
202 G4ThreeVector v12 = p2 - p1;
203 G4ThreeVector v13 = p3 - p1;
204 G4ThreeVector v14 = p4 - p1;
205 G4ThreeVector Vcross = v12.cross(v13);
207 if (std::fabs(Vcross.dot(v14) / (Vcross.mag()*v14.mag())) > kCoplanar_Tolerance) {
208 std::ostringstream message;
209 message <<
"Vertices are not in the same plane: " << GetName() <<
" volume =" << Vcross.dot(v14);
210 G4Exception(
"BelleCrystal::MakePlane()",
"BelleCrystal", FatalException, message);
213 double a = +(p4.y() - p2.y()) * (p3.z() - p1.z()) - (p3.y() - p1.y()) * (p4.z() - p2.z());
214 double b = -(p4.x() - p2.x()) * (p3.z() - p1.z()) + (p3.x() - p1.x()) * (p4.z() - p2.z());
215 double c = +(p4.x() - p2.x()) * (p3.y() - p1.y()) - (p3.x() - p1.x()) * (p4.y() - p2.y());
216 double sd =
sqrt(a * a + b * b + c * c);
220 plane.n = G4ThreeVector(a, b, c);
221 plane.d = -(a * p1.x() + b * p1.y() + c * p1.z());
232 const G4VPhysicalVolume*)
234 G4Exception(
"BelleCrystal::ComputeDimensions()",
235 "GeomSolids0001", FatalException,
236 "BelleCrystal does not support Parameterisation.");
242G4ThreeVector min(
const G4ThreeVector& a,
const G4ThreeVector& b)
244 return G4ThreeVector(std::min(a.x(), b.x()), std::min(a.y(), b.y()), std::min(a.z(), b.z()));
248G4ThreeVector max(
const G4ThreeVector& a,
const G4ThreeVector& b)
250 return G4ThreeVector(std::max(a.x(), b.x()), std::max(a.y(), b.y()), std::max(a.z(), b.z()));
255 const G4VoxelLimits& bb,
256 const G4AffineTransform& pTransform,
257 G4double& pMin, G4double& pMax)
const
259 const double inf = std::numeric_limits<double>::infinity();
260 G4ThreeVector v0(inf, inf, inf), v1(-inf, -inf, -inf);
261 for (
unsigned int i = 0; i < 2 *
nsides; i++) {
262 G4ThreeVector v = pTransform.TransformPoint(
vertex(i));
266 G4ThreeVector b0(bb.GetMinXExtent(), bb.GetMinYExtent(), bb.GetMinZExtent());
267 G4ThreeVector b1(bb.GetMaxXExtent(), bb.GetMaxYExtent(), bb.GetMaxZExtent());
273 case kXAxis: pMin = v0.x(); pMax = v1.x();
break;
274 case kYAxis: pMin = v0.y(); pMax = v1.y();
break;
275 case kZAxis: pMin = v0.z(); pMax = v1.z();
break;
280 if ((pMin < inf) || (pMax > -inf)) {
283 pMin -= kCarTolerance ;
284 pMax += kCarTolerance ;
301 MATCHOUT(
"Inside(p) " << p.x() <<
" " << p.y() <<
" " << p.z());
303 double d = std::fabs(p.z()) -
fDz;
307 d = max(t.n * p + t.d, d);
309 const G4double delta = 0.5 * kCarTolerance;
314 EInside res = EInside(in);
328 MATCHOUT(
"SurfaceNormal(p) " << p.x() <<
" " << p.y() <<
" " << p.z());
329 const G4double delta = 0.5 * kCarTolerance;
330 G4double safe = kInfinity;
331 unsigned int iside = 0, kside = 0;
332 vector<double> adist(
nsides + 2);
333 auto dist = [delta, &safe, &iside, &kside, &adist](
double d,
unsigned int i) ->
void {
336 iside = (d < safe) ? i : iside;
344 dist(t.n * p + t.d, i++);
347 dist(p.z() -
fDz, i++);
348 dist(p.z() +
fDz, i++);
355 if (adist[i++] < delta) res +=
fPlanes[i].n;
358 if (adist[i++] < delta) res.setZ(res.z() + 1.0);
359 if (adist[i++] < delta) res.setZ(res.z() - 1.0);
365 }
else if (iside ==
nsides) {
366 res = G4ThreeVector(0, 0, 1);
368 res = G4ThreeVector(0, 0, -1);
386 MATCHOUT(
"DistanceToIn(p) " << p.x() <<
" " << p.y() <<
" " << p.z());
387 G4double d = std::fabs(p.z()) -
fDz;
391 d = max(t.n * p + t.d, d);
409 MATCHOUT(
"DistanceToOut(p) " << p.x() <<
" " << p.y() <<
" " << p.z());
410 G4double d =
fDz - std::fabs(p.z());
414 d = min(-(t.n * p + t.d), d);
431 const G4ThreeVector& v)
const
435 MATCHOUT(
"DistanceToIn(p,v) " << p.x() <<
" " << p.y() <<
" " << p.z() <<
" " << v.x() <<
" " << v.y() <<
" " << v.z());
436 G4double delta = 0.5 * kCarTolerance;
437 double tin = 0, tout = kInfinity;
438 auto outside = [delta, &tin, &tout](
double d,
double nv) ->
bool {
444 if (d >= -delta)
return true;
453 if (outside(t.n * p + t.d, t.n * v)) {tin = kInfinity;
goto exit;}
456 if (outside(p.z() -
fDz, v.z())) {tin = kInfinity;
goto exit;}
457 if (outside(-p.z() -
fDz, -v.z())) {tin = kInfinity;
goto exit;}
460 double res = (tin > tout) ? kInfinity : tin;
475 const G4bool calcNorm, G4bool* IsValid, G4ThreeVector* n)
const
479 MATCHOUT(
"DistanceToOut(p,v) " << p.x() <<
" " << p.y() <<
" " << p.z() <<
" " << v.x() <<
" " << v.y() <<
" " << v.z() <<
" " <<
481 const G4double delta = 0.5 * kCarTolerance;
482 unsigned int iside = 10;
483 G4double lmin = kInfinity;
485 auto outside = [delta, &lmin, &iside](
double d,
double nv,
unsigned int i) ->
bool {
488 lmin = 0; iside = i;
return true;
495 if (d < nv * lmin) {lmin = d / nv; iside = i;}
499 lmin = 0; iside = i;
return true;
509 if (outside(t.n * p + t.d, t.n * v, i++))
goto exit;
512 if (outside(p.z() -
fDz, v.z(), i++))
goto exit;
513 if (outside(-p.z() -
fDz, -v.z(), i++))
goto exit;
520 }
else if (iside ==
nsides) {
521 *n = G4ThreeVector(0, 0, 1);
523 *n = G4ThreeVector(0, 0, -1);
543 return G4String(
"BelleCrystal");
555 G4int oldprc = os.precision(16);
556 os <<
"-----------------------------------------------------------\n"
557 <<
" *** Dump for solid - " << GetName() <<
" ***\n"
558 <<
" ===================================================\n"
559 <<
" Solid type: BelleCrystal\n"
561 <<
" crystal side plane equations:\n"
562 <<
"-----------------------------------------------------------\n";
563 os.precision(oldprc);
569unsigned int ivertx4[][3] = {{0, 5, 4}, {0, 1, 5}, {1, 7, 5}, {1, 3, 7}, {3, 6, 7}, {3, 2, 6}, {2, 4, 6}, {2, 0, 4}, {0, 3, 1}, {0, 2, 3}, {4, 5, 7}, {4, 7, 6}};
570unsigned int ivertx5[][3] = {{0, 6, 5}, {0, 1, 6}, {1, 7, 6}, {1, 2, 7}, {2, 8, 7}, {2, 3, 8}, {3, 9, 8}, {3, 4, 9}, {4, 5, 9}, {4, 0, 5}, {0, 2, 1}, {0, 3, 2}, {0, 4, 3}, {5, 6, 7}, {5, 7, 8}, {5, 8, 9}};
574 static unsigned int vert[3];
576 if (
nsides == 0)
return ivertx4[it];
588 vert[0] = 0, vert[2] = 1 + j, vert[1] = 2 + j;
598G4ThreeVector crossplanes(
const Plane_t& p0,
const Plane_t& p1,
double Dz)
600 const G4ThreeVector& n0 = p0.
n;
601 const G4ThreeVector& n1 = p1.n;
602 double A = n0.z() * Dz + p0.
d;
603 double B = n1.z() * Dz + p1.d;
604 double iD = 1 / (n0.y() * n1.x() - n0.x() * n1.y());
605 double x = (A * n1.y() - B * n0.y()) * iD;
606 double y = (B * n0.x() - A * n1.x()) * iD;
608 return G4ThreeVector(x, y, z);
611#define PACK(k0,k1,w,n) ((((k0)<<(0))+((k1)<<(w)))<<((2*w)*n))
629 return G4ThreeVector(
fx[i].x,
fx[i].y, Dz);
637 double a1 = CLHEP::RandFlat::shoot(0., 1.), a2 = CLHEP::RandFlat::shoot(0., 1.);
638 if (a1 + a2 > 1) { a1 = 1 - a1; a2 = 1 - a2;}
639 double a0 = 1 - (a1 + a2);
640 const unsigned int* iv =
ivertx(it);
642 G4ThreeVector r1(p0.x()*a0 + p1.x()*a1 + p2.x()*a2,
643 p0.y()*a0 + p1.y()*a1 + p2.y()*a2,
644 p0.z()*a0 + p1.z()*a1 + p2.z()*a2);
650 const unsigned int* iv =
ivertx(it);
653 G4ThreeVector n = (p1 - p0).cross(p2 - p0);
655 return 0.5 * n.mag();
663 double totarea = 0, totvol = 0;
664 for (
int i = 0; i < nt; i++) {
665 double v, s =
area(i, v);
668 fareas.push_back(totarea);
677 if (fCubicVolume == 0.0) {
679 fSurfaceArea =
fareas.back();
686 if (fSurfaceArea == 0.0) {
688 fSurfaceArea =
fareas.back();
697 double r = CLHEP::RandFlat::shoot(0.,
fareas.back());
698 std::vector<double>::const_iterator it = std::lower_bound(
fareas.begin(),
fareas.end(), r);
705 scene.AddSolid(*
this);
711 AllocateMemory(n, nsides + 2 * (nsides - 2));
712 for (
int i = 0; i < n; i++) pV[i + 1] = pt[i];
715 for (
int j = 0; j < nsides; j++)
716 pF[count++] = G4Facet(1 + j, 0, 1 + (j + 1) % nsides, 0, 1 + ((j + 1) % nsides) + nsides, 0, 1 + j + nsides, 0);
717 for (
int j = 0; j < nsides - 2; j++) pF[count++] = G4Facet(1 + nsides, 0, 2 + j + nsides, 0, 3 + j + nsides, 0, 0, 0);
718 for (
int j = 0; j < nsides - 2; j++) pF[count++] = G4Facet(1, 0, 3 + j, 0, 2 + j, 0, 0, 0);
727 vector<G4ThreeVector> pt(np);
728 for (
int i = 0; i < np; i++) pt[i] =
vertex(i);
740 const double inf = std::numeric_limits<double>::infinity();
741 G4ThreeVector minimum(inf, inf, inf), maximum(-inf, -inf, -inf);
743 for (
int i = 0; i < np; i++) {
747 minimum = min(minimum, pt);
748 maximum = max(maximum, pt);
a Belle crystal in Geant4
std::vector< Plane_t > fPlanes
vector of planes
G4GeometryType GetEntityType() const
Get entity type.
void DescribeYourselfTo(G4VGraphicsScene &scene) const
Visualisation functions.
const unsigned int * ivertx(unsigned int i) const
get the ith vertex
G4ThreeVector GetPointOnTriangle(int) const
Returns a random point on the surface of one of the faces.
G4Polyhedron * CreatePolyhedron() const
create polyhedron
G4bool MakePlane(const G4ThreeVector &p1, const G4ThreeVector &p2, const G4ThreeVector &p3, const G4ThreeVector &p4, Plane_t &plane) const
Calculate the coef's of the plane p1->p2->p3->p4->p1 where the ThreeVectors 1-4 are in anti-clockwise...
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Two vectors define an axis-parallel bounding box for the shape.
double area(int, double &) const
triangle area
G4double GetCubicVolume()
get the Cubic volume
G4ThreeVector vertex(unsigned int i) const
return ith vertex
BelleCrystal & operator=(const BelleCrystal &rhs)
assignment operator
G4ThreeVector GetPointOnSurface() const
get point on surface
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
calculate the extent of the volume
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
Calculate side nearest to p, and return normal.
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
Calculate exact shortest distance to any boundary from outside.
virtual ~BelleCrystal()
Destructor.
G4VSolid * Clone() const
Make a clone of the object.
std::ostream & StreamInfo(std::ostream &os) const
Stream object contents to an output stream.
std::vector< double > fareas
vector of area values
double getvolarea() const
get volume area
EInside Inside(const G4ThreeVector &p) const
Return whether point inside/outside/on surface, using tolerance.
std::vector< Point_t > fx
vector of points
G4double GetSurfaceArea()
get the surface area
BelleCrystal(const G4String &pName)
Constructor for "nominal" BelleCrystal.
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
compute the dimensions
unsigned int nsides
the number of sides
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0) const
Calculate exact shortest distance to any boundary from inside.
Belle crystal in polyhedron.
PolyhedronBelleCrystal(int, const G4ThreeVector *)
constructor
virtual ~PolyhedronBelleCrystal()
destructor
double sqrt(double a)
sqrt for double
Abstract base class for different kinds of events.
G4ThreeVector n
Normal unit vector (a,b,c)