Bug Summary

File:ecl/geometry/src/BelleLathe.cc
Warning:line 1031, column 33
Value stored to 't' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name BelleLathe.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/data/b2soft/buildbot/development/build -fcoverage-compilation-dir=/data/b2soft/buildbot/development/build -resource-dir /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/lib/clang/21 -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/include/c++ -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/include/c++/x86_64-redhat-linux -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/include/c++/backward -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/include -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/include/python3.12 -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/include/CLHEP -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/include/Geant4 -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/include -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/include/root -isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/include/belle_legacy -I include/ -D _PACKAGE_="ecl" -D G4UI_USE_TCSH -D RaveDllExport= -D HAS_SQLITE -D HAS_CALLGRIND -I include -I /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/include/libxml2 -internal-isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/bin/../lib64/gcc/x86_64-redhat-linux/15.2.0/../../../../include/c++ -internal-isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/bin/../lib64/gcc/x86_64-redhat-linux/15.2.0/../../../../include/c++/x86_64-redhat-linux -internal-isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/bin/../lib64/gcc/x86_64-redhat-linux/15.2.0/../../../../include/c++/backward -internal-isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /cvmfs/belle.cern.ch/el9/externals/v02-04-00/Linux_x86_64/common/bin/../lib64/gcc/x86_64-redhat-linux/15.2.0/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-missing-braces -Wno-unused-command-line-argument -std=c++20 -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /scan_build/2026-05-31-004316-385593-1 -x c++ ecl/geometry/src/BelleLathe.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9/* Own header. */
10#include <ecl/geometry/BelleLathe.h>
11
12/* Geant4 headers. */
13#include <G4AffineTransform.hh>
14#include <G4VoxelLimits.hh>
15#include <G4VGraphicsScene.hh>
16#include <G4VPVParameterisation.hh>
17
18/* CLHEP headers. */
19#include <CLHEP/Random/RandFlat.h>
20
21using namespace std;
22using namespace Belle2;
23using namespace ECL;
24
25#define COMPARE0 0
26#define PERFCOUNTER0 0
27#if PERFCOUNTER0==1
28typedef int counter_t[6];
29map<string, counter_t> counterl;
30#define COUNTER(x) counterl[GetName()][x]++
31//#define MATCHOUT(x) //if(GetName().find("sv_crystalcontainersolid")==0) cout<<x<<endl;
32#else
33#define COUNTER(x)
34//
35#endif
36
37//#define MATCHOUT(x) G4cout<<GetName()<<" "<<x<<G4endl;
38#define MATCHOUT(x)
39
40/** define plane struct */
41struct Plane_t {
42 G4ThreeVector n; /**< Normal unit vector (x,y,z) */
43 double d; /**< offset (d) */
44 // => n.x*x + n.y*y + n.z*z + d = 0
45};
46
47namespace Belle2 {
48 namespace ECL {
49 inline double dotxy(const G4ThreeVector& p, const G4ThreeVector& n)
50 {
51 return p.x() * n.x() + p.y() * n.y();
52 }
53 }
54}
55
56ostream& operator <<(ostream& o, const zr_t& v)
57{
58 return o << "{" << v.z << ", " << v.r << "}";
59}
60
61/** curl struct */
62struct curl_t {
63 G4ThreeVector v; /**< vector */
64 /** constructor */
65 explicit curl_t(const G4ThreeVector& _v): v(_v) {}
66};
67
68ostream& operator <<(ostream& o, const curl_t& c)
69{
70 return o << "{" << c.v.x() << ", " << c.v.y() << ", " << c.v.z() << "}, ";
71}
72
73
74BelleLathe::BelleLathe(const G4String& pName, double phi0, double dphi, const vector<zr_t>& c)
75 : G4CSGSolid(pName)
76{
77 Init(c, phi0, dphi);
78}
79
80BelleLathe::BelleLathe(const G4String& pName, double phi0, double dphi, int n, double* z, double* rin, double* rout)
81 : G4CSGSolid(pName)
82{
83 vector<zr_t> contour;
84 for (int i = 0; i < n; i++) {
85 zr_t t = {z[i], rin[i]};
86 contour.push_back(t);
87 }
88 for (int i = n - 1; i >= 0; i--) {
89 zr_t t = {z[i], rout[i]};
90 contour.push_back(t);
91 }
92
93 Init(contour, phi0, dphi);
94}
95
96void BelleLathe::Init(const vector<zr_t>& c, double phi0, double dphi)
97{
98 vector<zr_t> contour = c;
99 // remove duplicated vertices
100 do {
101 vector<zr_t>::iterator it0 = contour.begin(), it1 = it0 + 1;
102 for (; it1 != contour.end();) {
103 const zr_t& s0 = *it0, &s1 = *it1;
104 if (abs(s0.z - s1.z) < kCarTolerance && abs(s0.r - s1.r) < kCarTolerance)
105 it1 = contour.erase(it1);
106 else {
107 ++it0; ++it1;
108 }
109 }
110 const zr_t& s0 = *it0, &s1 = contour[0]; // cppcheck-suppress invalidContainer ; contour should be valid here
111 if (abs(s0.z - s1.z) < kCarTolerance && abs(s0.r - s1.r) < kCarTolerance) contour.erase(it0);
112 } while (0);
113
114 // remove vertices on the same line
115 do {
116 vector<zr_t>::iterator it0 = contour.begin(), it1 = it0 + 1, it2 = it1 + 1;
117 for (; it0 != contour.end();) {
118 const zr_t& s0 = *it0, &s1 = *it1, &s2 = *it2;
119 double dr2 = s2.r - s0.r, dz2 = s2.z - s0.z;
120 double d = (s1.z - s0.z) * dr2 - (s1.r - s0.r) * dz2;
121
122 if (d * d < kCarTolerance * kCarTolerance * (dr2 * dr2 + dz2 * dz2)) {
123 it1 = contour.erase(it1);
124 it2 = it1;
125 if (++it2 >= contour.end()) it2 = contour.begin();
126 it0 = it1;
127 if (--it0 < contour.begin()) it0 = (++contour.rbegin()).base();
128
129 } else {
130 ++it0;
131 if (++it1 >= contour.end()) it1 = contour.begin();
132 if (++it2 >= contour.end()) it2 = contour.begin();
133 }
134
135 }
136 } while (0);
137
138 double sum = 0;
139 zr_t p0 = contour[0];
140 for (int i = 1, imax = contour.size(); i < imax; i++) {
141 zr_t p1 = contour[i];
142 sum += (p1.z - p0.z) * (p1.r + p0.r);
143 p0 = p1;
144 }
145 zr_t p1 = contour[0];
146 sum += (p1.z - p0.z) * (p1.r + p0.r);
147
148 // If contour is Clockwise: reverse contour
149 if (sum > 0)
150 std::reverse(contour.begin(), contour.end());
151
152 fcontour = contour;
153
154 auto convexside = [this](cachezr_t& s, double eps) -> void {
155 s.isconvex = false;
156 if (s.dz > 0) return;
157 vector<zr_t>::const_iterator it = fcontour.begin();
158 double a = s.dz * s.is, b = s.dr * s.is, cc = b * s.z - a * s.r;
159 bool dp = false, dm = false;
160 s.isconvex = true;
161 do
162 {
163 const zr_t& p = *it;
164 double d = a * p.r - b * p.z + cc; // distance to line
165 dm = dm || (d < -eps);
166 dp = dp || (d > eps);
167 if (dm && dp) {s.isconvex = false; return;}
168 } while (++it != fcontour.end());
169 };
170
171 frmin = kInfinity;
172 frmax = -kInfinity;
173 fzmin = kInfinity;
174 fzmax = -kInfinity;
175 fcache.reserve(fcontour.size());
176 for (int i = 0, n = fcontour.size(); i < n; i++) {
177 const zr_t& s0 = fcontour[i], &s1 = fcontour[(i + 1) % n];
178 cachezr_t t;
179 t.z = s0.z;
180 t.r = s0.r;
181 t.dz = s1.z - s0.z;
182 t.dr = s1.r - s0.r;
183 t.s2 = t.dz * t.dz + t.dr * t.dr;
184 t.is2 = 1 / t.s2;
185 t.is = sqrt(t.is2);
186 t.zmin = min(s0.z, s1.z);
187 t.zmax = max(s0.z, s1.z);
188 t.r2min = pow(min(s0.r, s1.r), 2);
189 t.r2max = pow(max(s0.r, s1.r), 2);
190 t.ta = (s1.r - s0.r) / (s1.z - s0.z);
191 convexside(t, kCarTolerance);
192 fcache.push_back(t);
193
194 frmax = max(frmax, s0.r);
195 frmin = min(frmin, s0.r);
196 fzmax = max(fzmax, s0.z);
197 fzmin = min(fzmin, s0.z);
198 }
199
200 fphi = phi0;
201 fdphi = dphi;
202
203 fdphi = std::min(2 * M_PI3.14159265358979323846, fdphi);
204 fdphi = std::max(0.0, fdphi);
205 fc0 = cos(fphi);
206 fs0 = sin(fphi);
207 fc1 = cos(fphi + fdphi);
208 fs1 = sin(fphi + fdphi);
209
210 fn0x = fs0;
211 fn0y = -fc0;
212 fn1x = -fs1;
213 fn1y = fc1;
214 fgtpi = fdphi > M_PI3.14159265358979323846;
215 ftwopi = abs(fdphi - 2 * M_PI3.14159265358979323846) < kCarTolerance;
216
217 // cout << ftwopi << " " << fgtpi << " " << fn0y << " " << fn0x << " " << fn1y << " " << fn1x << endl;
218
219 for (int i = 0, n = fcontour.size(); i < n; i++) {
220 const zr_t& s = fcontour[i];
221 fz.push_back(s.z);
222 }
223 sort(fz.begin(), fz.end());
224 fz.erase(std::unique(fz.begin(), fz.end()), fz.end());
225
226 for (int i = 1, ni = fz.size(); i < ni; i++) {
227 double a = fz[i - 1], b = fz[i];
228 findx.push_back(fseg.size());
229 for (int j = 0, nj = fcache.size(); j < nj; j++) {
230 const cachezr_t& sj = fcache[j];
231 double cc = sj.zmin, d = sj.zmax;
232 if (cc != d and b > cc and d > a) { // overlap
233 fseg.push_back(j);
234 }
235 }
236 }
237 findx.push_back(fseg.size());
238
239 getvolarea();
240
241#if COMPARE0>0
242 auto getpolycone = [](const G4String & pName, double phi0, double dphi, const vector<zr_t>& c) -> G4GenericPolycone* {
243 vector<double> r, z;
244 r.reserve(c.size());
245 z.reserve(c.size());
246 for (int i = 0, imax = c.size(); i < imax; i++)
247 {
248 r.push_back(c[i].r);
249 z.push_back(c[i].z);
250 }
251 return new G4GenericPolycone(pName, phi0, dphi, c.size(), r.data(), z.data());
252 };
253 fshape = getpolycone(GetName(), phi0, dphi, fcontour);
254#else
255 fshape = nullptr;
256#endif
257// StreamInfo(G4cout);
258}
259
260// Nominal constructor for BelleLathe whose parameters are to be set by
261// a G4VParamaterisation later. Check and set half-widths as well as
262// angles: final check of coplanarity
263BelleLathe::BelleLathe(const G4String& pName)
264 : G4CSGSolid(pName)
265{
266 vector<zr_t> a;
267 Init(a, 0, 2 * M_PI3.14159265358979323846);
268}
269
270// Fake default constructor - sets only member data and allocates memory
271// for usage restricted to object persistency.
272BelleLathe::BelleLathe(__void__& a)
273 : G4CSGSolid(a)
274{
275 vector<zr_t> b;
276 Init(b, 0, 2 * M_PI3.14159265358979323846);
277}
278
279// Destructor
280BelleLathe::~BelleLathe()
281{
282#if PERFCOUNTER0==1
283 cout << GetName() << " ";
284 for (int i = 0; i < 6; i++) cout << counterl[GetName()][i] << " "; cout << endl;
285#endif
286}
287
288// Copy constructor
289BelleLathe::BelleLathe(const BelleLathe& rhs)
290 : G4CSGSolid(rhs), fcontour(rhs.fcontour), fcache(rhs.fcache), fz(rhs.fz),
291 findx(rhs.findx), fseg(rhs.fseg), farea(rhs.farea), ftlist(rhs.ftlist),
292 fphi(rhs.fphi), fdphi(rhs.fdphi), fs0(rhs.fs0), fc0(rhs.fc0), fs1(rhs.fs1),
293 fc1(rhs.fc1), fn0x(rhs.fn0x), fn0y(rhs.fn0y), fn1x(rhs.fn1x), fn1y(rhs.fn1y),
294 frmin(rhs.frmin), frmax(rhs.frmax), fzmin(rhs.fzmin), fzmax(rhs.fzmax),
295 fgtpi(rhs.fgtpi), ftwopi(rhs.ftwopi), fshape(rhs.fshape), fsurf(rhs.fsurf)
296{
297}
298
299// Assignment operator
300BelleLathe& BelleLathe::operator = (const BelleLathe& rhs)
301{
302 // Check assignment to self
303 if (this == &rhs) { return *this; }
304
305 // Copy base class data
306 G4CSGSolid::operator=(rhs);
307
308 // Copy data
309 fcontour = rhs.fcontour;
310 fcache = rhs.fcache;
311 fz = rhs.fz;
312 findx = rhs.findx;
313 fseg = rhs.fseg;
314 farea = rhs.farea;
315 ftlist = rhs.ftlist;
316 fphi = rhs.fphi;
317 fdphi = rhs.fdphi;
318 fs0 = rhs.fs0;
319 fc0 = rhs.fc0;
320 fs1 = rhs.fs1;
321 fc1 = rhs.fc1;
322 fn0x = rhs.fn0x;
323 fn0y = rhs.fn0y;
324 fn1x = rhs.fn1x;
325 fn1y = rhs.fn1y;
326 frmin = rhs.frmin;
327 frmax = rhs.frmax;
328 fzmin = rhs.fzmin;
329 fzmax = rhs.fzmax;
330 fgtpi = rhs.fgtpi;
331 ftwopi = rhs.ftwopi;
332 fshape = rhs.fshape;
333 fsurf = rhs.fsurf;
334 return *this;
335}
336
337
338// Dispatch to parameterisation for replication mechanism dimension
339// computation & modification.
340void BelleLathe::ComputeDimensions(G4VPVParameterisation*,
341 const G4int,
342 const G4VPhysicalVolume*)
343{
344 G4Exception("BelleLathe::ComputeDimensions()",
345 "GeomSolids0001", FatalException,
346 "BelleLathe does not support Parameterisation.");
347 // std::cout<<"ComputeDimensions"<<std::endl;
348 // p->ComputeDimensions(*this,n,pRep);
349}
350
351vector<double> quadsolve(double a, double b, double c)
352{
353 // solve equation a*t^2 + b*t + c = 0 taking care intermediate rounding errors
354 vector<double> t(2);
355 b *= 0.5;
356 double D = b * b - a * c;
357 if (D >= 0) {
358 double sD = sqrt(D);
359 double sum = b + ((b > 0) ? sD : -sD);
360 double t0 = -c / sum;
361 double t1 = -sum / a;
362 t[0] = t0;
363 t[1] = t1;
364 } else {
365 t.clear();
366 }
367
368 return t;
369}
370
371inline int quadsolve(double a, double b, double c, double& t0, double& t1)
372{
373 // solve equation a*t^2 + b*t + c = 0 taking care intermediate rounding errors
374 b *= 0.5;
375 double D = b * b - a * c;
376 if (D >= 0) {
377 double sD = sqrt(D);
378 double sum = b + ((b > 0) ? sD : -sD);
379 t0 = -c / sum;
380 t1 = -sum / a;
381 return 2;
382 }
383 return 0;
384}
385
386/** solution struct */
387struct solution_t {
388 double t; /**< t */
389 double s; /**< s */
390};
391vector<solution_t> extremum(double A, double B, double C, double D, double E, double F)
392{
393 // extremum of Fun(t,s) = A*t*t + B*t*s + C*s*s + D*t + E*s + F => dFun/ds = 0
394 vector<solution_t> res;
395 if (abs(B) < abs(A)) {
396 double a = 4 * A * C - B * B;
397 double b = 2 * (2 * A * E - B * D);
398 double c = 4 * A * F - D * D;
399 vector<double> ss = quadsolve(a, b, c);
400 for (auto s : ss) {
401 if (fpclassify(s) == FP_INFINITE1) continue;
402 double t = -(s * B + D) / (2 * A);
403 solution_t r = {t, s};
404 res.push_back(r);
405 }
406 } else {
407 double B2 = B * B, CD = C * D, BE = B * E;
408 double a = A * (4 * A * C - B2);
409 double b = 2 * A * (2 * CD - BE);
410 double c = D * (CD - BE) + B2 * F;
411 vector<double> ts = quadsolve(a, b, c);
412 for (auto t : ts) {
413 if (fpclassify(t) == FP_INFINITE1) continue;
414 double s = -(2 * t * A + D) / B;
415 solution_t r = {t, s};
416 res.push_back(r);
417 }
418 }
419 return res;
420}
421
422// calculate all ray solid's surface intersection return ordered vector
423vector<double> BelleLathe::linecross(const G4ThreeVector& p, const G4ThreeVector& n) const
424{
425 auto hitside = [this, &p, &n](double t, double zmin, double zmax) -> bool {
426 double z = p.z() + n.z() * t;
427 bool k = zmin < z && z <= zmax;
428 if (k && !ftwopi)
429 {
430 double x = p.x() + n.x() * t;
431 double y = p.y() + n.y() * t;
432 k = k && insector(x, y);
433 }
434 return k;
435 };
436
437 auto hitzside = [this, &p, &n](double t, double r2min, double r2max) -> bool {
438 double x = p.x() + n.x() * t;
439 double y = p.y() + n.y() * t;
440 double r2 = x * x + y * y;
441 bool k = r2min <= r2 && r2 < r2max;
442 if (k && !ftwopi)
443 {
444 k = k && insector(x, y);
445 }
446 return k;
447 };
448
449 vector<double> tc;
450 double inz = 1 / n.z();
451 double nn = Belle2::ECL::dotxy(n, n), np = dotxy(n, p), pp = dotxy(p, p);
452 for (const cachezr_t& s : fcache) { // loop over sides
453 if (s.dz == 0.0) { // z-plane
454 double t = (s.z - p.z()) * inz;
455 if (hitzside(t, s.r2min, s.r2max)) { tc.push_back(t); }
456 } else {
457 double ta = s.ta;
458 double A, B, R2;
459 if (s.dr == 0.0) { // cylinder
460 double R = s.r;
461 R2 = R * R;
462
463 A = -nn;
464 B = np;
465 } else { // cone
466 double taz = ta * (p.z() - s.z);
467 double R = taz + s.r;
468 R2 = R * R;
469
470 double nzta = n.z() * ta;
471 A = nzta * nzta - nn;
472 B = np - nzta * R;
473 }
474 double D = B * B + (pp - R2) * A;
475 if (D > 0) {
476 double sD = sqrt(D), iA = 1 / A;
477 double t0 = (B + sD) * iA, t1 = (B - sD) * iA;
478 if (hitside(t0, s.zmin, s.zmax)) tc.push_back(t0);
479 if (hitside(t1, s.zmin, s.zmax)) tc.push_back(t1);
480 }
481 }
482 }
483
484 if (!ftwopi) {
485 do { // side at phi0
486 double d = fn0x * p.x() + fn0y * p.y();
487 double vn = fn0x * n.x() + fn0y * n.y();
488 double t = -d / vn;
489 G4ThreeVector r = p + n * t;
490 zr_t zr = {r.z(), fc0 * r.x() + fs0 * r.y()};
491 if (vn != 0 && wn_poly(zr) == 2) tc.push_back(t);
492 } while (0);
493
494 do { // side at phi0+dphi
495 double d = fn1x * p.x() + fn1y * p.y();
496 double vn = fn1x * n.x() + fn1y * n.y();
497 double t = -d / vn;
498 G4ThreeVector r = p + n * t;
499 zr_t zr = {r.z(), fc1 * r.x() + fs1 * r.y()};
500 if (vn != 0 && wn_poly(zr) == 2) tc.push_back(t);
501 } while (0);
502 }
503
504 sort(tc.begin(), tc.end());
505 return tc;
506}
507
508// Calculate extent under transform and specified limit
509G4bool BelleLathe::CalculateExtent(const EAxis A,
510 const G4VoxelLimits& bb,
511 const G4AffineTransform& T,
512 G4double& pMin, G4double& pMax) const
513{
514 auto maxdist = [this](const G4ThreeVector & n) -> G4ThreeVector {
515 G4ThreeVector r;
516 int i = 0, nsize = fcache.size();
517 if (ftwopi || insector(n.x(), n.y())) // n in sector
518 {
519 double nr = hypot(n.x(), n.y()), nz = n.z();
520 double dmax = -kInfinity, R = 0, Z = 0;
521 do {
522 const cachezr_t& s = fcache[i];
523 double d1 = nz * s.z + nr * s.r;
524 if (dmax < d1) { R = s.r; Z = s.z; dmax = d1;}
525 } while (++i < nsize);
526 if (nr > 0) {
527 R /= nr;
528 r.set(R * n.x(), R * n.y(), Z);
529 } else {
530 double phi = fphi + 0.5 * fdphi;
531 r.set(R * cos(phi), R * sin(phi), Z);
532 }
533 } else
534 {
535 double dmax = -kInfinity;
536 do {
537 const cachezr_t& s = fcache[i];
538 // check both sides
539 G4ThreeVector rf(-fn0y * s.r, fn0x * s.r, s.z), rl(fn1y * s.r, -fn1x * s.r, s.z);
540 double d0 = rf * n, d1 = rl * n;
541 // cout<<rf<<" "<<rl<<endl;
542 if (dmax < d0) { r = rf; dmax = d0;}
543 if (dmax < d1) { r = rl; dmax = d1;}
544 } while (++i < nsize);
545 }
546 return r;
547 };
548
549 struct seg_t {int i0, i1;};
550 auto clip = [](vector<G4ThreeVector>& vlist, vector<seg_t>& slist, const G4ThreeVector & n, double dist) {
551 vector<seg_t> snew;
552 vector<int> lone;
553
554 vector<double> d;
555 for (const G4ThreeVector& v : vlist) d.push_back(v * n + dist);
556
557 for (seg_t s : slist) {
558 double prod = d[s.i0] * d[s.i1];
559 // cout<<d[s.i0]<<" "<<d[s.i1]<<endl;
560 if (prod < 0) { // segment crosses plane - break it
561 G4ThreeVector rn = (vlist[s.i0] * d[s.i1] - vlist[s.i1] * d[s.i0]) * (1 / (d[s.i1] - d[s.i0]));
562 lone.push_back(vlist.size()); vlist.push_back(rn);
563 if (d[s.i0] < 0) {
564 s = {lone.back(), s.i1};
565 } else {
566 s = {s.i0, lone.back()};
567 }
568 } else if (prod == 0) { // segment end on plane
569 if (d[s.i0] == 0 && d[s.i1] > 0) {
570 lone.push_back(s.i0);
571 } else if (d[s.i0] > 0 && d[s.i1] == 0) {
572 lone.push_back(s.i1);
573 } else continue;
574 } else {
575 if (d[s.i0] < 0) continue; // segment below plane
576 }
577 snew.push_back(s);
578 }
579
580 double dmax = -1e99;
581 int imax = -1, jmax = -1;
582 // search for the most distant points on the clipping plane
583 for (unsigned int i = 0; i < lone.size(); i++) {
584 for (unsigned int j = i + 1; j < lone.size(); j++) {
585 double d2 = (vlist[lone[i]] - vlist[lone[j]]).mag2();
586 if (d2 > dmax) { imax = lone[i]; jmax = lone[j];}
587 }
588 }
589
590 // close the new polygon by creating new segments
591 if (imax >= 0) {
592 G4ThreeVector k = vlist[jmax] - vlist[imax];
593 sort(lone.begin(), lone.end(), [&k, &vlist, &imax](int i, int j) {return k * (vlist[i] - vlist[imax]) < k * (vlist[j] - vlist[imax]);});
594
595 for (unsigned int i = 0; i < lone.size(); i += 2) {
596 seg_t t = {lone[i], lone[i + 1]};
597 for (const seg_t& s : snew) {
598 if (t.i1 == s.i0) { snew.push_back(t); break;}
599 if (t.i0 == s.i0) { swap(t.i0, t.i1); snew.push_back(t); break;}
600 }
601 }
602 }
603 swap(slist, snew);
604 };
605
606 auto PhiCrossN = [this, clip](const vector<Plane_t>& planes) {
607 // unordered clipped phi-sides vertices within
608 // limiting planes
609 vector<G4ThreeVector> vlist; // vertex list
610 vector<seg_t> slist; // segment list
611 vector<G4ThreeVector> res;
612
613 int nsize = fcache.size();
614 vlist.reserve(nsize);
615 slist.reserve(nsize);
616 for (int iphi = 0; iphi < 2; iphi++) {
617 vlist.clear();
618 slist.clear();
619 // phi-side directional vector is (kx,ky)
620 double kx = iphi ? -fn0y : fn1y, ky = iphi ? fn0x : -fn1x;
621 do {
622 int i = 0;
623 do {
624 const cachezr_t& s = fcache[i];
625 G4ThreeVector r(kx * s.r, ky * s.r, s.z);
626 vlist.push_back(r);
627 seg_t t = {i, i + 1};
628 slist.push_back(t);
629 } while (++i < nsize - 1);
630 const cachezr_t& s = fcache[nsize - 1];
631 G4ThreeVector r(kx * s.r, ky * s.r, s.z);
632 vlist.push_back(r);
633 seg_t t = {nsize - 1, 0};
634 slist.push_back(t);
635 } while (0);
636
637 // clip phi-side polygon by limiting planes
638 for (const Plane_t& p : planes) {
639 // cout<<p.n<<" "<<p.d<<endl;
640 clip(vlist, slist, p.n, p.d);
641 // for(auto t:vlist) cout<<t<<" "; cout<<endl;
642 }
643 vector<bool> bv(vlist.size(), false);
644
645 for (vector<seg_t>::const_iterator it = slist.begin(); it != slist.end(); ++it) {
646 bv[(*it).i0] = true;
647 bv[(*it).i1] = true;
648 }
649
650 for (unsigned int i = 0; i < vlist.size(); i++) {
651 if (!bv[i]) continue;
652 res.push_back(vlist[i]);
653 }
654 }
655 return res;
656 };
657
658 auto RCross = [this](const G4ThreeVector & op, const G4ThreeVector & k, const G4ThreeVector & u) {
659 // plane with origin at op and normal vector n = [k x u], k and u are orthogonal k*u = 0
660 // plane equation r = t*k + s*u + op
661 vector<solution_t> ts;
662 int nsize = fcache.size();
663 int i = 0;
664 do {
665 const cachezr_t& seg = fcache[i];
666 // r0 -- cone radius at z0, c -- cone axis
667 // cone equation is (r0 + tg * ((r-c0)*c))^2 = (r-c0)^2 - ((r-c0)*c)^2
668 double r0 = seg.r, z0 = seg.z, tg = seg.ta, tg2 = tg * tg;
669 double rtg = r0 * tg;
670
671 G4ThreeVector o(op.x(), op.y(), op.z() - z0);
672
673 double ko = k * o, uo = u * o, ck = k.z(), cu = u.z(), co = o.z();
674 double k2 = 1, u2 = 1, o2 = o * o;
675 double ck2 = ck * ck, cu2 = cu * cu, co2 = co * co;
676 double dr2 = r0 * r0 - o2;
677 if (seg.dz != 0.0) {
678 double q0 = 1 + tg2;
679 double q1 = co * q0 + rtg;
680
681 double F00 = co2 * q0 + 2 * co * rtg + dr2;
682 double F10 = 2 * (ck * q1 - ko);
683 double F20 = ck2 * q0 - k2;
684 double F01 = 2 * (cu * q1 - uo);
685 double F11 = 2 * ck * cu * q0;
686 double F02 = cu2 * q0 - u2;
687
688 vector<solution_t> res = extremum(F02, F11, F20, F01, F10, F00);
689 for (const solution_t& r : res) {
690 double t = r.s, s = r.t;
691 G4ThreeVector p = t * k + s * u + op;
692 if (seg.zmin < p.z() && p.z() < seg.zmax) {
693 solution_t e = {t, s};
694 if (ftwopi || insector(p.x(), p.y()))
695 ts.push_back(e);
696 }
697 }
698 }
699 double a = -(ck2 * u2 + cu2 * k2);
700 if (a != 0) {
701 if (abs(cu) > abs(ck)) {
702 double b = 2 * (ck * (cu * uo - co * u2) - cu2 * ko);
703 double c = co * (2 * cu * uo - co * u2) + cu2 * dr2;
704 vector<double> tv = quadsolve(a, b, c);
705 for (double t : tv) {
706 double s = -(co + ck * t) / cu;
707 G4ThreeVector p = t * k + s * u + op;
708 if (ftwopi || insector(p.x(), p.y())) {
709 solution_t e = {t, s};
710 ts.push_back(e);
711 }
712 }
713 } else {
714 double b = 2 * (cu * (ck * ko - co * k2) - ck2 * uo);
715 double c = co * (2 * ck * ko - co * k2) + ck2 * dr2;
716 vector<double> sv = quadsolve(a, b, c);
717 for (double s : sv) {
718 double t = -(co + cu * s) / ck;
719 G4ThreeVector p = t * k + s * u + op;
720 if (ftwopi || insector(p.x(), p.y())) {
721 solution_t e = {t, s};
722 ts.push_back(e);
723 }
724 }
725 }
726 }
727 } while (++i < nsize);
728 return ts;
729 };
730
731 bool b1 = false, b2 = false;
732 G4ThreeVector n0, n1, n2;
733 switch (A) {
734 case kXAxis: n0.set(1, 0, 0); n1.set(0, 1, 0); n2.set(0, 0, 1); b1 = bb.IsYLimited(); b2 = bb.IsZLimited(); break;
735 case kYAxis: n0.set(0, 1, 0); n1.set(1, 0, 0); n2.set(0, 0, 1); b1 = bb.IsXLimited(); b2 = bb.IsZLimited(); break;
736 case kZAxis: n0.set(0, 0, 1); n1.set(1, 0, 0); n2.set(0, 1, 0); b1 = bb.IsXLimited(); b2 = bb.IsYLimited(); break;
737 default: break;
738 }
739
740 double dmin1 = -kInfinity, dmax1 = kInfinity;
741 if (b1) {
742 switch (A) {
743 case kXAxis: dmin1 = bb.GetMinYExtent(); dmax1 = bb.GetMaxYExtent(); break;
744 case kYAxis: dmin1 = bb.GetMinXExtent(); dmax1 = bb.GetMaxXExtent(); break;
745 case kZAxis: dmin1 = bb.GetMinXExtent(); dmax1 = bb.GetMaxXExtent(); break;
746 default: break;
747 }
748 }
749
750 double dmin2 = -kInfinity, dmax2 = kInfinity;
751 if (b2) {
752 switch (A) {
753 case kXAxis: dmin2 = bb.GetMinZExtent(); dmax2 = bb.GetMaxZExtent(); break;
754 case kYAxis: dmin2 = bb.GetMinZExtent(); dmax2 = bb.GetMaxZExtent(); break;
755 case kZAxis: dmin2 = bb.GetMinYExtent(); dmax2 = bb.GetMaxYExtent(); break;
756 default: break;
757 }
758 }
759
760 G4AffineTransform iT = T.Inverse();
761 // axis to solid coordinates
762 G4ThreeVector n0t = iT.TransformAxis(n0);
763 G4ThreeVector smin = n0t * kInfinity, smax = (-kInfinity) * n0t; // extremum points in solid coordinate system
764 double pmin = kInfinity, pmax = -pmin;
765 if (b1 && b2) {
766 G4ThreeVector corners[] = {n1* dmin1 + n2 * dmin2, n1* dmax1 + n2 * dmin2, n1* dmax1 + n2 * dmax2, n1* dmin1 + n2 * dmax2};
767 for (G4ThreeVector& c : corners) iT.ApplyPointTransform(c); // to solid coordinates
768
769 vector<Plane_t> planes;
770 for (int i = 0; i < 4; i++) {
771 const G4ThreeVector& c0 = corners[i], &c1 = corners[(i + 1) % 4];
772 vector<double> dists = linecross(c0, n0t);
773 // cout<<"c0 "<<c0<<endl;
774 for (double t : dists) {
775 G4ThreeVector p = n0t * t + c0;
776 double tt = t + c0 * n0t;
777 // cout<<p<<" "<<tt<<endl;
778 if (pmax < tt) { pmax = tt; smax = p;}
779 if (pmin > tt) { pmin = tt; smin = p;}
780 }
781
782 G4ThreeVector u = c1 - c0, un = u.unit();
783 vector<solution_t> ts = RCross(c0, n0t, un);
784 double umax = u.mag();
785 for (solution_t r : ts) {
786 if (0 < r.s && r.s < umax) {
787 double tt = r.t + c0 * n0t;
788 G4ThreeVector p = n0t * r.t + un * r.s + c0;
789 // cout<<r.t<<" "<<r.s<<" "<<smax<<endl;
790 if (pmax < tt) { pmax = tt; smax = p;}
791 if (pmin > tt) { pmin = tt; smin = p;}
792 }
793 }
794 planes.push_back({ -un, un * c1});
795 }
796
797 vector<G4ThreeVector> vside = PhiCrossN(planes);
798 for (G4ThreeVector& p : vside) {
799 // cout<<p<<endl;
800 double tt = n0t * p;
801 if (pmax < tt) { pmax = tt; smax = p;}
802 if (pmin > tt) { pmin = tt; smin = p;}
803 }
804
805 } else if (b1 || b2) {
806 G4ThreeVector limits[2], u;
807 if (b1) {
808 limits[0] = n1 * dmin1;
809 limits[1] = n1 * dmax1;
810 u = iT.TransformAxis(n2);
811 } else {
812 limits[0] = n2 * dmin2;
813 limits[1] = n2 * dmax2;
814 u = iT.TransformAxis(n1);
815 }
816
817 for (G4ThreeVector& c : limits) iT.ApplyPointTransform(c); // to solid coordinates
818 for (int i = 0; i < 2; i++) {
819 vector<solution_t> ts = RCross(limits[i], n0t, u);
820 for (solution_t r : ts) {
821 double tt = r.t + limits[i] * n0t;
822 G4ThreeVector p = n0t * r.t + u * r.s + limits[i];
823 // cout<<r.t<<" "<<r.s<<" "<<endl;
824 if (pmax < tt) { pmax = tt; smax = p;}
825 if (pmin > tt) { pmin = tt; smin = p;}
826 }
827 }
828
829 vector<Plane_t> planes(2);
830 G4ThreeVector n;
831 if (b1) {
832 n = iT.TransformAxis(n1);
833 } else {
834 n = iT.TransformAxis(n2);
835 }
836 planes[0] = { n, -limits[0]* n};
837 planes[1] = { -n, limits[1]* n};
838 vector<G4ThreeVector> vside = PhiCrossN(planes);
839
840 for (G4ThreeVector& p : vside) {
841 // double t = n0t*(p-limits[0]);
842 double tt = n0t * p;
843 // cout<<tt<<" "<<p<<" "<<endl;
844 if (pmax < tt) { pmax = tt; smax = p;}
845 if (pmin > tt) { pmin = tt; smin = p;}
846 }
847 }
848 // maximal distance in +- directions
849 G4ThreeVector rp = maxdist(n0t), rm = maxdist(-n0t);
850 if (bb.Inside(T.TransformPoint(rm))) {
851 double tt = rm * n0t;
852 if (pmin > tt) {pmin = tt; smin = rm;}
853 }
854 if (bb.Inside(T.TransformPoint(rp))) {
855 double tt = rp * n0t;
856 if (pmax < tt) {pmax = tt; smax = rp;}
857 }
858
859 // to mother volume coordinate system
860 T.ApplyPointTransform(smin);
861 T.ApplyPointTransform(smax);
862 pmin = n0 * smin;
863 pmax = n0 * smax;
864
865 pmin -= kCarTolerance;
866 pmax += kCarTolerance;
867 // bool hit = pmin > -kInfinity && pmax < kInfinity;
868 bool hit = pmin < pmax;
869
870#if COMPARE0==10
871 auto surfhit = [this, &bb, &T, &n0, &n0t](double & pmin, double & pmax, bool print = false)->bool {
872 const int N = 1000 * 1000;
873 if (fsurf.size() == 0) for (int i = 0; i < N; i++) fsurf.push_back(GetPointOnSurface());
874
875 int umin = -1, umax = -1;
876 double wmin = 1e99, wmax = -1e99;
877 for (int i = 0; i < N; i++)
878 {
879 if (bb.Inside(T.TransformPoint(fsurf[i]))) {
880 double w = n0t * fsurf[i];
881 if (wmin > w) {wmin = w; umin = i;}
882 if (wmax < w) {wmax = w; umax = i;}
883 }
884 }
885 if (print)cout << umin << " " << umax << " " << wmin << " " << wmax << endl;
886 if (umin >= 0 && umax >= 0)
887 {
888 G4ThreeVector qmin = fsurf[umin], qmax = fsurf[umax];
889 T.ApplyPointTransform(qmin);
890 T.ApplyPointTransform(qmax);
891 pmin = n0 * qmin, pmax = n0 * qmax;
892 return true;
893 }
894 return false;
895 };
896
897 bool res = fshape->CalculateExtent(A, bb, T, pMin, pMax);
898 double srfmin = kInfinity, srfmax = -srfmin;
899 bool sHit = surfhit(srfmin, srfmax);
900 double diff = kCarTolerance;
901 diff = 10;
902 // if (abs(pmin - pMin) > diff || abs(pmax - pMax) > diff || hit != res) {
903 if ((abs(pmin - srfmin) > diff || abs(pmax - srfmax) > diff) && sHit) {
904 cout << "===================================\n";
905 cout << GetName() << " " << fcache.size() << " " << fphi << " " << fdphi << " " << ftwopi << "\n";
906 cout << hit << " " << res << " " << b1 << " " << b2 << "\n";
907 if (sHit) {
908 cout << "ss " << srfmin << " " << srfmax << "\n";
909 } else {
910 cout << "ss : not in bounding box" << "\n";
911 }
912 cout << "my " << pmin << " " << pmax << "\n";
913 cout << "tc " << pMin << " " << pMax << "\n";
914 cout << "df " << pmin - pMin << " " << pmax - pMax << "\n";
915 G4ThreeVector bmin(bb.GetMinXExtent(), bb.GetMinYExtent(), bb.GetMinZExtent());
916 G4ThreeVector bmax(bb.GetMaxXExtent(), bb.GetMaxYExtent(), bb.GetMaxZExtent());
917 cout << "Axis=" << A << " " << bmin << " " << bmax << " " << T << "\n";
918 cout << rp << " " << rm << "\n";
919 cout << smin << " " << smax << "\n";
920 cout << flush;
921 // _exit(0);
922 }
923 // cout<<endl;
924#endif
925 pMin = pmin;
926 pMax = pmax;
927
928 return hit;
929}
930
931// True if (x,y) is within the shape rotation
932inline bool BelleLathe::insector(double x, double y) const
933{
934 double d0 = fn0x * x + fn0y * y;
935 double d1 = fn1x * x + fn1y * y;
936 bool b0 = d0 < 0, b1 = d1 < 0;
937 return fgtpi ? b0 || b1 : b0 && b1;
938}
939
940int BelleLathe::wn_poly(const zr_t& r) const
941{
942 int wn = 0;
943 vector<double>::const_iterator it = upper_bound(fz.begin(), fz.end(), r.z);
944 // cout<<r<<" "<<fz.size()<<" "<<it-fz.begin()<<endl;
945 if (it != fz.begin() && it != fz.end()) {
946 int k = it - fz.begin();
947 for (int i = findx[k - 1]; i != findx[k]; i++) {
948 const cachezr_t& s = fcache[fseg[i]];
949 double dz = r.z - s.z, dr = r.r - s.r;
950 double crs = s.dr * dz - s.dz * dr;
951 wn -= (crs > 0) - (crs < 0);
952 }
953 }
954 return wn;
955}
956
957double BelleLathe::mindist(const zr_t& r) const
958{
959 double d = kInfinity;
960 int i = 0, n = fcache.size();
961 do {
962 const cachezr_t& s = fcache[i];
963 double dz = r.z - s.z, dr = r.r - s.r;
964 double dot = s.dz * dz + s.dr * dr; // projection of the point on the segment
965 if (dot < 0) {
966 d = min(d, dz * dz + dr * dr); // distance to the first point of the segment
967 } else if (dot <= s.s2) { // point should be within the segment
968 double crs = s.dr * dz - s.dz * dr;
969 d = min(d, crs * crs * s.is2);
970 }
971 } while (++i < n);
972 d = sqrt(d);
973 d = (wn_poly(r) == 2) ? -d : d;
974 return d;
975}
976
977// Return whether point inside/outside/on surface, using tolerance
978EInside BelleLathe::Inside(const G4ThreeVector& p) const
979{
980 COUNTER(0);
981 const double delta = 0.5 * kCarTolerance;
982 EInside res = kInside;
983 if (!ftwopi) {
984 double d0 = fn0x * p.x() + fn0y * p.y();
985 double d1 = fn1x * p.x() + fn1y * p.y();
986 if (fgtpi) {
987 if (d0 > delta && d1 > delta) { res = kOutside;}
988 else if (d0 > -delta && d1 > -delta) { res = kSurface;}
989 } else {
990 if (d0 > delta || d1 > delta) { res = kOutside;}
991 else if (d0 > -delta || d1 > -delta) { res = kSurface;}
992 }
993 }
994 if (res != kOutside) {
995 zr_t r = {p.z(), p.perp()};
996 double d = mindist(r);
997 if (res == kSurface && d < delta) res = kSurface;
998 else if (d > delta) res = kOutside;
999 else if (d > -delta) res = kSurface;
1000 else res = kInside;
1001 }
1002
1003#if COMPARE0==1
1004 EInside dd = fshape->Inside(p);
1005 if (1 || dd != res) {
1006 double d0 = fn0x * p.x() + fn0y * p.y();
1007 double d1 = fn1x * p.x() + fn1y * p.y();
1008 // if (abs(d0) > kCarTolerance && abs(d1) > kCarTolerance) {
1009 int oldprec = cout.precision(16);
1010 zr_t r = {p.z(), p.perp()};
1011 cout << GetName() << " Inside(p) " << p << " " << r << " my=" << res << " tc=" << dd <<
1012 " dist=" << mindist(r) << " " << d0 << " " << d1 << endl;
1013 cout.precision(oldprec);
1014 // }
1015 }
1016#endif
1017 MATCHOUT("BelleLathe::Inside(p) " << p << " res= " << res);
1018 return res;
1019}
1020
1021zr_t BelleLathe::normal(const zr_t& r, double& d2) const
1022{
1023 double d = std::numeric_limits<double>::infinity(), t = 0;
1024 int iseg = -1;
1025 for (int i = 0, imax = fcache.size(); i < imax; i++) {
1026 const cachezr_t& s = fcache[i];
1027 double dz = r.z - s.z, dr = r.r - s.r;
1028 double dot = s.dz * dz + s.dr * dr; // projection of the point on the segment
1029 if (dot < 0) {
1030 double dist = dz * dz + dr * dr; // distance to the first point of the segment
1031 if (dist < d) { d = dist; t = dot * s.is2; iseg = i;}
Value stored to 't' is never read
1032 } else if (dot <= s.s2) { // point should be within the segment
1033 double crs = s.dr * dz - s.dz * dr;
1034 double dist = crs * crs * s.is2;
1035 if (dist < d) { d = dist; t = dot * s.is2; iseg = i;}
1036 }
1037 }
1038 d2 = d;
1039
1040 auto getn = [this](int i)->zr_t{
1041 int imax = fcache.size();
1042 int i0 = i;
1043 if (i == -1) i0 = imax;
1044 const cachezr_t& s = fcache[i0];
1045 double is = sqrt(s.is2);
1046 return {s.dr * is, -s.dz * is};
1047 };
1048 return getn(iseg);
1049
1050 if (t < 0.0) {
1051 const cachezr_t& s = fcache[iseg];
1052 zr_t dist = {r.z - s.z, r.r - s.r};
1053 double dist2 = dist.z * dist.z + dist.r * dist.r;
1054 if (dist2 > 1e-18) {
1055 double q = 1 / sqrt(dist2);
1056 if (wn_poly(r) == 2) q = -q;
1057 return {dist.z * q, dist.r * q};
1058 } else {
1059 zr_t n = getn(iseg), np = getn(iseg - 1);
1060 n.z += np.z; n.r += np.r;
1061 double n2 = n.z * n.z + n.r * n.r;
1062 double q = 1 / sqrt(n2);
1063 n.z *= q, n.r *= q;
1064 return n;
1065 }
1066 }
1067 return getn(iseg);
1068}
1069
1070// Calculate side nearest to p, and return normal
1071// If 2+ sides equidistant, first side's normal returned (arbitrarily)
1072G4ThreeVector BelleLathe::SurfaceNormal(const G4ThreeVector& p) const
1073{
1074 COUNTER(1);
1075
1076 auto side = [this](const zr_t & r, double d, int iside) {
1077 double nx = (iside) ? fn1x : fn0x, ny = (iside) ? fn1y : fn0y;
1078 if (wn_poly(r) == 2) return G4ThreeVector(nx, ny, 0);
1079 double cphi = (iside) ? fc1 : fc0, sphi = (iside) ? fs1 : fc0;
1080
1081 double d2; zr_t n = normal(r, d2);
1082 double x = cphi * n.r, y = sphi * n.r;
1083 double u = sqrt(d2);
1084 d2 += d * d;
1085 G4ThreeVector res;
1086 if (d2 > 0) {
1087 double q = 1 / sqrt(d2);
1088 double cpsi = u * q, spsi = d * q;
1089 res.set(x * cpsi - y * spsi, x * spsi + y * cpsi, n.z);
1090 }
1091 res.set(x, y, n.z);
1092 return res;
1093 };
1094
1095 G4ThreeVector res;
1096 zr_t r = {p.z(), p.perp()};
1097 double d2; zr_t n = normal(r, d2);
1098 double d = sqrt(d2);
1099 double pt = hypot(p.x(), p.y());
1100
1101 if (pt > 0) {
1102 double ir = n.r / pt;
1103 res = G4ThreeVector(ir * p.x(), ir * p.y(), n.z);
1104 } else
1105 res = G4ThreeVector(n.r, 0, n.z);
1106
1107 if (!ftwopi) {
1108 double d0 = fn0x * p.x() + fn0y * p.y();
1109 double d1 = fn1x * p.x() + fn1y * p.y();
1110 zr_t r0 = {p.z(), fc0 * p.x() + fs0 * p.y()}; // projection on plane phi
1111 zr_t r1 = {p.z(), fc1 * p.x() + fs1 * p.y()}; // projection on plane phi+dphi
1112 if (fgtpi) {
1113 if (d0 > 0 && d1 > 0) { // outside sector
1114 if (d0 < d1) {
1115 res = side(r0, d0, 0); goto exit;
1116 } else {
1117 res = side(r1, -d1, 1); goto exit;
1118 }
1119 } else {// inside sector
1120 if (wn_poly(r) == 2) { // point p inside the solid
1121 if (abs(d0) < d && abs(d0) < abs(d1)) { res = G4ThreeVector(fn0x, fn0y, 0); goto exit;}
1122 if (abs(d1) < d && abs(d1) < abs(d0)) { res = G4ThreeVector(fn1x, fn1y, 0); goto exit;}
1123 }
1124 }
1125 } else {
1126 if (d0 > 0 || d1 > 0) { // outside sector
1127 if (d0 < 0) {
1128 res = side(r1, -d1, 1); goto exit;
1129 } else {
1130 res = side(r0, d0, 0); goto exit;
1131 }
1132 } else {
1133 if (wn_poly(r) == 2) { // point p inside the solid
1134 if (abs(d0) < d && abs(d0) < abs(d1)) { res = G4ThreeVector(fn0x, fn0y, 0); goto exit;}
1135 if (abs(d1) < d && abs(d1) < abs(d0)) { res = G4ThreeVector(fn1x, fn1y, 0); goto exit;}
1136 }
1137 }
1138 }
1139 }
1140exit:
1141#if COMPARE0==1
1142 G4ThreeVector dd = fshape->SurfaceNormal(p);
1143 if ((res - dd).mag() > 1e-11) {
1144 int oldprec = cout.precision(16);
1145 EInside inside = fshape->Inside(p);
1146 cout << GetName() << " SurfaceNormal(p) " << p << " " << res << " " << dd << " " << res - dd << " " << inside << endl;
1147 cout.precision(oldprec);
1148 // _exit(0);
1149 }
1150#endif
1151 MATCHOUT("BelleLathe::SurfaceNormal(p,n) " << p << " res= " << res);
1152 return res;
1153}
1154
1155// Calculate exact shortest distance to any boundary from outside
1156// This is the best fast estimation of the shortest distance to trap
1157// - Returns 0 is ThreeVector inside
1158G4double BelleLathe::DistanceToIn(const G4ThreeVector& p) const
1159{
1160 COUNTER(2);
1161 double d = 0;
1162 // int sector = 0, plane = 0;
1163 if (ftwopi) {
1164 zr_t r = {p.z(), p.perp()};
1165 d = max(mindist(r), 0.0);
1166 } else {
1167 double d0 = fn0x * p.x() + fn0y * p.y();
1168 double d1 = fn1x * p.x() + fn1y * p.y();
1169
1170 if (fgtpi) {
1171 if (d0 > 0 && d1 > 0) { // outside sector
1172 if (d0 < d1) {
1173 zr_t r = {p.z(), -fn0y * p.x() + fn0x * p.y()}; // projection on plane
1174 d = sqrt(pow(max(mindist(r), 0.0), 2) + d0 * d0);
1175 } else {
1176 zr_t r = {p.z(), fn1y * p.x() - fn1x * p.y()}; // projection on plane
1177 d = sqrt(pow(max(mindist(r), 0.0), 2) + d1 * d1);
1178 }
1179 } else {
1180 zr_t r = {p.z(), p.perp()};
1181 d = max(mindist(r), 0.0);
1182 }
1183 } else {
1184 if (d0 > 0 || d1 > 0) { // outside sector
1185 if (d0 < 0) {
1186 zr_t r = {p.z(), fn1y * p.x() - fn1x * p.y()}; // projection on plane
1187 d = sqrt(pow(max(mindist(r), 0.0), 2) + d1 * d1);
1188 } else {
1189 zr_t r = {p.z(), -fn0y * p.x() + fn0x * p.y()}; // projection on plane
1190 d = sqrt(pow(max(mindist(r), 0.0), 2) + d0 * d0);
1191 }
1192 } else {
1193 zr_t r = {p.z(), p.perp()};
1194 d = max(mindist(r), 0.0);
1195 }
1196 }
1197 }
1198#if COMPARE0==1
1199 // double dd = fshape->Inside(p) == 2 ? 0.0 : fshape->DistanceToIn(p);
1200 double dd = fshape->DistanceToIn(p);
1201 // if (abs(d - dd) > kCarTolerance) {
1202 if (dd > d && abs(d - dd) > kCarTolerance) {
1203 int oldprec = cout.precision(16);
1204 EInside inside = fshape->Inside(p);
1205 zr_t r = {p.z(), p.perp()};
1206 cout << GetName() << " DistanceToIn(p) " << p << " " << r << " " << d << " " << dd << " " << d - dd << " " << inside << endl;
1207 cout.precision(oldprec);
1208 // exit(0);
1209 }
1210#endif
1211 MATCHOUT("BelleLathe::DistanceToIn(p) " << p << " res= " << d);
1212 return d;
1213}
1214
1215// Calculate exact shortest distance to any boundary from inside
1216// - Returns 0 is ThreeVector outside
1217G4double BelleLathe::DistanceToOut(const G4ThreeVector& p) const
1218{
1219 // return ref->DistanceToOut(p);
1220 COUNTER(3);
1221 zr_t r = {p.z(), p.perp()};
1222 double d = mindist(r);
1223 if (!ftwopi) {
1224 double d0 = fn0x * p.x() + fn0y * p.y();
1225 double d1 = fn1x * p.x() + fn1y * p.y();
1226 if (fgtpi) {
1227 d = max(d, min(d0, d1));
1228 } else {
1229 d = max(d, max(d0, d1));
1230 }
1231 }
1232 d = max(-d, 0.0);
1233#if COMPARE0==1
1234 double dd = fshape->Inside(p) == 0 ? 0.0 : fshape->DistanceToOut(p);
1235 if (abs(d - dd) > kCarTolerance) {
1236 int oldprec = cout.precision(16);
1237 zr_t r = {p.z(), p.perp()};
1238 // cout<<r<<endl;
1239 cout << GetName() << " DistanceToOut(p) " << p << " " << r << " " << d << " " << dd << " " << d - dd << endl;
1240 cout.precision(oldprec);
1241 }
1242#endif
1243 MATCHOUT("BelleLathe::DistanceToOut(p) " << p.x() << " " << p.y() << " " << p.z() << " res= " << d);
1244 return d;
1245}
1246
1247// Calculate distance to shape from outside - return kInfinity if no intersection
1248G4double BelleLathe::DistanceToIn(const G4ThreeVector& p, const G4ThreeVector& n) const
1249{
1250 // return fshape->DistanceToIn(p, n);
1251 auto getnormal = [this, &p, &n](int i, double t) ->G4ThreeVector{
1252 const int imax = fcache.size();
1253 G4ThreeVector o;
1254 if (i < 0)
1255 {
1256 } else if (i < imax)
1257 {
1258 const cachezr_t& s = fcache[i];
1259 if (s.dz == 0.0) {
1260 o.setZ(copysign(1, s.dr));
1261 } else {
1262 double x = p.x() + n.x() * t;
1263 double y = p.y() + n.y() * t;
1264 double sth = s.dr * s.is, cth = -s.dz * s.is;
1265 double ir = cth / sqrt(x * x + y * y);
1266 o.set(x * ir, y * ir, sth);
1267 }
1268 } else if (i == imax)
1269 {
1270 o.setX(fn0x), o.setY(fn0y);
1271 } else
1272 {
1273 o.setX(fn1x), o.setY(fn1y);
1274 }
1275 return o;
1276 };
1277
1278 auto hitside = [this, &p, &n](double t, const cachezr_t& s) -> bool {
1279 double z = p.z() + n.z() * t;
1280 // cout<<t<<" "<<x<<" "<<y<<" "<<z<<endl;
1281 bool k = s.zmin < z && z <= s.zmax;
1282 if (k && !ftwopi)
1283 {
1284 double x = p.x() + n.x() * t;
1285 double y = p.y() + n.y() * t;
1286 k = k && insector(x, y);
1287 }
1288 return k;
1289 };
1290
1291 auto hitzside = [this, &p, &n](double t, const cachezr_t& s) -> bool {
1292 double x = p.x() + n.x() * t;
1293 double y = p.y() + n.y() * t;
1294 double r2 = x * x + y * y;
1295 bool k = s.r2min <= r2 && r2 < s.r2max;
1296 if (k && !ftwopi)
1297 {
1298 k = k && insector(x, y);
1299 }
1300 return k;
1301 };
1302
1303 auto hitphi0side = [this, &p, &n](double t) -> bool {
1304 double x = p.x() + n.x() * t;
1305 double y = p.y() + n.y() * t;
1306 double r = x * fc0 + y * fs0;
1307 if (r >= frmin)
1308 {
1309 double z = p.z() + n.z() * t;
1310 zr_t zr = {z, r};
1311 return wn_poly(zr) == 2;
1312 }
1313 return false;
1314 };
1315
1316 auto hitphi1side = [this, &p, &n](double t) -> bool {
1317 double x = p.x() + n.x() * t;
1318 double y = p.y() + n.y() * t;
1319 double r = x * fc1 + y * fs1;
1320 if (r >= frmin)
1321 {
1322 double z = p.z() + n.z() * t;
1323 zr_t zr = {z, r};
1324 return wn_poly(zr) == 2;
1325 }
1326 return false;
1327 };
1328
1329 double tmin = kInfinity;
1330 const int imax = fcache.size();
1331 int iseg = -1, isurface = -1;
1332 const double delta = 0.5 * kCarTolerance;
1333 double inz = 1 / n.z();
1334 double nn = dotxy(n, n), np = dotxy(n, p), pp = dotxy(p, p);
1335 double pz = p.z(), pr = sqrt(pp);
1336 for (int i = 0; i < imax; i++) { // loop over sides
1337 const cachezr_t& s = fcache[i];
1338 double dz = pz - s.z, dr = pr - s.r;
1339 double d = dz * s.dr - dr * s.dz;
1340 bool surface = false;
1341 if (abs(d * s.is) < delta) {
1342 double dot = dz * s.dz + dr * s.dr;
1343 if (dot >= 0 && dot <= s.s2) {
1344 surface = true;
1345 isurface = i;
1346 }
1347 }
1348 if (s.dz == 0.0) { // z-plane
1349 if (!surface) {
1350 double t = -dz * inz;
1351 if (0 < t && t < tmin && hitzside(t, s)) { tmin = t; iseg = i;}
1352 }
1353 } else {
1354 double A, B, R2;
1355 if (s.dr == 0.0) { // cylinder
1356 double R = s.r;
1357 R2 = R * R;
1358
1359 A = -nn;
1360 B = np;
1361 } else { // cone
1362 double taz = s.ta * dz;
1363 double R = taz + s.r;
1364 R2 = R * R;
1365
1366 double nzta = n.z() * s.ta;
1367 A = nzta * nzta - nn;
1368 B = np - nzta * R;
1369 }
1370 double C = pp - R2;
1371 double D = B * B + C * A;
1372 if (D > 0) {
1373 // double sD = sqrt(D), iA = 1 / A;
1374 // double t0 = (B + sD) * iA, t1 = (B - sD) * iA;
1375 double sD = sqrt(D), sum = B + copysign(sD, B);
1376 double t0 = -C / sum, t1 = sum / A;
1377 if (surface) { // exclude solution on surface
1378 if (abs(t0) > abs(t1)) {
1379 if (t0 > 0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1380 } else {
1381 if (t1 > 0 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1382 }
1383 } else {
1384 if (t0 > 0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1385 if (t1 > 0 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1386 }
1387 }
1388 }
1389 }
1390
1391 if (!ftwopi) {
1392 do { // side at phi0
1393 double vn = fn0x * n.x() + fn0y * n.y();
1394 if (vn < 0) {
1395 double d = fn0x * p.x() + fn0y * p.y();
1396 double t = -d / vn;
1397 if (hitphi0side(t)) {
1398 bool surface = std::abs(d) < delta;
1399 if (surface) {
1400 tmin = 0; iseg = imax + 0;
1401 } else {
1402 if (0 < t && t < tmin) {tmin = t; iseg = imax + 0;}
1403
1404 }
1405 }
1406 }
1407 } while (0);
1408
1409 do { // side at phi0+dphi
1410 double vn = fn1x * n.x() + fn1y * n.y();
1411 if (vn < 0) {
1412 double d = fn1x * p.x() + fn1y * p.y();
1413 double t = -d / vn;
1414 if (hitphi1side(t)) {
1415 bool surface = std::abs(d) < delta;
1416 if (surface) {
1417 tmin = 0; iseg = imax + 1;
1418 } else {
1419 if (0 < t && t < tmin) { tmin = t; iseg = imax + 1;}
1420 }
1421 }
1422 }
1423 } while (0);
1424 }
1425
1426 if (iseg >= 0) {
1427 if (getnormal(iseg, tmin)*n > 0) tmin = 0;
1428 // if (getnormal(iseg, tmin)*n > 0) tmin = kInfinity; // mimic genericpolycone
1429 }
1430
1431 auto convex = [this, imax](int i) -> bool{
1432 if (i < imax)
1433 return fcache[i].isconvex;
1434 else
1435 return !fgtpi;
1436 };
1437
1438 if (tmin >= 0 && tmin < kInfinity) {
1439 if (isurface >= 0) if (convex(isurface) && getnormal(isurface, 0)*n >= 0) tmin = kInfinity;
1440 } else {
1441 if (Inside(p) == kSurface) {
1442 if (isurface >= 0) {
1443 tmin = (getnormal(isurface, 0) * n >= 0) ? kInfinity : 0; // mimic genericpolycone
1444 }
1445 }
1446 }
1447
1448#if COMPARE0==1
1449 // double dd = fshape->Inside(p) == 2 ? 0.0 : fshape->DistanceToIn(p, n);
1450 double dd = fshape->DistanceToIn(p, n);
1451 if (abs(tmin - dd) > 1e-10) {
1452 int oldprec = cout.precision(16);
1453 EInside inside = fshape->Inside(p);
1454 cout << GetName() << " DistanceToIn(p,v) " << p << " " << n << " " << tmin << " " << dd << " " << tmin - dd << " " << inside << " "
1455 << Inside(p) << " iseg = " << iseg << " " << isurface << endl;
1456 if (isurface >= 0) cout << getnormal(isurface, 0) << endl;
1457 cout.precision(oldprec);
1458 }
1459#endif
1460 tmin = max(0.0, tmin);
1461 MATCHOUT("BelleLathe::DistanceToIn(p,n) " << p << " " << n << " res= " << tmin);
1462 return tmin;
1463}
1464
1465// Calculate distance to surface of shape from inside
1466G4double BelleLathe::DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& n,
1467 const G4bool calcNorm, G4bool* IsValid, G4ThreeVector* _n) const
1468{
1469 // return fshape->DistanceToOut(p, n, calcNorm, IsValid, _n);
1470 auto getnormal = [this, &p, &n](int i, double t)->G4ThreeVector{
1471 const int imax = fcache.size();
1472 G4ThreeVector o;
1473 if (i < 0)
1474 {
1475 } else if (i < imax)
1476 {
1477 const cachezr_t& s = fcache[i];
1478 if (s.dz == 0.0) {
1479 o.setZ(copysign(1, s.dr));
1480 } else {
1481 double x = p.x() + n.x() * t;
1482 double y = p.y() + n.y() * t;
1483 double sth = s.dr * s.is, cth = -s.dz * s.is;
1484 double ir = cth / sqrt(x * x + y * y);
1485 o.set(x * ir, y * ir, sth);
1486 }
1487 } else if (i == imax)
1488 {
1489 o.setX(fn0x), o.setY(fn0y);
1490 } else
1491 {
1492 o.setX(fn1x), o.setY(fn1y);
1493 }
1494 return o;
1495 };
1496
1497 double nn = dotxy(n, n), np = dotxy(n, p), pp = dotxy(p, p);
1498 auto hitside = [this, &p, &n, nn, np, pp](double t, const cachezr_t& s) -> bool {
1499 double z = p.z() + n.z() * t;
1500 // cout<<t<<" "<<x<<" "<<y<<" "<<z<<endl;
1501 double dot = n.z() * s.dr * sqrt(pp + ((np + np) + nn * t) * t) - s.dz * (np + nn * t);
1502 bool k = s.zmin < z && z <= s.zmax && dot > 0;
1503 if (k && !ftwopi)
1504 {
1505 double x = p.x() + n.x() * t;
1506 double y = p.y() + n.y() * t;
1507
1508 k = k && insector(x, y);
1509 }
1510 return k;
1511 };
1512
1513 auto hitzside = [this, &p, &n](double t, const cachezr_t& s) -> bool {
1514 double x = p.x() + n.x() * t;
1515 double y = p.y() + n.y() * t;
1516 double r2 = x * x + y * y;
1517 bool k = s.dr * n.z() > 0 && s.r2min <= r2 && r2 < s.r2max;
1518 if (k && !ftwopi)
1519 {
1520 k = k && insector(x, y);
1521 }
1522 return k;
1523 };
1524
1525 auto hitphi0side = [this, &p, &n](double t) -> bool {
1526 double x = p.x() + n.x() * t;
1527 double y = p.y() + n.y() * t;
1528 double r = x * fc0 + y * fs0;
1529 if (r >= frmin)
1530 {
1531 double z = p.z() + n.z() * t;
1532 zr_t zr = {z, r};
1533 return wn_poly(zr) == 2;
1534 }
1535 return false;
1536 };
1537
1538 auto hitphi1side = [this, &p, &n](double t) -> bool {
1539 double x = p.x() + n.x() * t;
1540 double y = p.y() + n.y() * t;
1541 double r = x * fc1 + y * fs1;
1542 if (r >= frmin)
1543 {
1544 double z = p.z() + n.z() * t;
1545 zr_t zr = {z, r};
1546 return wn_poly(zr) == 2;
1547 }
1548 return false;
1549 };
1550
1551 COUNTER(5);
1552 double tmin = kInfinity;
1553
1554 const int imax = fcache.size();
1555 int iseg = -1, isurface = -1;
1556
1557 const double delta = 0.5 * kCarTolerance;
1558 double inz = 1 / n.z();
1559 double pz = p.z(), pr = sqrt(pp);
1560
1561 for (int i = 0; i < imax; i++) {
1562 const cachezr_t& s = fcache[i];
1563
1564 double d = (pz - s.z) * s.dr - (pr - s.r) * s.dz;
1565 bool surface = abs(d * s.is) < delta;
1566 if (surface) isurface = i;
1567 if (s.dz == 0.0) {
1568 double t = (s.z - p.z()) * inz;
1569 if (surface) {
1570 if (hitzside(t, s)) {tmin = 0; iseg = i; break;}
1571 } else {
1572 if (0 < t && t < tmin && hitzside(t, s)) {tmin = t; iseg = i;}
1573 }
1574 } else {
1575 double A, B, R2;
1576 if (s.dr == 0.0) { // cylinder
1577 double R = s.r;
1578 R2 = R * R;
1579
1580 A = -nn;
1581 B = np;
1582 } else { // cone
1583 double taz = s.ta * (p.z() - s.z);
1584 double R = taz + s.r;
1585 R2 = R * R;
1586
1587 double nzta = n.z() * s.ta;
1588 A = nzta * nzta - nn;
1589 B = np - nzta * R;
1590 }
1591 double C = pp - R2;
1592 double D = B * B + C * A;
1593 if (D > 0) {
1594 double sD = sqrt(D);
1595 double sum = B + copysign(sD, B);
1596 double t0 = -C / sum, t1 = sum / A;
1597 // cout<<t0<<" "<<t1<<" "<<endl;
1598 if (surface) { //exclude solution on surface
1599 if (abs(t0) < abs(t1)) {
1600 if (hitside(t0, s)) { tmin = 0; iseg = i; break;}
1601 if (0 < t1 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1602 } else {
1603 if (hitside(t1, s)) { tmin = 0; iseg = i; break;}
1604 if (0 < t0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1605 }
1606 } else { // check both solutions
1607 if (0 < t0 && t0 < tmin && hitside(t0, s)) { tmin = t0; iseg = i;}
1608 if (0 < t1 && t1 < tmin && hitside(t1, s)) { tmin = t1; iseg = i;}
1609 }
1610 }
1611 }
1612 // cout<<i<<" "<<iseg<<" "<<sqrt(d*d*s.is2)<<" "<<tmin<<" "<<s.zmin<<" "<<s.zmax<<endl;
1613 }
1614
1615 if (!ftwopi) {
1616 do { // side at phi0
1617 double vn = fn0x * n.x() + fn0y * n.y();
1618 if (vn > 0) {
1619 double d = fn0x * p.x() + fn0y * p.y();
1620 double t = -d / vn;
1621 if (hitphi0side(t)) {
1622 bool surface = std::abs(d) < delta;
1623 if (surface) {
1624 tmin = 0; iseg = imax + 0;
1625 } else {
1626 if (0 < t && t < tmin) {tmin = t; iseg = imax + 0;}
1627
1628 }
1629 }
1630 }
1631 } while (0);
1632
1633 do { // side at phi0+dphi
1634 double vn = fn1x * n.x() + fn1y * n.y();
1635 if (vn > 0) {
1636 double d = fn1x * p.x() + fn1y * p.y();
1637 double t = -d / vn;
1638 if (hitphi1side(t)) {
1639 bool surface = std::abs(d) < delta;
1640 if (surface) {
1641 tmin = 0; iseg = imax + 1;
1642 } else {
1643 if (0 < t && t < tmin) { tmin = t; iseg = imax + 1;}
1644 }
1645 }
1646 }
1647 } while (0);
1648 }
1649
1650 auto convex = [this, imax](int i) -> bool{
1651 if (i < imax)
1652 return fcache[i].isconvex;
1653 else
1654 return !fgtpi;
1655 };
1656
1657 if (calcNorm) {
1658 if (tmin >= 0 && tmin < kInfinity) {
1659 *_n = getnormal(iseg, tmin);
1660 *IsValid = convex(iseg);
1661 } else {
1662 if (Inside(p) == kSurface) {
1663 if (isurface >= 0) {
1664 *_n = getnormal(isurface, tmin);
1665 *IsValid = convex(isurface);
1666 tmin = 0;
1667 }
1668 } else {
1669 *IsValid = false;
1670 }
1671 }
1672 }
1673 // cout<<"tmin "<<tmin<<endl;
1674#if COMPARE0==1
1675 do {
1676 // G4ThreeVector p0(1210.555046, -292.9578965, -36.71671492);
1677 // if ((p - p0).mag() > 1e-2)continue;
1678 bool isvalid;
1679 G4ThreeVector norm;
1680 double dd = fshape->DistanceToOut(p, n, calcNorm, &isvalid, &norm);
1681 if (abs(tmin - dd) > 1e-10 || (calcNorm && *IsValid != isvalid)) {
1682 int oldprec = cout.precision(16);
1683 cout << GetName() << " DistanceToOut(p,v) p,n =" << curl_t(p) << curl_t(n) << " calcNorm=" << calcNorm
1684 << " myInside=" << Inside(p) << " tmin=" << tmin << " dd=" << dd << " d=" << tmin - dd << " iseg=" << iseg << " isurf=" << isurface
1685 << " ";
1686 if (calcNorm) cout << "myIsValid = " << *IsValid << " tIsValid=" << isvalid << " myn=" << (*_n) << " tn=" << (norm);
1687 cout << endl;
1688 cout.precision(oldprec);
1689 // _exit(0);
1690 }
1691 } while (0);
1692#endif
1693 MATCHOUT("BelleLathe::DistanceToOut(p,n) " << p << " " << n << " res= " << tmin);
1694 return tmin;
1695}
1696
1697void BelleLathe::eartrim() const
1698{
1699 ftlist.clear();
1700 unsigned int n = fcontour.size();
1701 vector<int> indx;
1702 for (unsigned int i = 0; i < n; i++) indx.push_back(i);
1703 int count = 0;
1704 while (indx.size() > 3 && ++count < 200) {
1705 unsigned int ni = indx.size();
1706 for (unsigned int i = 0; i < ni; i++) {
1707 int i0 = indx[i], i1 = indx[(i + 1) % ni], i2 = indx[(i + 2) % ni];
1708 double nx = fcontour[i2].z - fcontour[i0].z;
1709 double ny = fcontour[i2].r - fcontour[i0].r;
1710 double d1 = nx * (fcontour[i1].r - fcontour[i0].r) - ny * (fcontour[i1].z - fcontour[i0].z);
1711 bool ear = true;
1712 for (unsigned int j = 0; j < ni - 3; j++) {
1713 int k = indx[(i + 3 + j) % ni];
1714 double d = nx * (fcontour[k].r - fcontour[i0].r) - ny * (fcontour[k].z - fcontour[i0].z);
1715 if (d * d1 > 0) {
1716 ear = false;
1717 break;
1718 }
1719 }
1720 if (ear) {
1721 triangle_t t = {i0, i1, i2};
1722 ftlist.push_back(t);
1723 indx.erase(indx.begin() + (i + 1) % ni);
1724 break;
1725 }
1726 }
1727 }
1728 if (indx.size() == 3) {
1729 triangle_t t = {indx[0], indx[1], indx[2]};
1730 ftlist.push_back(t);
1731 }
1732}
1733
1734void BelleLathe::getvolarea()
1735{
1736 double vol = 0;
1737 for (const cachezr_t& s : fcache) vol += s.dz * ((3 * s.r) * (s.r + s.dr) + s.dr * s.dr);
1738 fCubicVolume = -fdphi * vol / 6;
1739
1740 double totalarea = 0;
1741 if (!ftwopi) {
1742 eartrim();
1743 for (const triangle_t& t : ftlist) {
1744 const zr_t& p0 = fcontour[t.i0], &p1 = fcontour[t.i1], &p2 = fcontour[t.i2];
1745 double area = (p1.z - p0.z) * (p2.r - p0.r) - (p1.r - p0.r) * (p2.z - p0.z);
1746 totalarea += abs(area);
1747 farea.push_back(totalarea);
1748 }
1749 }
1750
1751 for (const cachezr_t& s : fcache) {
1752 double area = fdphi * (s.r + 0.5 * s.dr) * sqrt(s.dz * s.dz + s.dr * s.dr);
1753 totalarea += area;
1754 farea.push_back(totalarea);
1755 }
1756 fSurfaceArea = farea.back();
1757}
1758
1759G4ThreeVector BelleLathe::GetPointOnSurface() const
1760{
1761 auto GetPointOnTriangle = [this](const triangle_t& t)-> G4ThreeVector{
1762 // barycentric coordinates
1763 double a1 = CLHEP::RandFlat::shoot(0., 1.), a2 = CLHEP::RandFlat::shoot(0., 1.);
1764 if (a1 + a2 > 1) { a1 = 1 - a1; a2 = 1 - a2;}
1765 double a0 = 1 - (a1 + a2);
1766 const zr_t& p0 = fcontour[t.i0], &p1 = fcontour[t.i1], &p2 = fcontour[t.i2];
1767 zr_t p = {p0.z* a0 + p1.z* a1 + p2.z * a2, p0.r* a0 + p1.r* a1 + p2.r * a2};
1768 double c, s;
1769 if (CLHEP::RandFlat::shoot(0., 1.) > 0.5) // select phi side
1770 {
1771 c = -fn0y; s = fn0x;
1772 } else
1773 {
1774 c = fn1y; s = -fn1x;
1775 }
1776 G4ThreeVector r1(p.r * c, p.r * s, p.z);
1777 return r1;
1778 };
1779
1780 double rnd = CLHEP::RandFlat::shoot(0., farea.back());
1781 std::vector<double>::const_iterator it = std::lower_bound(farea.begin(), farea.end(), rnd);
1782 unsigned int i = it - farea.begin();
1783
1784 if (!ftwopi) {
1785 if (i < ftlist.size()) {
1786 return GetPointOnTriangle(ftlist[i]);
1787 } else {
1788 i -= ftlist.size();
1789 }
1790 }
1791
1792 const cachezr_t& s = fcache[i];
1793 double I = 2 * s.r + s.dr;
1794 double Iw = CLHEP::RandFlat::shoot(0., I);
1795 double q = sqrt(Iw * s.dr + s.r * s.r);
1796 double t = Iw / (q + s.r);
1797 double z = s.z + s.dz * t;
1798 double r = s.r + s.dr * t;
1799 double phi = CLHEP::RandFlat::shoot(fphi, fphi + fdphi);
1800 double x = r * cos(phi), y = r * sin(phi);
1801 return G4ThreeVector(x, y, z);
1802}
1803
1804// GetEntityType
1805G4GeometryType BelleLathe::GetEntityType() const
1806{
1807 return G4String("BelleLathe");
1808}
1809
1810// Make a clone of the object
1811G4VSolid* BelleLathe::Clone() const
1812{
1813 return new BelleLathe(*this);
1814}
1815
1816// Stream object contents to an output stream
1817std::ostream& BelleLathe::StreamInfo(std::ostream& os) const
1818{
1819 G4int oldprc = os.precision(16);
1820 os << "-----------------------------------------------------------\n"
1821 << " *** Dump for solid - " << GetName() << " ***\n"
1822 << " ===================================================\n"
1823 << " Solid type: BelleLathe\n"
1824 << " Contour: " << fcontour.size() << " sides, {z, r} points \n";
1825 for (int i = 0, imax = fcontour.size(); i < imax; i++) {
1826 os << fcontour[i] << ", ";
1827 }
1828 os << "\n";
1829 for (int i = 0, imax = fcontour.size(); i < imax; i++) {
1830 os << fcache[i].isconvex << ", ";
1831 }
1832 os << "\n";
1833 os << "phi0 = " << fphi << ", dphi = " << fdphi << ", Full Circle = " << (ftwopi ? "yes" : "no") << "\n";
1834 double xmin = fzmin - 0.05 * (fzmax - fzmin), xmax = fzmax + 0.05 * (fzmax - fzmin);
1835 double ymin = frmin - 0.05 * (frmax - frmin), ymax = frmax + 0.05 * (frmax - frmin);
1836 os << " BB: " << xmin << ", " << xmax << ", " << ymin << ", " << ymax << endl;
1837 os << "-----------------------------------------------------------\n";
1838 os.precision(oldprc);
1839
1840 return os;
1841}
1842
1843// Methods for visualisation
1844void BelleLathe::DescribeYourselfTo(G4VGraphicsScene& scene) const
1845{
1846 scene.AddSolid(*this);
1847}
1848
1849// Function to define the bounding box
1850void BelleLathe::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const
1851{
1852 std::vector<vector_t> points;
1853 vector_t point;
1854
1855 // Placeholder vectors
1856 const double inf = std::numeric_limits<double>::infinity();
1857 G4ThreeVector minimum(inf, inf, inf), maximum(-inf, -inf, -inf);
1858
1859 // Outer vertices
1860 if (fdphi < 2 * M_PI3.14159265358979323846) { // Only axis-crossings are relevant if the shape is a full circle
1861 point.x = frmax * cos(fphi); point.y = frmax * sin(fphi);
1862 points.push_back(point);
1863 point.x = frmax * cos(fphi + fdphi); point.y = frmax * sin(fphi + fdphi);
1864 points.push_back(point);
1865 }
1866
1867 // Inner vertices
1868 point.x = frmin * cos(fphi); point.y = frmin * sin(fphi);
1869 points.push_back(point);
1870 if (frmin != 0) { // Avoid duplicate (0,0)
1871 point.x = frmin * cos(fphi + fdphi); point.y = frmin * sin(fphi + fdphi);
1872 points.push_back(point);
1873 }
1874
1875 // Check if shape crosses an axis
1876 // Because the inside is concave, extremums will always be at vertices
1877 // Because the outside is convex, extremums may be at an axis-crossing
1878 if (insector(0, 1)) {
1879 point.x = 0; point.y = frmax;
1880 points.push_back(point);
1881 }
1882 if (insector(-1, 0)) {
1883 point.x = -frmax; point.y = 0;
1884 points.push_back(point);
1885 }
1886 if (insector(0, -1)) {
1887 point.x = 0; point.y = -frmax;
1888 points.push_back(point);
1889 }
1890 if (insector(1, 0)) {
1891 point.x = frmax; point.y = 0;
1892 points.push_back(point);
1893 }
1894
1895 for (std::vector<vector_t>::size_type i = 0; i != points.size(); i++) {
1896 // global min in x
1897 if (points[i].x < minimum.x())
1898 minimum.setX(points[i].x);
1899
1900 // global min in y
1901 if (points[i].y < minimum.y())
1902 minimum.setY(points[i].y);
1903
1904 // global max in x
1905 if (points[i].x > maximum.x())
1906 maximum.setX(points[i].x);
1907
1908 // global max in y
1909 if (points[i].y > maximum.y())
1910 maximum.setY(points[i].y);
1911 }
1912
1913 // Set z extremum values
1914 minimum.setZ(fzmin);
1915 maximum.setZ(fzmax);
1916
1917 // Assign
1918 pMin = minimum;
1919 pMax = maximum;
1920}
1921
1922void takePolyhedron(const HepPolyhedron& p)
1923{
1924 int i, nnode, iNodes[5], iVis[4], iFaces[4];
1925
1926 for (int iface = 1; iface <= p.GetNoFacets(); iface++) {
1927 p.GetFacet(iface, nnode, iNodes, iVis, iFaces);
1928 for (i = 0; i < nnode; i++) {
1929 if (iNodes[i] < 1 || iNodes[i] > p.GetNoVertices()) { //G.Barrand
1930 // processor_error = 1;
1931 G4cerr
1932 << "BooleanProcessor::takePolyhedron : problem 1."
1933 << G4endlstd::endl;
1934 }
1935 if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets()) { //G.Barrand
1936 // processor_error = 1;
1937 G4cerr
1938 << "BooleanProcessor::takePolyhedron : problem 2. "
1939 << i << " " << iFaces[i] << " " << p.GetNoFacets() << G4endlstd::endl;
1940 }
1941 }
1942 }
1943}
1944
1945PolyhedronBelleLathe::PolyhedronBelleLathe(const std::vector<zr_t>& v, const std::vector<triangle_t>& t, double phi, double dphi)
1946{
1947 int nphi = GetNumberOfRotationSteps();
1948 bool twopi = abs(dphi - 2 * M_PI3.14159265358979323846) < 1e-6;
1949 int n = v.size();
1950 if (twopi) {
1951 int nv = n * nphi;
1952 int nf = nv;
1953 AllocateMemory(nv, nf);
1954
1955 auto vnum = [nphi, n](int iphi, int ip) {
1956 return (iphi % nphi) * n + (ip % n) + 1;
1957 };
1958
1959 int fcount = 1;
1960 double dfi = dphi / nphi;
1961 for (int i = 0; i < nphi; i++) {
1962 double fi = phi + i * dfi;
1963 double cf = cos(fi), sf = sin(fi);
1964 for (int j = 0; j < n; j++) pV[vnum(i, j)].set(v[j].r * cf, v[j].r * sf, v[j].z);
1965 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);
1966 }
1967 } else {
1968 // cout<<"NPHI = "<<nphi<<" "<<phi<<" "<<dphi<<endl;
1969 nphi = int(nphi * (dphi / (2 * M_PI3.14159265358979323846)) + 0.5);
1970 nphi = nphi > 3 ? nphi : 3;
1971
1972 // cout<<"NPHI = "<<nphi<<endl;
1973
1974 int nv = n * nphi;
1975 int nf = n * (nphi - 1) + 2 * t.size();
1976 AllocateMemory(nv, nf);
1977
1978 auto vnum = [n](int iphi, int ip) {
1979 return iphi * n + (ip % n) + 1;
1980 };
1981
1982 int fcount = 1;
1983 double dfi = dphi / (nphi - 1);
1984 for (int i = 0; i < nphi; i++) {
1985 double fi = phi + i * dfi;
1986 double cf = cos(fi), sf = sin(fi);
1987 for (int j = 0; j < n; j++) pV[vnum(i, j)].set(v[j].r * cf, v[j].r * sf, v[j].z);
1988 if (i == nphi - 1) break;
1989 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);
1990 }
1991
1992 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);
1993 int i = nphi - 1;
1994 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);
1995
1996 }
1997 SetReferences();
1998 // takePolyhedron(*this);
1999}
2000
2001PolyhedronBelleLathe::~PolyhedronBelleLathe() {}
2002
2003G4Polyhedron* BelleLathe::CreatePolyhedron() const
2004{
2005 eartrim();
2006 return new PolyhedronBelleLathe(fcontour, ftlist, fphi, fdphi);
2007}
2008
2009#if 0
2010#include <immintrin.h>
2011double mindistsimd(const zr_t& r, const vector<cachezr_t>& contour)
2012{
2013 double d = kInfinity;
2014 int i = 0, n = contour.size();
2015 __m128d zero = _mm_set_sd(0);
2016 __m128d one = _mm_set_sd(1);
2017 double wn = 0;
2018 do {
2019 const cachezr_t& s = contour[i];
2020 double dz = r.z - s.z, dr = r.r - s.r;
2021 double crs = s.dr * dz - s.dz * dr;
2022 double dot = s.dz * dz + s.dr * dr; // projection of the point on the segment
2023 // if(s.zmin<=r.z&&r.z<s.zmax) wn -= (crs>0) - (crs<0);
2024 __m128d crssd = _mm_set_sd(crs);
2025 __m128d maskgt = _mm_cmpgt_sd(crssd, zero);
2026 __m128d masklt = _mm_cmplt_sd(crssd, zero);
2027 __m128d left = _mm_sub_sd(_mm_and_pd(maskgt, one), _mm_and_pd(masklt, one));
2028 __m128d z = _mm_set_sd(s.z);
2029 __m128d mask = _mm_and_pd(_mm_cmple_sd(_mm_set_sd(s.zmin), z), _mm_cmplt_sd(z, _mm_set_sd(s.zmax)));
2030 left = _mm_and_pd(mask, left);
2031 double du = dz * dz + dr * dr;
2032 double dv = crs * crs * s.is2;
2033
2034 masklt = _mm_cmplt_sd(_mm_set_sd(dot), zero);
2035 maskgt = _mm_cmpgt_sd(_mm_set_sd(dot), _mm_set_sd(s.s2));
2036
2037 __m128d uu = _mm_or_pd(_mm_and_pd(maskgt, _mm_set_sd(kInfinity)), _mm_andnot_pd(maskgt, _mm_set_sd(dv)));
2038 __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]))));
2039 wn -= left[0];
2040 d = vv[0];
2041 } while (++i < n);
2042 d = sqrt(d);
2043 d = (wn == 2) ? -d : d;
2044 // cout<<wn<<" "<<d<<endl;
2045 // cout<<sqrt(dp)<<" "<<sqrt(dm)<<endl;
2046 return d;
2047}
2048inline int left(const zr_t& r0, const zr_t& r1, const zr_t& r)
2049{
2050 double d = (r1.z - r0.z) * (r.r - r0.r) - (r.z - r0.z) * (r1.r - r0.r);
2051 return (d > 0) - (d < 0);
2052}
2053
2054inline int checkside(const zr_t& s0, const zr_t& s1, const zr_t& r)
2055{
2056 double zmin = min(s0.z, s1.z), zmax = max(s0.z, s1.z);
2057 if (zmin <= r.z && r.z < zmax) return left(s0, s1, r);
2058 return 0;
2059}
2060
2061int wn_poly(const zr_t& r, const vector<zr_t>& contour)
2062{
2063 int wn = 0; // the winding number counter
2064 int i = 0, n = contour.size() - 1;
2065 do {
2066 wn += checkside(contour[i], contour[i + 1], r);
2067 } while (++i < n);
2068 wn += checkside(contour[n], contour[0], r);
2069 return wn;
2070}
2071
2072double mindist(const zr_t& r, const vector<zr_t>& contour)
2073{
2074 int wn = 0;
2075 double d = kInfinity;
2076 auto dist = [&contour, &d, &r, &wn](int i0, int i1)->void {
2077 const zr_t& s0 = contour[i0], &s1 = contour[i1];
2078 double zmin = min(s0.z, s1.z), zmax = max(s0.z, s1.z);
2079 double sz = s1.z - s0.z, sr = s1.r - s0.r;
2080 double dz = r.z - s0.z, dr = r.r - s0.r;
2081 double crs = dz * sr - sz * dr;
2082 if (zmin <= r.z && r.z < zmax) wn -= (crs > 0) - (crs < 0);
2083 double dot = sz * dz + sr * dr; // projection of the point on the segment
2084 double s2 = sz * sz + sr * sr;
2085 if (dot > s2) return; // point should be within the segment
2086 if (dot < 0)
2087 {
2088 double d2 = dz * dz + dr * dr; // distance to the first point of the segment
2089 d = min(d, d2);
2090 } else
2091 {
2092 d = min(d, crs * crs / s2);
2093 }
2094 // cout<<i0<<" "<<s0.z<<" "<<s0.r<<" "<<d<<" "<<wn<<endl;
2095 };
2096 int i = 0, n = contour.size() - 1;
2097 do {dist(i, i + 1);} while (++i < n);
2098 dist(n, 0);
2099 d = sqrt(d);
2100 d = (wn == 2) ? -d : d;
2101 // cout<<wn<<" "<<d<<endl;
2102 // cout<<sqrt(dp)<<" "<<sqrt(dm)<<endl;
2103 return d;
2104}
2105
2106double mindist(const zr_t& r, const vector<cachezr_t>& contour)
2107{
2108 double d = kInfinity;
2109 int wn = 0, i = 0, n = contour.size();
2110 do {
2111 const cachezr_t& s = contour[i];
2112 double dz = r.z - s.z, dr = r.r - s.r;
2113 double crs = s.dr * dz - s.dz * dr;
2114 double dot = s.dz * dz + s.dr * dr; // projection of the point on the segment
2115 if (s.zmin <= r.z && r.z < s.zmax) wn -= (crs > 0) - (crs < 0);
2116 if (dot > s.s2) continue; // point should be within the segment
2117 if (dot < 0) {
2118 d = min(d, dz * dz + dr * dr); // distance to the first point of the segment
2119 } else {
2120 d = min(d, crs * crs * s.is2);
2121 }
2122 // cout<<i<<" "<<s.z<<" "<<s.r<<" "<<d<<" "<<wn<<endl;
2123 // cout<<i<<" "<<d<<" "<<wn<<endl;
2124 } while (++i < n);
2125 d = sqrt(d);
2126 d = (wn == 2) ? -d : d;
2127 // cout<<wn<<" "<<d<<endl;
2128 return d;
2129}
2130
2131
2132#endif