8 #include "ecl/geometry/BelleLathe.h"
12 #include "G4VoxelLimits.hh"
13 #include "G4AffineTransform.hh"
15 #include "G4VPVParameterisation.hh"
17 #include "G4VGraphicsScene.hh"
19 #include "CLHEP/Random/RandFlat.h"
28 typedef int counter_t[6];
29 map<string, counter_t> counterl;
30 #define COUNTER(x) counterl[GetName()][x]++
52 inline double dotxy(
const G4ThreeVector& p,
const G4ThreeVector& n)
54 return p.x() * n.x() + p.y() * n.y();
62 return o <<
"{" << v.z <<
", " << v.r <<
"}";
67 explicit curl_t(
const G4ThreeVector& _v): v(_v) {}
72 return o <<
"{" << c.v.x() <<
", " << c.v.y() <<
", " << c.v.z() <<
"}, ";
76 BelleLathe::BelleLathe(
const G4String& pName,
double phi0,
double dphi,
const vector<zr_t>& c)
86 for (
int i = 0; i < n; i++) {
87 zr_t t = {z[i], rin[i]};
90 for (
int i = n - 1; i >= 0; i--) {
91 zr_t t = {z[i], rout[i]};
95 Init(contour, phi0, dphi);
98 void BelleLathe::Init(
const vector<zr_t>& c,
double phi0,
double dphi)
100 vector<zr_t> contour = c;
103 vector<zr_t>::iterator it0 = contour.begin(), it1 = it0 + 1;
104 for (; it1 != contour.end();) {
105 const zr_t& s0 = *it0, &s1 = *it1;
106 if (abs(s0.z - s1.z) < kCarTolerance && abs(s0.r - s1.r) < kCarTolerance)
107 it1 = contour.erase(it1);
112 const zr_t& s0 = *it0, &s1 = contour[0];
113 if (abs(s0.z - s1.z) < kCarTolerance && abs(s0.r - s1.r) < kCarTolerance) contour.erase(it0);
118 vector<zr_t>::iterator it0 = contour.begin(), it1 = it0 + 1, it2 = it1 + 1;
119 for (; it0 != contour.end();) {
120 const zr_t& s0 = *it0, &s1 = *it1, &s2 = *it2;
121 double dr2 = s2.r - s0.r, dz2 = s2.z - s0.z;
122 double d = (s1.z - s0.z) * dr2 - (s1.r - s0.r) * dz2;
124 if (d * d < kCarTolerance * kCarTolerance * (dr2 * dr2 + dz2 * dz2)) {
125 it1 = contour.erase(it1);
127 if (++it2 >= contour.end()) it2 = contour.begin();
129 if (--it0 < contour.begin()) it0 = (++contour.rbegin()).base();
133 if (++it1 >= contour.end()) it1 = contour.begin();
134 if (++it2 >= contour.end()) it2 = contour.begin();
141 zr_t p0 = contour[0];
142 for (
int i = 1, imax = contour.size(); i < imax; i++) {
143 zr_t p1 = contour[i];
144 sum += (p1.z - p0.z) * (p1.r + p0.r);
147 zr_t p1 = contour[0];
148 sum += (p1.z - p0.z) * (p1.r + p0.r);
152 std::reverse(contour.begin(), contour.end());
156 auto convexside = [
this](
cachezr_t& s,
double eps) ->
void {
158 if (s.dz > 0)
return;
159 vector<zr_t>::const_iterator it = fcontour.begin();
160 double a = s.dz * s.is, b = s.dr * s.is, cc = b * s.z - a * s.r;
161 bool dp =
false, dm =
false;
165 double d = a * p.r - b * p.z + cc;
166 dm = dm || (d < -eps);
167 dp = dp || (d > eps);
168 if (dm && dp) {s.isconvex =
false;
return;}
169 }
while (++it != fcontour.end());
176 fcache.reserve(fcontour.size());
177 for (
int i = 0, n = fcontour.size(); i < n; i++) {
178 const zr_t& s0 = fcontour[i], &s1 = fcontour[(i + 1) % n];
184 t.s2 = t.dz * t.dz + t.dr * t.dr;
187 t.zmin = min(s0.z, s1.z);
188 t.zmax = max(s0.z, s1.z);
189 t.r2min = pow(min(s0.r, s1.r), 2);
190 t.r2max = pow(max(s0.r, s1.r), 2);
191 t.ta = (s1.r - s0.r) / (s1.z - s0.z);
192 convexside(t, kCarTolerance);
195 frmax = max(frmax, s0.r);
196 frmin = min(frmin, s0.r);
197 fzmax = max(fzmax, s0.z);
198 fzmin = min(fzmin, s0.z);
204 fdphi = std::min(2 * M_PI, fdphi);
205 fdphi = std::max(0.0, fdphi);
208 fc1 = cos(fphi + fdphi);
209 fs1 = sin(fphi + fdphi);
215 fgtpi = fdphi > M_PI;
216 ftwopi = abs(fdphi - 2 * M_PI) < kCarTolerance;
220 for (
int i = 0, n = fcontour.size(); i < n; i++) {
221 const zr_t& s = fcontour[i];
224 sort(fz.begin(), fz.end());
225 fz.erase(std::unique(fz.begin(), fz.end()), fz.end());
227 for (
int i = 1, ni = fz.size(); i < ni; i++) {
228 double a = fz[i - 1], b = fz[i];
229 findx.push_back(fseg.size());
230 for (
int j = 0, nj = fcache.size(); j < nj; j++) {
232 double cc = sj.zmin, d = sj.zmax;
233 if (cc != d and b > cc and d > a) {
238 findx.push_back(fseg.size());
243 auto getpolycone = [](
const G4String & pName,
double phi0,
double dphi,
const vector<zr_t>& c) -> G4GenericPolycone* {
247 for (
int i = 0, imax = c.size(); i < imax; i++)
252 return new G4GenericPolycone(pName, phi0, dphi, c.size(), r.data(), z.data());
254 fshape = getpolycone(GetName(), phi0, dphi, fcontour);
268 Init(a, 0, 2 * M_PI);
277 Init(b, 0, 2 * M_PI);
284 cout << GetName() <<
" ";
285 for (
int i = 0; i < 6; i++) cout << counterl[GetName()][i] <<
" "; cout << endl;
291 : G4CSGSolid(rhs), fcontour(rhs.fcontour), fcache(rhs.fcache), fz(rhs.fz),
292 findx(rhs.findx), fseg(rhs.fseg), farea(rhs.farea), ftlist(rhs.ftlist),
293 fphi(rhs.fphi), fdphi(rhs.fdphi), fs0(rhs.fs0), fc0(rhs.fc0), fs1(rhs.fs1),
294 fc1(rhs.fc1), fn0x(rhs.fn0x), fn0y(rhs.fn0y), fn1x(rhs.fn1x), fn1y(rhs.fn1y),
295 frmin(rhs.frmin), frmax(rhs.frmax), fzmin(rhs.fzmin), fzmax(rhs.fzmax),
296 fgtpi(rhs.fgtpi), ftwopi(rhs.ftwopi), fshape(rhs.fshape), fsurf(rhs.fsurf)
304 if (
this == &rhs) {
return *
this; }
307 G4CSGSolid::operator=(rhs);
310 fcontour = rhs.fcontour;
343 const G4VPhysicalVolume*)
345 G4Exception(
"BelleLathe::ComputeDimensions()",
346 "GeomSolids0001", FatalException,
347 "BelleLathe does not support Parameterisation.");
352 vector<double> quadsolve(
double a,
double b,
double c)
357 double D = b * b - a * c;
360 double sum = b + ((b > 0) ? sD : -sD);
361 double t0 = -c / sum;
362 double t1 = -sum / a;
372 inline int quadsolve(
double a,
double b,
double c,
double& t0,
double& t1)
376 double D = b * b - a * c;
379 double sum = b + ((b > 0) ? sD : -sD);
388 vector<solution_t> extremum(
double A,
double B,
double C,
double D,
double E,
double F)
391 vector<solution_t> res;
392 if (abs(B) < abs(A)) {
393 double a = 4 * A * C - B * B;
394 double b = 2 * (2 * A * E - B * D);
395 double c = 4 * A * F - D * D;
396 vector<double> ss = quadsolve(a, b, c);
398 if (fpclassify(s) == FP_INFINITE)
continue;
399 double t = -(s * B + D) / (2 * A);
404 double B2 = B * B, CD = C * D, BE = B * E;
405 double a = A * (4 * A * C - B2);
406 double b = 2 * A * (2 * CD - BE);
407 double c = D * (CD - BE) + B2 * F;
408 vector<double> ts = quadsolve(a, b, c);
410 if (fpclassify(t) == FP_INFINITE)
continue;
411 double s = -(2 * t * A + D) / B;
420 vector<double> BelleLathe::linecross(
const G4ThreeVector& p,
const G4ThreeVector& n)
const
422 auto hitside = [
this, &p, &n](
double t,
double zmin,
double zmax) ->
bool {
423 double z = p.z() + n.z() * t;
424 bool k = zmin < z && z <= zmax;
427 double x = p.x() + n.x() * t;
428 double y = p.y() + n.y() * t;
429 k = k && insector(x, y);
434 auto hitzside = [
this, &p, &n](
double t,
double r2min,
double r2max) ->
bool {
435 double x = p.x() + n.x() * t;
436 double y = p.y() + n.y() * t;
437 double r2 = x * x + y * y;
438 bool k = r2min <= r2 && r2 < r2max;
441 k = k && insector(x, y);
447 double inz = 1 / n.z();
448 double nn = Belle2::ECL::dotxy(n, n), np = dotxy(n, p), pp = dotxy(p, p);
451 double t = (s.z - p.z()) * inz;
452 if (hitzside(t, s.r2min, s.r2max)) { tc.push_back(t); }
463 double taz = ta * (p.z() - s.z);
464 double R = taz + s.r;
467 double nzta = n.z() * ta;
468 A = nzta * nzta - nn;
471 double D = B * B + (pp - R2) * A;
473 double sD = sqrt(D), iA = 1 / A;
474 double t0 = (B + sD) * iA, t1 = (B - sD) * iA;
475 if (hitside(t0, s.zmin, s.zmax)) tc.push_back(t0);
476 if (hitside(t1, s.zmin, s.zmax)) tc.push_back(t1);
483 double d = fn0x * p.x() + fn0y * p.y();
484 double vn = fn0x * n.x() + fn0y * n.y();
486 G4ThreeVector r = p + n * t;
487 zr_t zr = {r.z(), fc0 * r.x() + fs0 * r.y()};
488 if (vn != 0 && wn_poly(zr) == 2) tc.push_back(t);
492 double d = fn1x * p.x() + fn1y * p.y();
493 double vn = fn1x * n.x() + fn1y * n.y();
495 G4ThreeVector r = p + n * t;
496 zr_t zr = {r.z(), fc1 * r.x() + fs1 * r.y()};
497 if (vn != 0 && wn_poly(zr) == 2) tc.push_back(t);
501 sort(tc.begin(), tc.end());
507 const G4VoxelLimits& bb,
508 const G4AffineTransform& T,
509 G4double& pMin, G4double& pMax)
const
511 auto maxdist = [
this](
const G4ThreeVector & n) -> G4ThreeVector {
513 int i = 0, nsize = fcache.size();
514 if (ftwopi || insector(n.x(), n.y()))
516 double nr = hypot(n.x(), n.y()), nz = n.z();
517 double dmax = -kInfinity, R = 0, Z = 0;
520 double d1 = nz * s.z + nr * s.r;
521 if (dmax < d1) { R = s.r; Z = s.z; dmax = d1;}
522 }
while (++i < nsize);
525 r.set(R * n.x(), R * n.y(), Z);
527 double phi = fphi + 0.5 * fdphi;
528 r.set(R * cos(phi), R * sin(phi), Z);
531 double dmax = -kInfinity;
535 G4ThreeVector rf(-fn0y * s.r, fn0x * s.r, s.z), rl(fn1y * s.r, -fn1x * s.r, s.z);
536 double d0 = rf * n, d1 = rl * n;
538 if (dmax < d0) { r = rf; dmax = d0;}
539 if (dmax < d1) { r = rl; dmax = d1;}
540 }
while (++i < nsize);
545 struct seg_t {
int i0, i1;};
546 auto clip = [](vector<G4ThreeVector>& vlist, vector<seg_t>& slist,
const G4ThreeVector & n,
double dist) {
551 for (
const G4ThreeVector& v : vlist) d.push_back(v * n + dist);
553 for (seg_t s : slist) {
554 double prod = d[s.i0] * d[s.i1];
557 G4ThreeVector
rn = (vlist[s.i0] * d[s.i1] - vlist[s.i1] * d[s.i0]) * (1 / (d[s.i1] - d[s.i0]));
558 lone.push_back(vlist.size()); vlist.push_back(
rn);
560 s = {lone.back(), s.i1};
562 s = {s.i0, lone.back()};
564 }
else if (prod == 0) {
565 if (d[s.i0] == 0 && d[s.i1] > 0) {
566 lone.push_back(s.i0);
567 }
else if (d[s.i0] > 0 && d[s.i1] == 0) {
568 lone.push_back(s.i1);
571 if (d[s.i0] < 0)
continue;
577 int imax = -1, jmax = -1;
579 for (
unsigned int i = 0; i < lone.size(); i++) {
580 for (
unsigned int j = i + 1; j < lone.size(); j++) {
581 double d2 = (vlist[lone[i]] - vlist[lone[j]]).mag2();
582 if (d2 > dmax) { imax = lone[i]; jmax = lone[j];}
588 G4ThreeVector k = vlist[jmax] - vlist[imax];
589 sort(lone.begin(), lone.end(), [&k, &vlist, &imax](
int i,
int j) {return k * (vlist[i] - vlist[imax]) < k * (vlist[j] - vlist[imax]);});
591 for (
unsigned int i = 0; i < lone.size(); i += 2) {
592 seg_t t = {lone[i], lone[i + 1]};
593 for (
const seg_t& s : snew) {
594 if (t.i1 == s.i0) { snew.push_back(t);
break;}
595 if (t.i0 == s.i0) { swap(t.i0, t.i1); snew.push_back(t);
break;}
602 auto PhiCrossN = [
this, clip](
const vector<Plane_t>& planes) {
605 vector<G4ThreeVector> vlist;
607 vector<G4ThreeVector> res;
609 int nsize = fcache.size();
610 vlist.reserve(nsize);
611 slist.reserve(nsize);
612 for (
int iphi = 0; iphi < 2; iphi++) {
616 double kx = iphi ? -fn0y : fn1y, ky = iphi ? fn0x : -fn1x;
621 G4ThreeVector r(kx * s.r, ky * s.r, s.z);
623 seg_t t = {i, i + 1};
625 }
while (++i < nsize - 1);
627 G4ThreeVector r(kx * s.r, ky * s.r, s.z);
629 seg_t t = {nsize - 1, 0};
634 for (
const Plane_t& p : planes) {
636 clip(vlist, slist, p.n, p.d);
639 vector<bool> bv(vlist.size(),
false);
641 for (vector<seg_t>::const_iterator it = slist.begin(); it != slist.end(); ++it) {
646 for (
unsigned int i = 0; i < vlist.size(); i++) {
647 if (!bv[i])
continue;
648 res.push_back(vlist[i]);
654 auto RCross = [
this](
const G4ThreeVector & op,
const G4ThreeVector & k,
const G4ThreeVector & u) {
657 vector<solution_t> ts;
658 int nsize = fcache.size();
664 double r0 = seg.r, z0 = seg.z, tg = seg.ta, tg2 = tg * tg;
665 double rtg = r0 * tg;
667 G4ThreeVector o(op.x(), op.y(), op.z() - z0);
669 double ko = k * o, uo = u * o, ck = k.z(), cu = u.z(), co = o.z();
670 double k2 = 1, u2 = 1, o2 = o * o;
671 double ck2 = ck * ck, cu2 = cu * cu, co2 = co * co;
672 double dr2 = r0 * r0 - o2;
675 double q1 = co * q0 + rtg;
677 double F00 = co2 * q0 + 2 * co * rtg + dr2;
678 double F10 = 2 * (ck * q1 - ko);
679 double F20 = ck2 * q0 - k2;
680 double F01 = 2 * (cu * q1 - uo);
681 double F11 = 2 * ck * cu * q0;
682 double F02 = cu2 * q0 - u2;
684 vector<solution_t> res = extremum(F02, F11, F20, F01, F10, F00);
686 double t = r.s, s = r.t;
687 G4ThreeVector p = t * k + s * u + op;
688 if (seg.zmin < p.z() && p.z() < seg.zmax) {
690 if (ftwopi || insector(p.x(), p.y()))
695 double a = -(ck2 * u2 + cu2 * k2);
697 if (abs(cu) > abs(ck)) {
698 double b = 2 * (ck * (cu * uo - co * u2) - cu2 * ko);
699 double c = co * (2 * cu * uo - co * u2) + cu2 * dr2;
700 vector<double> tv = quadsolve(a, b, c);
701 for (
double t : tv) {
702 double s = -(co + ck * t) / cu;
703 G4ThreeVector p = t * k + s * u + op;
704 if (ftwopi || insector(p.x(), p.y())) {
710 double b = 2 * (cu * (ck * ko - co * k2) - ck2 * uo);
711 double c = co * (2 * ck * ko - co * k2) + ck2 * dr2;
712 vector<double> sv = quadsolve(a, b, c);
713 for (
double s : sv) {
714 double t = -(co + cu * s) / ck;
715 G4ThreeVector p = t * k + s * u + op;
716 if (ftwopi || insector(p.x(), p.y())) {
723 }
while (++i < nsize);
727 bool b1 =
false, b2 =
false;
728 G4ThreeVector n0, n1, n2;
730 case kXAxis: n0.set(1, 0, 0); n1.set(0, 1, 0); n2.set(0, 0, 1); b1 = bb.IsYLimited(); b2 = bb.IsZLimited();
break;
731 case kYAxis: n0.set(0, 1, 0); n1.set(1, 0, 0); n2.set(0, 0, 1); b1 = bb.IsXLimited(); b2 = bb.IsZLimited();
break;
732 case kZAxis: n0.set(0, 0, 1); n1.set(1, 0, 0); n2.set(0, 1, 0); b1 = bb.IsXLimited(); b2 = bb.IsYLimited();
break;
736 double dmin1 = -kInfinity, dmax1 = kInfinity;
739 case kXAxis: dmin1 = bb.GetMinYExtent(); dmax1 = bb.GetMaxYExtent();
break;
740 case kYAxis: dmin1 = bb.GetMinXExtent(); dmax1 = bb.GetMaxXExtent();
break;
741 case kZAxis: dmin1 = bb.GetMinXExtent(); dmax1 = bb.GetMaxXExtent();
break;
746 double dmin2 = -kInfinity, dmax2 = kInfinity;
749 case kXAxis: dmin2 = bb.GetMinZExtent(); dmax2 = bb.GetMaxZExtent();
break;
750 case kYAxis: dmin2 = bb.GetMinZExtent(); dmax2 = bb.GetMaxZExtent();
break;
751 case kZAxis: dmin2 = bb.GetMinYExtent(); dmax2 = bb.GetMaxYExtent();
break;
756 G4AffineTransform iT = T.Inverse();
758 G4ThreeVector n0t = iT.TransformAxis(n0);
759 G4ThreeVector smin = n0t * kInfinity, smax = (-kInfinity) * n0t;
760 double pmin = kInfinity, pmax = -pmin;
762 G4ThreeVector corners[] = {n1* dmin1 + n2 * dmin2, n1* dmax1 + n2 * dmin2, n1* dmax1 + n2 * dmax2, n1* dmin1 + n2 * dmax2};
763 for (G4ThreeVector& c : corners) iT.ApplyPointTransform(c);
765 vector<Plane_t> planes;
766 for (
int i = 0; i < 4; i++) {
767 const G4ThreeVector& c0 = corners[i], &c1 = corners[(i + 1) % 4];
768 vector<double> dists = linecross(c0, n0t);
770 for (
double t : dists) {
771 G4ThreeVector p = n0t * t + c0;
772 double tt = t + c0 * n0t;
774 if (pmax < tt) { pmax = tt; smax = p;}
775 if (pmin > tt) { pmin = tt; smin = p;}
778 G4ThreeVector u = c1 - c0, un = u.unit();
779 vector<solution_t> ts = RCross(c0, n0t, un);
780 double umax = u.mag();
782 if (0 < r.s && r.s < umax) {
783 double tt = r.t + c0 * n0t;
784 G4ThreeVector p = n0t * r.t + un * r.s + c0;
786 if (pmax < tt) { pmax = tt; smax = p;}
787 if (pmin > tt) { pmin = tt; smin = p;}
790 planes.push_back({ -un, un * c1});
793 vector<G4ThreeVector> vside = PhiCrossN(planes);
794 for (G4ThreeVector& p : vside) {
797 if (pmax < tt) { pmax = tt; smax = p;}
798 if (pmin > tt) { pmin = tt; smin = p;}
801 }
else if (b1 || b2) {
802 G4ThreeVector limits[2], u;
804 limits[0] = n1 * dmin1;
805 limits[1] = n1 * dmax1;
806 u = iT.TransformAxis(n2);
808 limits[0] = n2 * dmin2;
809 limits[1] = n2 * dmax2;
810 u = iT.TransformAxis(n1);
813 for (G4ThreeVector& c : limits) iT.ApplyPointTransform(c);
814 for (
int i = 0; i < 2; i++) {
815 vector<solution_t> ts = RCross(limits[i], n0t, u);
817 double tt = r.t + limits[i] * n0t;
818 G4ThreeVector p = n0t * r.t + u * r.s + limits[i];
820 if (pmax < tt) { pmax = tt; smax = p;}
821 if (pmin > tt) { pmin = tt; smin = p;}
825 vector<Plane_t> planes(2);
828 n = iT.TransformAxis(n1);
830 n = iT.TransformAxis(n2);
832 planes[0] = { n, -limits[0]* n};
833 planes[1] = { -n, limits[1]* n};
834 vector<G4ThreeVector> vside = PhiCrossN(planes);
836 for (G4ThreeVector& p : vside) {
840 if (pmax < tt) { pmax = tt; smax = p;}
841 if (pmin > tt) { pmin = tt; smin = p;}
845 G4ThreeVector rp = maxdist(n0t), rm = maxdist(-n0t);
846 if (bb.Inside(T.TransformPoint(rm))) {
847 double tt = rm * n0t;
848 if (pmin > tt) {pmin = tt; smin = rm;}
850 if (bb.Inside(T.TransformPoint(rp))) {
851 double tt = rp * n0t;
852 if (pmax < tt) {pmax = tt; smax = rp;}
856 T.ApplyPointTransform(smin);
857 T.ApplyPointTransform(smax);
861 pmin -= kCarTolerance;
862 pmax += kCarTolerance;
864 bool hit = pmin < pmax;
867 auto surfhit = [
this, &bb, &T, &n0, &n0t](
double & pmin,
double & pmax,
bool print =
false)->
bool {
868 const int N = 1000 * 1000;
869 if (fsurf.size() == 0)
for (
int i = 0; i < N; i++) fsurf.push_back(GetPointOnSurface());
871 int umin = -1, umax = -1;
872 double wmin = 1e99, wmax = -1e99;
873 for (
int i = 0; i < N; i++)
875 if (bb.Inside(T.TransformPoint(fsurf[i]))) {
876 double w = n0t * fsurf[i];
877 if (wmin > w) {wmin = w; umin = i;}
878 if (wmax < w) {wmax = w; umax = i;}
881 if (print)cout << umin <<
" " << umax <<
" " << wmin <<
" " << wmax << endl;
882 if (umin >= 0 && umax >= 0)
884 G4ThreeVector qmin = fsurf[umin], qmax = fsurf[umax];
885 T.ApplyPointTransform(qmin);
886 T.ApplyPointTransform(qmax);
887 pmin = n0 * qmin, pmax = n0 * qmax;
893 bool res = fshape->CalculateExtent(A, bb, T, pMin, pMax);
894 double srfmin = kInfinity, srfmax = -srfmin;
895 bool sHit = surfhit(srfmin, srfmax);
896 double diff = kCarTolerance;
899 if ((abs(pmin - srfmin) > diff || abs(pmax - srfmax) > diff) && sHit) {
900 cout <<
"===================================\n";
901 cout << GetName() <<
" " << fcache.size() <<
" " << fphi <<
" " << fdphi <<
" " << ftwopi <<
"\n";
902 cout << hit <<
" " << res <<
" " << b1 <<
" " << b2 <<
"\n";
904 cout <<
"ss " << srfmin <<
" " << srfmax <<
"\n";
906 cout <<
"ss : not in bounding box" <<
"\n";
908 cout <<
"my " << pmin <<
" " << pmax <<
"\n";
909 cout <<
"tc " << pMin <<
" " << pMax <<
"\n";
910 cout <<
"df " << pmin - pMin <<
" " << pmax - pMax <<
"\n";
911 G4ThreeVector bmin(bb.GetMinXExtent(), bb.GetMinYExtent(), bb.GetMinZExtent());
912 G4ThreeVector bmax(bb.GetMaxXExtent(), bb.GetMaxYExtent(), bb.GetMaxZExtent());
913 cout <<
"Axis=" << A <<
" " << bmin <<
" " << bmax <<
" " << T <<
"\n";
914 cout << rp <<
" " << rm <<
"\n";
915 cout << smin <<
" " << smax <<
"\n";
928 inline bool BelleLathe::insector(
double x,
double y)
const
930 double d0 = fn0x * x + fn0y * y;
931 double d1 = fn1x * x + fn1y * y;
932 bool b0 = d0 < 0, b1 = d1 < 0;
933 return fgtpi ? b0 || b1 : b0 && b1;
936 int BelleLathe::wn_poly(
const zr_t& r)
const
939 vector<double>::const_iterator it = upper_bound(fz.begin(), fz.end(), r.z);
941 if (it != fz.begin() && it != fz.end()) {
942 int k = it - fz.begin();
943 for (
int i = findx[k - 1]; i != findx[k]; i++) {
945 double dz = r.z - s.z, dr = r.r - s.r;
946 double crs = s.dr * dz - s.dz * dr;
947 wn -= (crs > 0) - (crs < 0);
953 double BelleLathe::mindist(
const zr_t& r)
const
955 double d = kInfinity;
956 int i = 0, n = fcache.size();
959 double dz = r.z - s.z, dr = r.r - s.r;
960 double dot = s.dz * dz + s.dr * dr;
962 d = min(d, dz * dz + dr * dr);
963 }
else if (dot <= s.s2) {
964 double crs = s.dr * dz - s.dz * dr;
965 d = min(d, crs * crs * s.is2);
969 d = (wn_poly(r) == 2) ? -d : d;
974 EInside BelleLathe::Inside(
const G4ThreeVector& p)
const
977 const double delta = 0.5 * kCarTolerance;
978 EInside res = kInside;
980 double d0 = fn0x * p.x() + fn0y * p.y();
981 double d1 = fn1x * p.x() + fn1y * p.y();
983 if (d0 > delta && d1 > delta) { res = kOutside;}
984 else if (d0 > -delta && d1 > -delta) { res = kSurface;}
986 if (d0 > delta || d1 > delta) { res = kOutside;}
987 else if (d0 > -delta || d1 > -delta) { res = kSurface;}
990 if (res != kOutside) {
991 zr_t r = {p.z(), p.perp()};
992 double d = mindist(r);
993 if (res == kSurface && d < delta) res = kSurface;
994 else if (d > delta) res = kOutside;
995 else if (d > -delta) res = kSurface;
1000 EInside dd = fshape->Inside(p);
1001 if (1 || dd != res) {
1002 double d0 = fn0x * p.x() + fn0y * p.y();
1003 double d1 = fn1x * p.x() + fn1y * p.y();
1005 int oldprec = cout.precision(16);
1006 zr_t r = {p.z(), p.perp()};
1007 cout << GetName() <<
" Inside(p) " << p <<
" " << r <<
" my=" << res <<
" tc=" << dd <<
1008 " dist=" << mindist(r) <<
" " << d0 <<
" " << d1 << endl;
1009 cout.precision(oldprec);
1013 MATCHOUT(
"BelleLathe::Inside(p) " << p <<
" res= " << res);
1017 zr_t BelleLathe::normal(
const zr_t& r,
double& d2)
const
1019 double d = std::numeric_limits<double>::infinity(), t = 0;
1021 for (
int i = 0, imax = fcache.size(); i < imax; i++) {
1023 double dz = r.z - s.z, dr = r.r - s.r;
1024 double dot = s.dz * dz + s.dr * dr;
1026 double dist = dz * dz + dr * dr;
1027 if (dist < d) { d = dist; t = dot * s.is2; iseg = i;}
1028 }
else if (dot <= s.s2) {
1029 double crs = s.dr * dz - s.dz * dr;
1030 double dist = crs * crs * s.is2;
1031 if (dist < d) { d = dist; t = dot * s.is2; iseg = i;}
1036 auto getn = [
this](
int i)->
zr_t{
1037 int imax = fcache.size();
1039 if (i == -1) i0 = imax;
1041 double is = sqrt(s.is2);
1042 return {s.dr * is, -s.dz * is};
1048 zr_t dist = {r.z - s.z, r.r - s.r};
1049 double dist2 = dist.z * dist.z + dist.r * dist.r;
1050 if (dist2 > 1e-18) {
1051 double q = 1 / sqrt(dist2);
1052 if (wn_poly(r) == 2) q = -q;
1053 return {dist.z * q, dist.r * q};
1055 zr_t n = getn(iseg), np = getn(iseg - 1);
1056 n.z += np.z; n.r += np.r;
1057 double n2 = n.z * n.z + n.r * n.r;
1058 double q = 1 / sqrt(n2);
1068 G4ThreeVector BelleLathe::SurfaceNormal(
const G4ThreeVector& p)
const
1072 auto side = [
this](
const zr_t & r,
double d,
int iside) {
1073 double nx = (iside) ? fn1x : fn0x, ny = (iside) ? fn1y : fn0y;
1074 if (wn_poly(r) == 2)
return G4ThreeVector(nx, ny, 0);
1075 double cphi = (iside) ? fc1 : fc0, sphi = (iside) ? fs1 : fc0;
1077 double d2;
zr_t n = normal(r, d2);
1078 double x = cphi * n.r, y = sphi * n.r;
1079 double u = sqrt(d2);
1083 double q = 1 / sqrt(d2);
1084 double cpsi = u * q, spsi = d * q;
1085 res.set(x * cpsi - y * spsi, x * spsi + y * cpsi, n.z);
1092 zr_t r = {p.z(), p.perp()};
1093 double d2;
zr_t n = normal(r, d2);
1094 double d = sqrt(d2);
1095 double pt = hypot(p.x(), p.y());
1098 double ir = n.r / pt;
1099 res = G4ThreeVector(ir * p.x(), ir * p.y(), n.z);
1101 res = G4ThreeVector(n.r, 0, n.z);
1104 double d0 = fn0x * p.x() + fn0y * p.y();
1105 double d1 = fn1x * p.x() + fn1y * p.y();
1106 zr_t r0 = {p.z(), fc0 * p.x() + fs0 * p.y()};
1107 zr_t r1 = {p.z(), fc1 * p.x() + fs1 * p.y()};
1109 if (d0 > 0 && d1 > 0) {
1111 res = side(r0, d0, 0);
goto exit;
1113 res = side(r1, -d1, 1);
goto exit;
1116 if (wn_poly(r) == 2) {
1117 if (abs(d0) < d && abs(d0) < abs(d1)) { res = G4ThreeVector(fn0x, fn0y, 0);
goto exit;}
1118 if (abs(d1) < d && abs(d1) < abs(d0)) { res = G4ThreeVector(fn1x, fn1y, 0);
goto exit;}
1122 if (d0 > 0 || d1 > 0) {
1124 res = side(r1, -d1, 1);
goto exit;
1126 res = side(r0, d0, 0);
goto exit;
1129 if (wn_poly(r) == 2) {
1130 if (abs(d0) < d && abs(d0) < abs(d1)) { res = G4ThreeVector(fn0x, fn0y, 0);
goto exit;}
1131 if (abs(d1) < d && abs(d1) < abs(d0)) { res = G4ThreeVector(fn1x, fn1y, 0);
goto exit;}
1138 G4ThreeVector dd = fshape->SurfaceNormal(p);
1139 if ((res - dd).mag() > 1e-11) {
1140 int oldprec = cout.precision(16);
1141 EInside inside = fshape->Inside(p);
1142 cout << GetName() <<
" SurfaceNormal(p) " << p <<
" " << res <<
" " << dd <<
" " << res - dd <<
" " << inside << endl;
1143 cout.precision(oldprec);
1147 MATCHOUT(
"BelleLathe::SurfaceNormal(p,n) " << p <<
" res= " << res);
1154 G4double BelleLathe::DistanceToIn(
const G4ThreeVector& p)
const
1160 zr_t r = {p.z(), p.perp()};
1161 d = max(mindist(r), 0.0);
1163 double d0 = fn0x * p.x() + fn0y * p.y();
1164 double d1 = fn1x * p.x() + fn1y * p.y();
1167 if (d0 > 0 && d1 > 0) {
1169 zr_t r = {p.z(), -fn0y * p.x() + fn0x * p.y()};
1170 d = sqrt(pow(max(mindist(r), 0.0), 2) + d0 * d0);
1172 zr_t r = {p.z(), fn1y * p.x() - fn1x * p.y()};
1173 d = sqrt(pow(max(mindist(r), 0.0), 2) + d1 * d1);
1176 zr_t r = {p.z(), p.perp()};
1177 d = max(mindist(r), 0.0);
1180 if (d0 > 0 || d1 > 0) {
1182 zr_t r = {p.z(), fn1y * p.x() - fn1x * p.y()};
1183 d = sqrt(pow(max(mindist(r), 0.0), 2) + d1 * d1);
1185 zr_t r = {p.z(), -fn0y * p.x() + fn0x * p.y()};
1186 d = sqrt(pow(max(mindist(r), 0.0), 2) + d0 * d0);
1189 zr_t r = {p.z(), p.perp()};
1190 d = max(mindist(r), 0.0);
1196 double dd = fshape->DistanceToIn(p);
1198 if (dd > d && abs(d - dd) > kCarTolerance) {
1199 int oldprec = cout.precision(16);
1200 EInside inside = fshape->Inside(p);
1201 zr_t r = {p.z(), p.perp()};
1202 cout << GetName() <<
" DistanceToIn(p) " << p <<
" " << r <<
" " << d <<
" " << dd <<
" " << d - dd <<
" " << inside << endl;
1203 cout.precision(oldprec);
1207 MATCHOUT(
"BelleLathe::DistanceToIn(p) " << p <<
" res= " << d);
1213 G4double BelleLathe::DistanceToOut(
const G4ThreeVector& p)
const
1217 zr_t r = {p.z(), p.perp()};
1218 double d = mindist(r);
1220 double d0 = fn0x * p.x() + fn0y * p.y();
1221 double d1 = fn1x * p.x() + fn1y * p.y();
1223 d = max(d, min(d0, d1));
1225 d = max(d, max(d0, d1));
1230 double dd = fshape->Inside(p) == 0 ? 0.0 : fshape->DistanceToOut(p);
1231 if (abs(d - dd) > kCarTolerance) {
1232 int oldprec = cout.precision(16);
1233 zr_t r = {p.z(), p.perp()};
1235 cout << GetName() <<
" DistanceToOut(p) " << p <<
" " << r <<
" " << d <<
" " << dd <<
" " << d - dd << endl;
1236 cout.precision(oldprec);
1239 MATCHOUT(
"BelleLathe::DistanceToOut(p) " << p.x() <<
" " << p.y() <<
" " << p.z() <<
" res= " << d);
1244 G4double BelleLathe::DistanceToIn(
const G4ThreeVector& p,
const G4ThreeVector& n)
const
1247 auto getnormal = [
this, &p, &n](
int i,
double t) ->G4ThreeVector{
1248 const int imax = fcache.size();
1252 }
else if (i < imax)
1256 o.setZ(copysign(1, s.dr));
1258 double x = p.x() + n.x() * t;
1259 double y = p.y() + n.y() * t;
1260 double sth = s.dr * s.is, cth = -s.dz * s.is;
1261 double ir = cth / sqrt(x * x + y * y);
1262 o.set(x * ir, y * ir, sth);
1264 }
else if (i == imax)
1266 o.setX(fn0x), o.setY(fn0y);
1268 o.setX(fn1x), o.setY(fn1y);
1273 auto hitside = [
this, &p, &n](
double t,
const cachezr_t& s) ->
bool {
1274 double z = p.z() + n.z() * t;
1276 bool k = s.zmin < z && z <= s.zmax;
1279 double x = p.x() + n.x() * t;
1280 double y = p.y() + n.y() * t;
1281 k = k && insector(x, y);
1286 auto hitzside = [
this, &p, &n](
double t,
const cachezr_t& s) ->
bool {
1287 double x = p.x() + n.x() * t;
1288 double y = p.y() + n.y() * t;
1289 double r2 = x * x + y * y;
1290 bool k = s.r2min <= r2 && r2 < s.r2max;
1293 k = k && insector(x, y);
1298 auto hitphi0side = [
this, &p, &n](
double t) ->
bool {
1299 double x = p.x() + n.x() * t;
1300 double y = p.y() + n.y() * t;
1301 double r = x * fc0 + y * fs0;
1304 double z = p.z() + n.z() * t;
1306 return wn_poly(zr) == 2;
1311 auto hitphi1side = [
this, &p, &n](
double t) ->
bool {
1312 double x = p.x() + n.x() * t;
1313 double y = p.y() + n.y() * t;
1314 double r = x * fc1 + y * fs1;
1317 double z = p.z() + n.z() * t;
1319 return wn_poly(zr) == 2;
1324 double tmin = kInfinity;
1325 const int imax = fcache.size();
1326 int iseg = -1, isurface = -1;
1327 const double delta = 0.5 * kCarTolerance;
1328 double inz = 1 / n.z();
1329 double nn = dotxy(n, n), np = dotxy(n, p), pp = dotxy(p, p);
1330 double pz = p.z(), pr = sqrt(pp);
1331 for (
int i = 0; i < imax; i++) {
1333 double dz = pz - s.z, dr = pr - s.r;
1334 double d = dz * s.dr - dr * s.dz;
1335 bool surface =
false;
1336 if (abs(d * s.is) < delta) {
1337 double dot = dz * s.dz + dr * s.dr;
1338 if (dot >= 0 && dot <= s.s2) {
1345 double t = -dz * inz;
1346 if (0 < t && t < tmin && hitzside(t, s)) { tmin = t; iseg = i;}
1357 double taz = s.ta * dz;
1358 double R = taz + s.r;
1361 double nzta = n.z() * s.ta;
1362 A = nzta * nzta - nn;
1366 double D = B * B + C * A;
1370 double sD = sqrt(D), sum = B + copysign(sD, B);
1371 double t0 = -C / sum, t1 = sum / A;
1373 if (abs(t0) > abs(t1)) {
1374 if (t0 > 0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1376 if (t1 > 0 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1379 if (t0 > 0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1380 if (t1 > 0 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1388 double vn = fn0x * n.x() + fn0y * n.y();
1390 double d = fn0x * p.x() + fn0y * p.y();
1392 if (hitphi0side(t)) {
1393 bool surface = std::abs(d) < delta;
1395 tmin = 0; iseg = imax + 0;
1397 if (0 < t && t < tmin) {tmin = t; iseg = imax + 0;}
1405 double vn = fn1x * n.x() + fn1y * n.y();
1407 double d = fn1x * p.x() + fn1y * p.y();
1409 if (hitphi1side(t)) {
1410 bool surface = std::abs(d) < delta;
1412 tmin = 0; iseg = imax + 1;
1414 if (0 < t && t < tmin) { tmin = t; iseg = imax + 1;}
1422 if (getnormal(iseg, tmin)*n > 0) tmin = 0;
1426 auto convex = [
this, imax](
int i) ->
bool{
1428 return fcache[i].isconvex;
1433 if (tmin >= 0 && tmin < kInfinity) {
1434 if (isurface >= 0)
if (convex(isurface) && getnormal(isurface, 0)*n >= 0) tmin = kInfinity;
1436 if (Inside(p) == kSurface) {
1437 if (isurface >= 0) {
1438 tmin = (getnormal(isurface, 0) * n >= 0) ? kInfinity : 0;
1445 double dd = fshape->DistanceToIn(p, n);
1446 if (abs(tmin - dd) > 1e-10) {
1447 int oldprec = cout.precision(16);
1448 EInside inside = fshape->Inside(p);
1449 cout << GetName() <<
" DistanceToIn(p,v) " << p <<
" " << n <<
" " << tmin <<
" " << dd <<
" " << tmin - dd <<
" " << inside <<
" "
1450 << Inside(p) <<
" iseg = " << iseg <<
" " << isurface << endl;
1451 if (isurface >= 0) cout << getnormal(isurface, 0) << endl;
1452 cout.precision(oldprec);
1455 tmin = max(0.0, tmin);
1456 MATCHOUT(
"BelleLathe::DistanceToIn(p,n) " << p <<
" " << n <<
" res= " << tmin);
1461 G4double BelleLathe::DistanceToOut(
const G4ThreeVector& p,
const G4ThreeVector& n,
1462 const G4bool calcNorm, G4bool* IsValid, G4ThreeVector* _n)
const
1465 auto getnormal = [
this, &p, &n](
int i,
double t)->G4ThreeVector{
1466 const int imax = fcache.size();
1470 }
else if (i < imax)
1474 o.setZ(copysign(1, s.dr));
1476 double x = p.x() + n.x() * t;
1477 double y = p.y() + n.y() * t;
1478 double sth = s.dr * s.is, cth = -s.dz * s.is;
1479 double ir = cth / sqrt(x * x + y * y);
1480 o.set(x * ir, y * ir, sth);
1482 }
else if (i == imax)
1484 o.setX(fn0x), o.setY(fn0y);
1486 o.setX(fn1x), o.setY(fn1y);
1491 double nn = dotxy(n, n), np = dotxy(n, p), pp = dotxy(p, p);
1492 auto hitside = [
this, &p, &n, nn, np, pp](
double t,
const cachezr_t& s) ->
bool {
1493 double z = p.z() + n.z() * t;
1495 double dot = n.z() * s.dr * sqrt(pp + ((np + np) + nn * t) * t) - s.dz * (np + nn * t);
1496 bool k = s.zmin < z && z <= s.zmax && dot > 0;
1499 double x = p.x() + n.x() * t;
1500 double y = p.y() + n.y() * t;
1502 k = k && insector(x, y);
1507 auto hitzside = [
this, &p, &n](
double t,
const cachezr_t& s) ->
bool {
1508 double x = p.x() + n.x() * t;
1509 double y = p.y() + n.y() * t;
1510 double r2 = x * x + y * y;
1511 bool k = s.dr * n.z() > 0 && s.r2min <= r2 && r2 < s.r2max;
1514 k = k && insector(x, y);
1519 auto hitphi0side = [
this, &p, &n](
double t) ->
bool {
1520 double x = p.x() + n.x() * t;
1521 double y = p.y() + n.y() * t;
1522 double r = x * fc0 + y * fs0;
1525 double z = p.z() + n.z() * t;
1527 return wn_poly(zr) == 2;
1532 auto hitphi1side = [
this, &p, &n](
double t) ->
bool {
1533 double x = p.x() + n.x() * t;
1534 double y = p.y() + n.y() * t;
1535 double r = x * fc1 + y * fs1;
1538 double z = p.z() + n.z() * t;
1540 return wn_poly(zr) == 2;
1546 double tmin = kInfinity;
1548 const int imax = fcache.size();
1549 int iseg = -1, isurface = -1;
1551 const double delta = 0.5 * kCarTolerance;
1552 double inz = 1 / n.z();
1553 double pz = p.z(), pr = sqrt(pp);
1555 for (
int i = 0; i < imax; i++) {
1558 double d = (pz - s.z) * s.dr - (pr - s.r) * s.dz;
1559 bool surface = abs(d * s.is) < delta;
1560 if (surface) isurface = i;
1562 double t = (s.z - p.z()) * inz;
1564 if (hitzside(t, s)) {tmin = 0; iseg = i;
break;}
1566 if (0 < t && t < tmin && hitzside(t, s)) {tmin = t; iseg = i;}
1577 double taz = s.ta * (p.z() - s.z);
1578 double R = taz + s.r;
1581 double nzta = n.z() * s.ta;
1582 A = nzta * nzta - nn;
1586 double D = B * B + C * A;
1588 double sD = sqrt(D);
1589 double sum = B + copysign(sD, B);
1590 double t0 = -C / sum, t1 = sum / A;
1593 if (abs(t0) < abs(t1)) {
1594 if (hitside(t0, s)) { tmin = 0; iseg = i;
break;}
1595 if (0 < t1 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1597 if (hitside(t1, s)) { tmin = 0; iseg = i;
break;}
1598 if (0 < t0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1601 if (0 < t0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1602 if (0 < t1 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1611 double vn = fn0x * n.x() + fn0y * n.y();
1613 double d = fn0x * p.x() + fn0y * p.y();
1615 if (hitphi0side(t)) {
1616 bool surface = std::abs(d) < delta;
1618 tmin = 0; iseg = imax + 0;
1620 if (0 < t && t < tmin) {tmin = t; iseg = imax + 0;}
1628 double vn = fn1x * n.x() + fn1y * n.y();
1630 double d = fn1x * p.x() + fn1y * p.y();
1632 if (hitphi1side(t)) {
1633 bool surface = std::abs(d) < delta;
1635 tmin = 0; iseg = imax + 1;
1637 if (0 < t && t < tmin) { tmin = t; iseg = imax + 1;}
1644 auto convex = [
this, imax](
int i) ->
bool{
1646 return fcache[i].isconvex;
1652 if (tmin >= 0 && tmin < kInfinity) {
1653 *_n = getnormal(iseg, tmin);
1654 *IsValid = convex(iseg);
1656 if (Inside(p) == kSurface) {
1657 if (isurface >= 0) {
1658 *_n = getnormal(isurface, tmin);
1659 *IsValid = convex(isurface);
1674 double dd = fshape->DistanceToOut(p, n, calcNorm, &isvalid, &norm);
1675 if (abs(tmin - dd) > 1e-10 || (calcNorm && *IsValid != isvalid)) {
1676 int oldprec = cout.precision(16);
1677 cout << GetName() <<
" DistanceToOut(p,v) p,n =" <<
curl_t(p) <<
curl_t(n) <<
" calcNorm=" << calcNorm
1678 <<
" myInside=" << Inside(p) <<
" tmin=" << tmin <<
" dd=" << dd <<
" d=" << tmin - dd <<
" iseg=" << iseg <<
" isurf=" << isurface
1680 if (calcNorm) cout <<
"myIsValid = " << *IsValid <<
" tIsValid=" << isvalid <<
" myn=" << (*_n) <<
" tn=" << (norm);
1682 cout.precision(oldprec);
1687 MATCHOUT(
"BelleLathe::DistanceToOut(p,n) " << p <<
" " << n <<
" res= " << tmin);
1691 void BelleLathe::eartrim()
const
1694 unsigned int n = fcontour.size();
1696 for (
unsigned int i = 0; i < n; i++) indx.push_back(i);
1698 while (indx.size() > 3 && ++count < 200) {
1699 unsigned int ni = indx.size();
1700 for (
unsigned int i = 0; i < ni; i++) {
1701 int i0 = indx[i], i1 = indx[(i + 1) % ni], i2 = indx[(i + 2) % ni];
1702 double nx = fcontour[i2].z - fcontour[i0].z;
1703 double ny = fcontour[i2].r - fcontour[i0].r;
1704 double d1 = nx * (fcontour[i1].r - fcontour[i0].r) - ny * (fcontour[i1].z - fcontour[i0].z);
1706 for (
unsigned int j = 0; j < ni - 3; j++) {
1707 int k = indx[(i + 3 + j) % ni];
1708 double d = nx * (fcontour[k].r - fcontour[i0].r) - ny * (fcontour[k].z - fcontour[i0].z);
1716 ftlist.push_back(t);
1717 indx.erase(indx.begin() + (i + 1) % ni);
1722 if (indx.size() == 3) {
1724 ftlist.push_back(t);
1728 void BelleLathe::getvolarea()
1731 for (
const cachezr_t& s : fcache) vol += s.dz * ((3 * s.r) * (s.r + s.dr) + s.dr * s.dr);
1732 fCubicVolume = -fdphi * vol / 6;
1734 double totalarea = 0;
1738 const zr_t& p0 = fcontour[t.i0], &p1 = fcontour[t.i1], &p2 = fcontour[t.i2];
1739 double area = (p1.z - p0.z) * (p2.r - p0.r) - (p1.r - p0.r) * (p2.z - p0.z);
1740 totalarea += abs(area);
1741 farea.push_back(totalarea);
1746 double area = fdphi * (s.r + 0.5 * s.dr) * sqrt(s.dz * s.dz + s.dr * s.dr);
1748 farea.push_back(totalarea);
1750 fSurfaceArea = farea.back();
1753 G4ThreeVector BelleLathe::GetPointOnSurface()
const
1755 auto GetPointOnTriangle = [
this](
const triangle_t& t)-> G4ThreeVector{
1757 double a1 = CLHEP::RandFlat::shoot(0., 1.), a2 = CLHEP::RandFlat::shoot(0., 1.);
1758 if (a1 + a2 > 1) { a1 = 1 - a1; a2 = 1 - a2;}
1759 double a0 = 1 - (a1 + a2);
1760 const zr_t& p0 = fcontour[t.i0], &p1 = fcontour[t.i1], &p2 = fcontour[t.i2];
1761 zr_t p = {p0.z* a0 + p1.z* a1 + p2.z * a2, p0.r* a0 + p1.r* a1 + p2.r * a2};
1763 if (CLHEP::RandFlat::shoot(0., 1.) > 0.5)
1765 c = -fn0y; s = fn0x;
1767 c = fn1y; s = -fn1x;
1769 G4ThreeVector r1(p.r * c, p.r * s, p.z);
1773 double rnd = CLHEP::RandFlat::shoot(0., farea.back());
1774 std::vector<double>::const_iterator it = std::lower_bound(farea.begin(), farea.end(), rnd);
1775 unsigned int i = it - farea.begin();
1778 if (i < ftlist.size()) {
1779 return GetPointOnTriangle(ftlist[i]);
1786 double I = 2 * s.r + s.dr;
1787 double Iw = CLHEP::RandFlat::shoot(0., I);
1788 double q = sqrt(Iw * s.dr + s.r * s.r);
1789 double t = Iw / (q + s.r);
1790 double z = s.z + s.dz * t;
1791 double r = s.r + s.dr * t;
1792 double phi = CLHEP::RandFlat::shoot(fphi, fphi + fdphi);
1793 double x = r * cos(phi), y = r * sin(phi);
1794 return G4ThreeVector(x, y, z);
1798 G4GeometryType BelleLathe::GetEntityType()
const
1800 return G4String(
"BelleLathe");
1804 G4VSolid* BelleLathe::Clone()
const
1810 std::ostream& BelleLathe::StreamInfo(std::ostream& os)
const
1812 G4int oldprc = os.precision(16);
1813 os <<
"-----------------------------------------------------------\n"
1814 <<
" *** Dump for solid - " << GetName() <<
" ***\n"
1815 <<
" ===================================================\n"
1816 <<
" Solid type: BelleLathe\n"
1817 <<
" Contour: " << fcontour.size() <<
" sides, {z, r} points \n";
1818 for (
int i = 0, imax = fcontour.size(); i < imax; i++) {
1819 os << fcontour[i] <<
", ";
1822 for (
int i = 0, imax = fcontour.size(); i < imax; i++) {
1823 os << fcache[i].isconvex <<
", ";
1826 os <<
"phi0 = " << fphi <<
", dphi = " << fdphi <<
", Full Circle = " << (ftwopi ?
"yes" :
"no") <<
"\n";
1827 double xmin = fzmin - 0.05 * (fzmax - fzmin), xmax = fzmax + 0.05 * (fzmax - fzmin);
1828 double ymin = frmin - 0.05 * (frmax - frmin), ymax = frmax + 0.05 * (frmax - frmin);
1829 os <<
" BB: " << xmin <<
", " << xmax <<
", " << ymin <<
", " << ymax << endl;
1830 os <<
"-----------------------------------------------------------\n";
1831 os.precision(oldprc);
1837 void BelleLathe::DescribeYourselfTo(G4VGraphicsScene& scene)
const
1839 scene.AddSolid(*
this);
1845 std::vector<vector_t> points;
1849 const double inf = std::numeric_limits<double>::infinity();
1850 G4ThreeVector minimum(inf, inf, inf), maximum(-inf, -inf, -inf);
1853 if (fdphi < 2 * M_PI) {
1854 point.x = frmax * cos(fphi); point.y = frmax * sin(fphi);
1855 points.push_back(point);
1856 point.x = frmax * cos(fphi + fdphi); point.y = frmax * sin(fphi + fdphi);
1857 points.push_back(point);
1861 point.x = frmin * cos(fphi); point.y = frmin * sin(fphi);
1862 points.push_back(point);
1864 point.x = frmin * cos(fphi + fdphi); point.y = frmin * sin(fphi + fdphi);
1865 points.push_back(point);
1871 if (insector(0, 1)) {
1872 point.x = 0; point.y = frmax;
1873 points.push_back(point);
1875 if (insector(-1, 0)) {
1876 point.x = -frmax; point.y = 0;
1877 points.push_back(point);
1879 if (insector(0, -1)) {
1880 point.x = 0; point.y = -frmax;
1881 points.push_back(point);
1883 if (insector(1, 0)) {
1884 point.x = frmax; point.y = 0;
1885 points.push_back(point);
1888 for (std::vector<vector_t>::size_type i = 0; i != points.size(); i++) {
1890 if (points[i].x < minimum.x())
1891 minimum.setX(points[i].x);
1894 if (points[i].y < minimum.y())
1895 minimum.setY(points[i].y);
1898 if (points[i].x > maximum.x())
1899 maximum.setX(points[i].x);
1902 if (points[i].y > maximum.y())
1903 maximum.setY(points[i].y);
1907 minimum.setZ(fzmin);
1908 maximum.setZ(fzmax);
1915 void takePolyhedron(
const HepPolyhedron& p)
1917 int i, nnode, iNodes[5], iVis[4], iFaces[4];
1919 for (
int iface = 1; iface <= p.GetNoFacets(); iface++) {
1920 p.GetFacet(iface, nnode, iNodes, iVis, iFaces);
1921 for (i = 0; i < nnode; i++) {
1922 if (iNodes[i] < 1 || iNodes[i] > p.GetNoVertices()) {
1925 <<
"BooleanProcessor::takePolyhedron : problem 1."
1928 if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets()) {
1931 <<
"BooleanProcessor::takePolyhedron : problem 2. "
1932 << i <<
" " << iFaces[i] <<
" " << p.GetNoFacets() << G4endl;
1940 int nphi = GetNumberOfRotationSteps();
1941 bool twopi = abs(dphi - 2 * M_PI) < 1e-6;
1946 AllocateMemory(nv, nf);
1948 auto vnum = [nphi, n](
int iphi,
int ip) {
1949 return (iphi % nphi) * n + (ip % n) + 1;
1953 double dfi = dphi / nphi;
1954 for (
int i = 0; i < nphi; i++) {
1955 double fi = phi + i * dfi;
1956 double cf = cos(fi), sf = sin(fi);
1957 for (
int j = 0; j < n; j++) pV[vnum(i, j)].set(v[j].r * cf, v[j].r * sf, v[j].z);
1958 for (
int j = 0; j < n; j++) pF[fcount++ ] = G4Facet(vnum(i, j), 0, vnum(i, j + 1), 0, vnum(i + 1, j + 1), 0, vnum(i + 1, j), 0);
1962 nphi = int(nphi * (dphi / (2 * M_PI)) + 0.5);
1963 nphi = nphi > 3 ? nphi : 3;
1968 int nf = n * (nphi - 1) + 2 * t.size();
1969 AllocateMemory(nv, nf);
1971 auto vnum = [n](
int iphi,
int ip) {
1972 return iphi * n + (ip % n) + 1;
1976 double dfi = dphi / (nphi - 1);
1977 for (
int i = 0; i < nphi; i++) {
1978 double fi = phi + i * dfi;
1979 double cf = cos(fi), sf = sin(fi);
1980 for (
int j = 0; j < n; j++) pV[vnum(i, j)].set(v[j].r * cf, v[j].r * sf, v[j].z);
1981 if (i == nphi - 1)
break;
1982 for (
int j = 0; j < n; j++) pF[fcount++] = G4Facet(vnum(i, j), 0, vnum(i, j + 1), 0, vnum(i + 1, j + 1), 0, vnum(i + 1, j), 0);
1985 for (
const triangle_t& k : t) pF[fcount++] = G4Facet(vnum(0, k.i0), 0, vnum(0, k.i2), 0, vnum(0, k.i1), 0, 0, 0);
1987 for (
const triangle_t& k : t) pF[fcount++] = G4Facet(vnum(i, k.i0), 0, vnum(i, k.i1), 0, vnum(i, k.i2), 0, 0, 0);
1996 G4Polyhedron* BelleLathe::CreatePolyhedron()
const
2003 #include <immintrin.h>
2004 double mindistsimd(
const zr_t& r,
const vector<cachezr_t>& contour)
2006 double d = kInfinity;
2007 int i = 0, n = contour.size();
2008 __m128d zero = _mm_set_sd(0);
2009 __m128d one = _mm_set_sd(1);
2013 double dz = r.z - s.z, dr = r.r - s.r;
2014 double crs = s.dr * dz - s.dz * dr;
2015 double dot = s.dz * dz + s.dr * dr;
2017 __m128d crssd = _mm_set_sd(crs);
2018 __m128d maskgt = _mm_cmpgt_sd(crssd, zero);
2019 __m128d masklt = _mm_cmplt_sd(crssd, zero);
2020 __m128d left = _mm_sub_sd(_mm_and_pd(maskgt, one), _mm_and_pd(masklt, one));
2021 __m128d z = _mm_set_sd(s.z);
2022 __m128d mask = _mm_and_pd(_mm_cmple_sd(_mm_set_sd(s.zmin), z), _mm_cmplt_sd(z, _mm_set_sd(s.zmax)));
2023 left = _mm_and_pd(mask, left);
2024 double du = dz * dz + dr * dr;
2025 double dv = crs * crs * s.is2;
2027 masklt = _mm_cmplt_sd(_mm_set_sd(dot), zero);
2028 maskgt = _mm_cmpgt_sd(_mm_set_sd(dot), _mm_set_sd(s.s2));
2030 __m128d uu = _mm_or_pd(_mm_and_pd(maskgt, _mm_set_sd(kInfinity)), _mm_andnot_pd(maskgt, _mm_set_sd(dv)));
2031 __m128d vv = _mm_or_pd(_mm_and_pd(masklt, _mm_set_sd(min(d, du))), _mm_andnot_pd(masklt, _mm_set_sd(min(d, uu[0]))));
2036 d = (wn == 2) ? -d : d;
2041 inline int left(
const zr_t& r0,
const zr_t& r1,
const zr_t& r)
2043 double d = (r1.z - r0.z) * (r.r - r0.r) - (r.z - r0.z) * (r1.r - r0.r);
2044 return (d > 0) - (d < 0);
2047 inline int checkside(
const zr_t& s0,
const zr_t& s1,
const zr_t& r)
2049 double zmin = min(s0.z, s1.z), zmax = max(s0.z, s1.z);
2050 if (zmin <= r.z && r.z < zmax)
return left(s0, s1, r);
2054 int wn_poly(
const zr_t& r,
const vector<zr_t>& contour)
2057 int i = 0, n = contour.size() - 1;
2059 wn += checkside(contour[i], contour[i + 1], r);
2061 wn += checkside(contour[n], contour[0], r);
2065 double mindist(
const zr_t& r,
const vector<zr_t>& contour)
2068 double d = kInfinity;
2069 auto dist = [&contour, &d, &r, &wn](
int i0,
int i1)->
void {
2070 const zr_t& s0 = contour[i0], &s1 = contour[i1];
2071 double zmin = min(s0.z, s1.z), zmax = max(s0.z, s1.z);
2072 double sz = s1.z - s0.z, sr = s1.r - s0.r;
2073 double dz = r.z - s0.z, dr = r.r - s0.r;
2074 double crs = dz * sr - sz * dr;
2075 if (zmin <= r.z && r.z < zmax) wn -= (crs > 0) - (crs < 0);
2076 double dot = sz * dz + sr * dr;
2077 double s2 = sz * sz + sr * sr;
2078 if (dot > s2)
return;
2081 double d2 = dz * dz + dr * dr;
2084 d = min(d, crs* crs / s2);
2088 int i = 0, n = contour.size() - 1;
2089 do {dist(i, i + 1);}
while (++i < n);
2092 d = (wn == 2) ? -d : d;
2098 double mindist(
const zr_t& r,
const vector<cachezr_t>& contour)
2100 double d = kInfinity;
2101 int wn = 0, i = 0, n = contour.size();
2104 double dz = r.z - s.z, dr = r.r - s.r;
2105 double crs = s.dr * dz - s.dz * dr;
2106 double dot = s.dz * dz + s.dr * dr;
2107 if (s.zmin <= r.z && r.z < s.zmax) wn -= (crs > 0) - (crs < 0);
2108 if (dot > s.s2)
continue;
2110 d = min(d, dz * dz + dr * dr);
2112 d = min(d, crs * crs * s.is2);
2118 d = (wn == 2) ? -d : d;
BelleLathe & operator=(const BelleLathe &rhs)
assignment operator
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Two vectors define an axis-parallel bounding box for the shape.
virtual ~BelleLathe()
Destructor.
BelleLathe(const G4String &pName)
Constructor for "nominal" BelleLathe whose parameters are to be set by a G4VPVParamaterisation later.
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
calculate the extent of the volume
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
compute the dimensions
virtual ~PolyhedronBelleLathe()
destructor
PolyhedronBelleLathe(const std::vector< zr_t > &, const std::vector< triangle_t > &, double, double)
constructor
std::ostream & operator<<(std::ostream &output, const IntervalOfValidity &iov)
TString rn()
Get random string.
Abstract base class for different kinds of events.
struct for a three vector