35 double pRmin,
double pRmax,
36 double pSPhi,
double pDPhi,
37 double pSTheta,
double pDTheta)
38 :
VUSolid(pName), fCubicVolume(0.),
39 fSurfaceArea(0.),fEpsilon(2.e-11),
40 fFullPhiSphere(true), fFullThetaSphere(true)
47 if ((pRmin >= pRmax) || (pRmax < 1.1 * kRadTolerance) || (pRmin < 0))
49 std::ostringstream message;
50 message <<
"Invalid radii for Solid: " <<
GetName() << std::endl
51 <<
" pRmin = " << pRmin <<
", pRmax = " << pRmax;
57 fRminTolerance = (fRmin) ?
std::max(kRadTolerance, fEpsilon * fRmin) : 0;
58 kTolerance =
std::max(kRadTolerance, fEpsilon * fRmax);
62 CheckPhiAngles(pSPhi, pDPhi);
63 CheckThetaAngles(pSTheta, pDTheta);
79 :
VUSolid(rhs), fCubicVolume(0.),fSurfaceArea(0.),
80 fRminTolerance(rhs.fRminTolerance),
81 kTolerance(rhs.kTolerance), kAngTolerance(rhs.kAngTolerance),
82 kRadTolerance(rhs.kRadTolerance), fEpsilon(rhs.fEpsilon),
83 fRmin(rhs.fRmin), fRmax(rhs.fRmax), fSPhi(rhs.fSPhi), fDPhi(rhs.fDPhi),
84 fSTheta(rhs.fSTheta), fDTheta(rhs.fDTheta),
85 sinCPhi(rhs.sinCPhi), cosCPhi(rhs.cosCPhi),
86 cosHDPhiOT(rhs.cosHDPhiOT), cosHDPhiIT(rhs.cosHDPhiIT),
87 sinSPhi(rhs.sinSPhi), cosSPhi(rhs.cosSPhi),
88 sinEPhi(rhs.sinEPhi), cosEPhi(rhs.cosEPhi),
89 hDPhi(rhs.hDPhi), cPhi(rhs.cPhi), ePhi(rhs.ePhi),
90 sinSTheta(rhs.sinSTheta), cosSTheta(rhs.cosSTheta),
91 sinETheta(rhs.sinETheta), cosETheta(rhs.cosETheta),
92 tanSTheta(rhs.tanSTheta), tanSTheta2(rhs.tanSTheta2),
93 tanETheta(rhs.tanETheta), tanETheta2(rhs.tanETheta2), eTheta(rhs.eTheta),
94 fFullPhiSphere(rhs.fFullPhiSphere), fFullThetaSphere(rhs.fFullThetaSphere),
95 fFullSphere(rhs.fFullSphere)
114 VUSolid::operator=(rhs);
118 fCubicVolume = rhs.fCubicVolume;
119 fSurfaceArea = rhs.fSurfaceArea;
120 fRminTolerance = rhs.fRminTolerance;
121 kTolerance = rhs.kTolerance;
122 kAngTolerance = rhs.kAngTolerance;
123 kRadTolerance = rhs.kRadTolerance;
124 fEpsilon = rhs.fEpsilon;
129 fSTheta = rhs.fSTheta;
130 fDTheta = rhs.fDTheta;
131 sinCPhi = rhs.sinCPhi;
132 cosCPhi = rhs.cosCPhi;
133 cosHDPhiOT = rhs.cosHDPhiOT;
134 cosHDPhiIT = rhs.cosHDPhiIT;
135 sinSPhi = rhs.sinSPhi;
136 cosSPhi = rhs.cosSPhi;
137 sinEPhi = rhs.sinEPhi;
138 cosEPhi = rhs.cosEPhi;
142 sinSTheta = rhs.sinSTheta;
143 cosSTheta = rhs.cosSTheta;
144 sinETheta = rhs.sinETheta;
145 cosETheta = rhs.cosETheta;
146 tanSTheta = rhs.tanSTheta;
147 tanSTheta2 = rhs.tanSTheta2;
148 tanETheta = rhs.tanETheta;
149 tanETheta2 = rhs.tanETheta2;
151 fFullPhiSphere = rhs.fFullPhiSphere;
152 fFullThetaSphere = rhs.fFullThetaSphere;
153 fFullSphere = rhs.fFullSphere;
166 double rho, rho2, rad2, tolRMin, tolRMax;
169 static const double halfAngTolerance = kAngTolerance * 0.5;
170 const double halfTolerance = kTolerance * 0.5;
171 const double halfRminTolerance = fRminTolerance * 0.5;
172 const double rMaxMinus = fRmax - halfTolerance;
173 const double rMinPlus = (fRmin > 0) ? fRmin + halfRminTolerance : 0;
175 rho2 = p.
x * p.
x + p.
y * p.
y;
176 rad2 = rho2 + p.
z * p.
z;
183 if ((rad2 <= rMaxMinus * rMaxMinus) && (rad2 >= rMinPlus * rMinPlus))
189 tolRMax = fRmax + halfTolerance;
190 tolRMin =
std::max(fRmin - halfRminTolerance, 0.);
191 if ((rad2 <= tolRMax * tolRMax) && (rad2 >= tolRMin * tolRMin))
203 if (!fFullPhiSphere && rho2)
205 pPhi = std::atan2(p.
y, p.
x);
207 if (pPhi < fSPhi - halfAngTolerance)
209 pPhi += 2 * UUtils::kPi;
211 else if (pPhi > ePhi + halfAngTolerance)
213 pPhi -= 2 * UUtils::kPi;
216 if ((pPhi < fSPhi - halfAngTolerance)
217 || (pPhi > ePhi + halfAngTolerance))
224 if ((pPhi < fSPhi + halfAngTolerance)
225 || (pPhi > ePhi - halfAngTolerance))
234 if ((rho2 || p.
z) && (!fFullThetaSphere))
236 rho = std::sqrt(rho2);
237 pTheta = std::atan2(rho, p.
z);
241 if ((pTheta < fSTheta + halfAngTolerance)
242 || (pTheta > eTheta - halfAngTolerance))
244 if ((pTheta >= fSTheta - halfAngTolerance)
245 && (pTheta <= eTheta + halfAngTolerance))
257 if ((pTheta < fSTheta - halfAngTolerance)
258 || (pTheta > eTheta + halfAngTolerance))
276 double rho, rho2, radius, pTheta, pPhi = 0.;
280 UVector3 nR, nPs, nPe, nTs, nTe, nZ(0., 0., 1.);
284 static const double halfAngTolerance = 0.5 * kAngTolerance;
286 rho2 = p.
x * p.
x + p.
y * p.
y;
287 radius = std::sqrt(rho2 + p.
z * p.
z);
288 rho = std::sqrt(rho2);
290 double distRMax = std::fabs(radius - fRmax);
291 if (fRmin) distRMin = std::fabs(radius - fRmin);
293 if (rho && !fFullSphere)
295 pPhi = std::atan2(p.
y, p.
x);
297 if (pPhi < fSPhi - halfAngTolerance)
299 pPhi += 2 * UUtils::kPi;
301 else if (pPhi > ePhi + halfAngTolerance)
303 pPhi -= 2 * UUtils::kPi;
310 distSPhi = std::fabs(pPhi - fSPhi);
311 distEPhi = std::fabs(pPhi - ePhi);
318 nPs =
UVector3(sinSPhi, -cosSPhi, 0);
319 nPe =
UVector3(-sinEPhi, cosEPhi, 0);
321 if (!fFullThetaSphere)
325 pTheta = std::atan2(rho, p.
z);
326 distSTheta = std::fabs(pTheta - fSTheta);
327 distETheta = std::fabs(pTheta - eTheta);
330 -cosSTheta * p.
y / rho,
334 cosETheta * p.
y / rho,
344 if (eTheta < UUtils::kPi)
353 nR =
UVector3(p.
x / radius, p.
y / radius, p.
z / radius);
356 if (distRMax <= halfCarTolerance)
361 if (fRmin && (distRMin <= halfCarTolerance))
368 if (distSPhi <= halfAngTolerance)
373 if (distEPhi <= halfAngTolerance)
379 if (!fFullThetaSphere)
381 if ((distSTheta <= halfAngTolerance) && (fSTheta > 0.))
384 if ((radius <= halfCarTolerance) && fFullPhiSphere)
393 if ((distETheta <= halfAngTolerance) && (eTheta < UUtils::kPi))
396 if ((radius <= halfCarTolerance) && fFullPhiSphere)
414 Warning, 1,
"Point p is not on surface !?");
416 norm = ApproxSurfaceNormal(p);
418 else if (noSurfaces == 1)
424 norm = sumnorm.
Unit();
427 return (noSurfaces > 0);
440 double rho, rho2, radius, pPhi, pTheta;
441 double distRMin, distRMax, distSPhi, distEPhi,
442 distSTheta, distETheta, distMin;
444 rho2 = p.
x * p.
x + p.
y * p.
y;
445 radius = std::sqrt(rho2 + p.
z * p.
z);
446 rho = std::sqrt(rho2);
452 distRMax = std::fabs(radius - fRmax);
455 distRMin = std::fabs(radius - fRmin);
457 if (distRMin < distRMax)
478 pPhi = std::atan2(p.
y, p.
x);
481 pPhi += 2 * UUtils::kPi;
484 if (!fFullPhiSphere && rho)
488 distSPhi = std::fabs(pPhi - (fSPhi + 2 * UUtils::kPi)) * rho;
492 distSPhi = std::fabs(pPhi - fSPhi) * rho;
495 distEPhi = std::fabs(pPhi - fSPhi - fDPhi) * rho;
499 if (distSPhi < distEPhi)
501 if (distSPhi < distMin)
509 if (distEPhi < distMin)
521 if (!fFullThetaSphere && radius)
523 pTheta = std::atan2(rho, p.
z);
524 distSTheta = std::fabs(pTheta - fSTheta) * radius;
525 distETheta = std::fabs(pTheta - fSTheta - fDTheta) * radius;
529 if (distSTheta < distETheta)
531 if (distSTheta < distMin)
533 distMin = distSTheta;
539 if (distETheta < distMin)
541 distMin = distETheta;
550 norm =
UVector3(-p.
x / radius, -p.
y / radius, -p.
z / radius);
553 norm =
UVector3(p.
x / radius, p.
y / radius, p.
z / radius);
556 norm =
UVector3(sinSPhi, -cosSPhi, 0);
559 norm =
UVector3(-sinEPhi, cosEPhi, 0);
562 norm =
UVector3(-cosSTheta * std::cos(pPhi),
563 -cosSTheta * std::sin(pPhi),
567 norm =
UVector3(cosETheta * std::cos(pPhi),
568 cosETheta * std::sin(pPhi),
575 "Undefined side for valid surface normal to solid.");
614 double rho2, rad2, pDotV2d, pDotV3d, pTheta;
615 double tolSTheta = 0., tolETheta = 0.;
616 const double dRmax = 100.*fRmax;
619 static const double halfAngTolerance = kAngTolerance * 0.5;
620 const double halfTolerance = kTolerance * 0.5;
621 const double halfRminTolerance = fRminTolerance * 0.5;
622 const double tolORMin2 = (fRmin > halfRminTolerance)
623 ? (fRmin - halfRminTolerance) * (fRmin - halfRminTolerance) : 0;
624 const double tolIRMin2 =
625 (fRmin + halfRminTolerance) * (fRmin + halfRminTolerance);
626 const double tolORMax2 =
627 (fRmax + halfTolerance) * (fRmax + halfTolerance);
628 const double tolIRMax2 =
629 (fRmax - halfTolerance) * (fRmax - halfTolerance);
633 double xi, yi, zi, rhoi, rhoi2, radi2, iTheta;
645 double dist2STheta, dist2ETheta;
650 rho2 = p.
x * p.
x + p.
y * p.
y;
651 rad2 = rho2 + p.
z * p.
z;
652 pTheta = std::atan2(std::sqrt(rho2), p.
z);
654 pDotV2d = p.
x * v.
x + p.
y * v.
y;
655 pDotV3d = pDotV2d + p.
z * v.
z;
659 if (!fFullThetaSphere)
661 tolSTheta = fSTheta - halfAngTolerance;
662 tolETheta = eTheta + halfAngTolerance;
679 c = rad2 - fRmax * fRmax;
681 if (c > kTolerance * fRmax)
686 d2 = pDotV3d * pDotV3d -
c;
690 sd = -pDotV3d - std::sqrt(d2);
697 double fTerm = sd - std::fmod(sd, dRmax);
702 rhoi = std::sqrt(xi * xi + yi * yi);
704 if (!fFullPhiSphere && rhoi)
706 cosPsi = (xi * cosCPhi + yi * sinCPhi) / rhoi;
708 if (cosPsi >= cosHDPhiOT)
710 if (!fFullThetaSphere)
717 iTheta = std::atan2(rhoi, zi);
718 if ((iTheta >= tolSTheta) && (iTheta <= tolETheta))
731 if (!fFullThetaSphere)
738 iTheta = std::atan2(rhoi, zi);
739 if ((iTheta >= tolSTheta) && (iTheta <= tolETheta))
761 d2 = pDotV3d * pDotV3d -
c;
763 if ((rad2 > tolIRMax2)
764 && ((d2 >= kTolerance * fRmax) && (pDotV3d < 0)))
771 cosPsi = (p.
x * cosCPhi + p.
y * sinCPhi) / std::sqrt(rho2);
773 if (cosPsi >= cosHDPhiIT)
777 if (!fFullThetaSphere)
779 if ((pTheta >= tolSTheta + kAngTolerance)
780 && (pTheta <= tolETheta - kAngTolerance))
793 if (!fFullThetaSphere)
795 if ((pTheta >= tolSTheta + kAngTolerance)
796 && (pTheta <= tolETheta - kAngTolerance))
816 c = rad2 - fRmin * fRmin;
817 d2 = pDotV3d * pDotV3d -
c;
822 if ((c > -halfRminTolerance) && (rad2 < tolIRMin2)
830 cosPsi = (p.
x * cosCPhi + p.
y * sinCPhi) / std::sqrt(rho2);
831 if (cosPsi >= cosHDPhiIT)
835 if (!fFullThetaSphere)
837 if ((pTheta >= tolSTheta + kAngTolerance)
838 && (pTheta <= tolETheta - kAngTolerance))
851 if (!fFullThetaSphere)
853 if ((pTheta >= tolSTheta + kAngTolerance)
854 && (pTheta <= tolETheta - kAngTolerance))
869 sd = -pDotV3d + std::sqrt(d2);
870 if (sd >= halfRminTolerance)
874 rhoi = std::sqrt(xi * xi + yi * yi);
876 if (!fFullPhiSphere && rhoi)
878 cosPsi = (xi * cosCPhi + yi * sinCPhi) / rhoi;
880 if (cosPsi >= cosHDPhiOT)
882 if (!fFullThetaSphere)
889 iTheta = std::atan2(rhoi, zi);
890 if ((iTheta >= tolSTheta) && (iTheta <= tolETheta))
903 if (!fFullThetaSphere)
910 iTheta = std::atan2(rhoi, zi);
911 if ((iTheta >= tolSTheta) && (iTheta <= tolETheta))
940 Comp = v.
x * sinSPhi - v.
y * cosSPhi;
944 Dist = p.
y * cosSPhi - p.
x * sinSPhi;
946 if (Dist < halfCarTolerance)
957 rhoi2 = xi * xi + yi * yi ;
958 radi2 = rhoi2 + zi * zi ;
969 if ((radi2 <= tolORMax2)
970 && (radi2 >= tolORMin2)
971 && ((yi * cosCPhi - xi * sinCPhi) <= 0))
977 if (!fFullThetaSphere)
979 iTheta = std::atan2(std::sqrt(rhoi2), zi);
980 if ((iTheta >= tolSTheta) && (iTheta <= tolETheta))
985 if ((yi * cosCPhi - xi * sinCPhi) <= 0)
1003 Comp = -(v.
x * sinEPhi - v.
y * cosEPhi);
1007 Dist = -(p.
y * cosEPhi - p.
x * sinEPhi);
1008 if (Dist < halfCarTolerance)
1016 xi = p.
x + sd * v.
x;
1017 yi = p.
y + sd * v.
y;
1018 zi = p.
z + sd * v.
z;
1019 rhoi2 = xi * xi + yi * yi ;
1020 radi2 = rhoi2 + zi * zi ;
1031 if ((radi2 <= tolORMax2)
1032 && (radi2 >= tolORMin2)
1033 && ((yi * cosCPhi - xi * sinCPhi) >= 0))
1039 if (!fFullThetaSphere)
1041 iTheta = std::atan2(std::sqrt(rhoi2), zi);
1042 if ((iTheta >= tolSTheta) && (iTheta <= tolETheta))
1047 if ((yi * cosCPhi - xi * sinCPhi) >= 0)
1065 if (!fFullThetaSphere)
1089 dist2STheta = rho2 - p.
z * p.
z * tanSTheta2;
1095 if (eTheta < UUtils::kPi)
1097 dist2ETheta = rho2 - p.
z * p.
z * tanETheta2;
1103 if (pTheta < tolSTheta)
1108 t1 = 1 - v.
z * v.
z * (1 + tanSTheta2);
1109 t2 = pDotV2d - p.
z * v.
z * tanSTheta2;
1113 c = dist2STheta /
t1;
1120 zi = p.
z + sd * v.
z;
1122 if ((sd < 0) || (zi * (fSTheta - UUtils::kPi / 2) > 0))
1126 if ((sd >= 0) && (sd < snxt))
1128 xi = p.
x + sd * v.
x;
1129 yi = p.
y + sd * v.
y;
1130 zi = p.
z + sd * v.
z;
1131 rhoi2 = xi * xi + yi * yi;
1132 radi2 = rhoi2 + zi * zi;
1133 if ((radi2 <= tolORMax2)
1134 && (radi2 >= tolORMin2)
1135 && (zi * (fSTheta - UUtils::kPi / 2) <= 0))
1137 if (!fFullPhiSphere && rhoi2)
1139 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1140 if (cosPsi >= cosHDPhiOT)
1157 if (eTheta < UUtils::kPi)
1159 t1 = 1 - v.
z * v.
z * (1 + tanETheta2);
1160 t2 = pDotV2d - p.
z * v.
z * tanETheta2;
1164 c = dist2ETheta /
t1;
1172 if ((sd >= 0) && (sd < snxt))
1174 xi = p.
x + sd * v.
x;
1175 yi = p.
y + sd * v.
y;
1176 zi = p.
z + sd * v.
z;
1177 rhoi2 = xi * xi + yi * yi;
1178 radi2 = rhoi2 + zi * zi;
1180 if ((radi2 <= tolORMax2)
1181 && (radi2 >= tolORMin2)
1182 && (zi * (eTheta - UUtils::kPi / 2) <= 0))
1184 if (!fFullPhiSphere && rhoi2)
1186 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1187 if (cosPsi >= cosHDPhiOT)
1202 else if (pTheta > tolETheta)
1208 t1 = 1 - v.
z * v.
z * (1 + tanETheta2);
1209 t2 = pDotV2d - p.
z * v.
z * tanETheta2;
1213 c = dist2ETheta /
t1;
1220 zi = p.
z + sd * v.
z;
1222 if ((sd < 0) || (zi * (eTheta - UUtils::kPi / 2) > 0))
1226 if ((sd >= 0) && (sd < snxt))
1228 xi = p.
x + sd * v.
x;
1229 yi = p.
y + sd * v.
y;
1230 zi = p.
z + sd * v.
z;
1231 rhoi2 = xi * xi + yi * yi;
1232 radi2 = rhoi2 + zi * zi;
1234 if ((radi2 <= tolORMax2)
1235 && (radi2 >= tolORMin2)
1236 && (zi * (eTheta - UUtils::kPi / 2) <= 0))
1238 if (!fFullPhiSphere && rhoi2)
1240 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1241 if (cosPsi >= cosHDPhiOT)
1260 t1 = 1 - v.
z * v.
z * (1 + tanSTheta2);
1261 t2 = pDotV2d - p.
z * v.
z * tanSTheta2;
1265 c = dist2STheta /
t1;
1273 if ((sd >= 0) && (sd < snxt))
1275 xi = p.
x + sd * v.
x;
1276 yi = p.
y + sd * v.
y;
1277 zi = p.
z + sd * v.
z;
1278 rhoi2 = xi * xi + yi * yi;
1279 radi2 = rhoi2 + zi * zi;
1281 if ((radi2 <= tolORMax2)
1282 && (radi2 >= tolORMin2)
1283 && (zi * (fSTheta - UUtils::kPi / 2) <= 0))
1285 if (!fFullPhiSphere && rhoi2)
1287 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1288 if (cosPsi >= cosHDPhiOT)
1303 else if ((pTheta < tolSTheta + kAngTolerance)
1304 && (fSTheta > halfAngTolerance))
1310 t2 = pDotV2d - p.
z * v.
z * tanSTheta2;
1311 if ((t2 >= 0 && tolIRMin2 < rad2 && rad2 < tolIRMax2 && fSTheta < UUtils::kPi / 2)
1312 || (t2 < 0 && tolIRMin2 < rad2 && rad2 < tolIRMax2 && fSTheta > UUtils::kPi / 2)
1313 || (v.
z < 0 && tolIRMin2 < rad2 && rad2 < tolIRMax2 && fSTheta == UUtils::kPi / 2))
1315 if (!fFullPhiSphere && rho2)
1317 cosPsi = (p.
x * cosCPhi + p.
y * sinCPhi) / std::sqrt(rho2);
1318 if (cosPsi >= cosHDPhiIT)
1331 t1 = 1 - v.
z * v.
z * (1 + tanSTheta2);
1335 c = dist2STheta /
t1;
1342 if ((sd >= halfCarTolerance) && (sd < snxt) && (fSTheta < UUtils::kPi / 2))
1345 xi = p.
x + sd * v.
x;
1346 yi = p.
y + sd * v.
y;
1347 zi = p.
z + sd * v.
z;
1348 rhoi2 = xi * xi + yi * yi;
1349 radi2 = rhoi2 + zi * zi;
1351 if ((radi2 <= tolORMax2)
1352 && (radi2 >= tolORMin2)
1353 && (zi * (fSTheta - UUtils::kPi / 2) <= 0))
1355 if (!fFullPhiSphere && rhoi2)
1357 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1358 if (cosPsi >= cosHDPhiOT)
1372 else if ((pTheta > tolETheta - kAngTolerance) && (eTheta < UUtils::kPi - kAngTolerance))
1379 t2 = pDotV2d - p.
z * v.
z * tanETheta2;
1381 if (((t2 < 0) && (eTheta < UUtils::kPi / 2)
1382 && (tolIRMin2 < rad2) && (rad2 < tolIRMax2))
1383 || ((t2 >= 0) && (eTheta > UUtils::kPi / 2)
1384 && (tolIRMin2 < rad2) && (rad2 < tolIRMax2))
1385 || ((v.
z > 0) && (eTheta == UUtils::kPi / 2)
1386 && (tolIRMin2 < rad2) && (rad2 < tolIRMax2)))
1388 if (!fFullPhiSphere && rho2)
1390 cosPsi = (p.
x * cosCPhi + p.
y * sinCPhi) / std::sqrt(rho2);
1391 if (cosPsi >= cosHDPhiIT)
1404 t1 = 1 - v.
z * v.
z * (1 + tanETheta2);
1408 c = dist2ETheta /
t1;
1416 if ((sd >= halfCarTolerance)
1417 && (sd < snxt) && (eTheta > UUtils::kPi / 2))
1419 xi = p.
x + sd * v.
x;
1420 yi = p.
y + sd * v.
y;
1421 zi = p.
z + sd * v.
z;
1422 rhoi2 = xi * xi + yi * yi;
1423 radi2 = rhoi2 + zi * zi;
1425 if ((radi2 <= tolORMax2)
1426 && (radi2 >= tolORMin2)
1427 && (zi * (eTheta - UUtils::kPi / 2) <= 0))
1429 if (!fFullPhiSphere && rhoi2)
1431 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1432 if (cosPsi >= cosHDPhiOT)
1451 t1 = 1 - v.
z * v.
z * (1 + tanSTheta2);
1452 t2 = pDotV2d - p.
z * v.
z * tanSTheta2;
1456 c = dist2STheta /
t1;
1464 if ((sd >= 0) && (sd < snxt))
1466 xi = p.
x + sd * v.
x;
1467 yi = p.
y + sd * v.
y;
1468 zi = p.
z + sd * v.
z;
1469 rhoi2 = xi * xi + yi * yi;
1470 radi2 = rhoi2 + zi * zi;
1472 if ((radi2 <= tolORMax2)
1473 && (radi2 >= tolORMin2)
1474 && (zi * (fSTheta - UUtils::kPi / 2) <= 0))
1476 if (!fFullPhiSphere && rhoi2)
1478 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1479 if (cosPsi >= cosHDPhiOT)
1492 t1 = 1 - v.
z * v.
z * (1 + tanETheta2);
1493 t2 = pDotV2d - p.
z * v.
z * tanETheta2;
1497 c = dist2ETheta /
t1;
1505 if ((sd >= 0) && (sd < snxt))
1507 xi = p.
x + sd * v.
x;
1508 yi = p.
y + sd * v.
y;
1509 zi = p.
z + sd * v.
z;
1510 rhoi2 = xi * xi + yi * yi;
1511 radi2 = rhoi2 + zi * zi;
1513 if ((radi2 <= tolORMax2)
1514 && (radi2 >= tolORMin2)
1515 && (zi * (eTheta - UUtils::kPi / 2) <= 0))
1517 if (!fFullPhiSphere && rhoi2)
1519 cosPsi = (xi * cosCPhi + yi * sinCPhi) / std::sqrt(rhoi2);
1520 if (cosPsi >= cosHDPhiOT)
1548 double safe = 0.0, safeRMin, safeRMax, safePhi, safeTheta;
1549 double rho2, rds, rho;
1551 double pTheta, dTheta1, dTheta2;
1552 rho2 = p.
x * p.
x + p.
y * p.
y;
1553 rds = std::sqrt(rho2 + p.
z * p.
z);
1554 rho = std::sqrt(rho2);
1561 safeRMin = fRmin - rds;
1562 safeRMax = rds - fRmax;
1563 if (safeRMin > safeRMax)
1580 if (!fFullPhiSphere && rho)
1584 cosPsi = (p.
x * cosCPhi + p.
y * sinCPhi) / rho;
1585 if (cosPsi < std::cos(hDPhi))
1589 if ((p.
y * cosCPhi - p.
x * sinCPhi) <= 0)
1591 safePhi = std::fabs(p.
x * sinSPhi - p.
y * cosSPhi);
1595 safePhi = std::fabs(p.
x * sinEPhi - p.
y * cosEPhi);
1606 if ((rds != 0.0) && (!fFullThetaSphere))
1608 pTheta = std::acos(p.
z / rds);
1611 pTheta += UUtils::kPi;
1613 dTheta1 = fSTheta - pTheta;
1614 dTheta2 = pTheta - eTheta;
1615 if (dTheta1 > dTheta2)
1619 safeTheta = rds * std::sin(dTheta1);
1620 if (safe <= safeTheta)
1630 safeTheta = rds * std::sin(dTheta2);
1631 if (safe <= safeTheta)
1655 ESide side = kNull, sidephi = kNull, sidetheta = kNull;
1658 static const double halfAngTolerance = kAngTolerance * 0.5;
1659 const double halfTolerance = kTolerance * 0.5;
1660 const double halfRminTolerance = fRminTolerance * 0.5;
1661 const double rMaxPlus = fRmax + halfTolerance;
1662 const double Rmin_minus = (fRmin) ? fRmin - halfRminTolerance : 0;
1668 double pDistS, compS, pDistE, compE, sphi2, vphi;
1670 double rho2, rad2, pDotV2d, pDotV3d;
1677 double dist2STheta, dist2ETheta, distTheta;
1682 rho2 = p.
x * p.
x + p.
y * p.
y;
1683 rad2 = rho2 + p.
z * p.
z;
1685 pDotV2d = p.
x * v.
x + p.
y * v.
y;
1686 pDotV3d = pDotV2d + p.
z * v.
z;
1704 if ((rad2 <= rMaxPlus * rMaxPlus) && (rad2 >= Rmin_minus * Rmin_minus))
1706 c = rad2 - fRmax * fRmax;
1708 if (c < kTolerance * fRmax)
1719 d2 = pDotV3d * pDotV3d -
c;
1721 if ((c > - kTolerance * fRmax)
1722 && ((pDotV3d >= 0) || (d2 < 0)))
1726 n =
UVector3(p.
x / fRmax, p.
y / fRmax, p.
z / fRmax);
1731 snxt = -pDotV3d + std::sqrt(d2);
1742 c = rad2 - fRmin * fRmin;
1743 d2 = pDotV3d * pDotV3d -
c;
1745 if (c > - fRminTolerance * fRmin)
1747 if ((c < fRminTolerance * fRmin)
1748 && (d2 >= fRminTolerance * fRmin) && (pDotV3d < 0))
1757 sd = -pDotV3d - std::sqrt(d2);
1772 if (!fFullThetaSphere)
1798 if (std::fabs(tanSTheta) > 5. / kAngTolerance)
1802 if (std::fabs(p.
z) <= halfTolerance)
1808 stheta = -p.
z / v.
z;
1809 sidetheta = kSTheta;
1814 t1 = 1 - v.
z * v.
z * (1 + tanSTheta2);
1815 t2 = pDotV2d - p.
z * v.
z * tanSTheta2;
1816 dist2STheta = rho2 - p.
z * p.
z * tanSTheta2;
1818 distTheta = std::sqrt(rho2) - p.
z * tanSTheta;
1820 if (std::fabs(t1) < halfAngTolerance)
1825 if (std::fabs(distTheta) < halfTolerance)
1827 if ((fSTheta < UUtils::kPi / 2) && (p.
z > 0.))
1832 else if ((fSTheta > UUtils::kPi / 2) && (p.
z <= 0))
1837 rhoSecTheta = std::sqrt(rho2 * (1 + tanSTheta2));
1847 stheta = -0.5 * dist2STheta /
t2;
1848 sidetheta = kSTheta;
1853 if (std::fabs(distTheta) < halfTolerance)
1855 if ((fSTheta > UUtils::kPi / 2) && (t2 >= 0.))
1860 rhoSecTheta = std::sqrt(rho2 * (1 + tanSTheta2));
1872 else if ((fSTheta < UUtils::kPi / 2) && (t2 < 0.) && (p.
z >= 0.))
1879 c = dist2STheta /
t1;
1886 if (fSTheta > UUtils::kPi / 2)
1890 if (((std::fabs(sd) < halfTolerance) && (t2 < 0.))
1891 || (sd < 0.) || ((sd > 0.) && (p.
z + sd * v.
z > 0.)))
1895 if ((sd > halfTolerance) && (p.
z + sd * v.
z <= 0.))
1898 sidetheta = kSTheta;
1905 if (((std::fabs(sd) < halfTolerance) && (t2 >= 0.))
1906 || (sd < 0.) || ((sd > 0.) && (p.
z + sd * v.
z < 0.)))
1910 if ((sd > halfTolerance) && (p.
z + sd * v.
z >= 0.))
1913 sidetheta = kSTheta;
1920 if (eTheta < UUtils::kPi)
1922 if (std::fabs(tanETheta) > 5. / kAngTolerance)
1926 if (std::fabs(p.
z) <= halfTolerance)
1937 sidetheta = kETheta;
1943 t1 = 1 - v.
z * v.
z * (1 + tanETheta2);
1944 t2 = pDotV2d - p.
z * v.
z * tanETheta2;
1945 dist2ETheta = rho2 - p.
z * p.
z * tanETheta2;
1947 distTheta = std::sqrt(rho2) - p.
z * tanETheta;
1949 if (std::fabs(t1) < halfAngTolerance)
1954 if (std::fabs(distTheta) < halfTolerance)
1956 if ((eTheta > UUtils::kPi / 2) && (p.
z < 0.))
1961 else if ((eTheta < UUtils::kPi / 2) && (p.
z >= 0))
1966 rhoSecTheta = std::sqrt(rho2 * (1 + tanETheta2));
1978 sd = -0.5 * dist2ETheta /
t2;
1983 sidetheta = kETheta;
1989 if (std::fabs(distTheta) < halfTolerance)
1991 if ((eTheta < UUtils::kPi / 2) && (t2 >= 0.))
1996 rhoSecTheta = std::sqrt(rho2 * (1 + tanETheta2));
2004 else if ((eTheta > UUtils::kPi / 2)
2005 && (t2 < 0.) && (p.
z <= 0.))
2012 c = dist2ETheta /
t1;
2019 if (eTheta < UUtils::kPi / 2)
2023 if (((std::fabs(sd) < halfTolerance) && (t2 < 0.))
2028 if (sd > halfTolerance)
2033 sidetheta = kETheta;
2041 if (((std::fabs(sd) < halfTolerance) && (t2 >= 0.))
2042 || (sd < 0.) || ((sd > 0.) && (p.
z + sd * v.
z > 0.)))
2046 if ((sd > halfTolerance) && (p.
z + sd * v.
z <= 0.))
2051 sidetheta = kETheta;
2064 if (!fFullPhiSphere)
2070 pDistS = p.
x * sinSPhi - p.
y * cosSPhi;
2071 pDistE = -p.
x * sinEPhi + p.
y * cosEPhi;
2075 compS = -sinSPhi * v.
x + cosSPhi * v.
y;
2076 compE = sinEPhi * v.
x - cosEPhi * v.
y;
2079 if ((pDistS <= 0) && (pDistE <= 0))
2085 sphi = pDistS / compS;
2086 xi = p.
x + sphi * v.
x;
2087 yi = p.
y + sphi * v.
y;
2093 vphi = std::atan2(v.
y, v.
x);
2095 if (((fSPhi - halfAngTolerance) <= vphi)
2096 && ((ePhi + halfAngTolerance) >= vphi))
2101 else if ((yi * cosCPhi - xi * sinCPhi) >= 0)
2108 if (pDistS > -halfCarTolerance)
2121 sphi2 = pDistE / compE;
2124 xi = p.
x + sphi2 * v.
x;
2125 yi = p.
y + sphi2 * v.
y;
2133 vphi = std::atan2(v.
y, v.
x);
2135 if (!((fSPhi - halfAngTolerance <= vphi)
2136 && (fSPhi + fDPhi + halfAngTolerance >= vphi)))
2139 if (pDistE <= -halfCarTolerance)
2149 else if ((yi * cosCPhi - xi * sinCPhi) >= 0)
2152 if (pDistE <= -halfCarTolerance)
2164 else if ((pDistS >= 0) && (pDistE >= 0))
2166 if (pDistS <= pDistE)
2174 if (fDPhi > UUtils::kPi)
2176 if ((compS < 0) && (compE < 0))
2190 if ((compS >= 0) && (compE >= 0))
2200 else if ((pDistS > 0) && (pDistE < 0))
2204 if (fDPhi > UUtils::kPi)
2208 sphi = pDistE / compE;
2209 xi = p.
x + sphi * v.
x;
2210 yi = p.
y + sphi * v.
y;
2217 vphi = std::atan2(v.
y, v.
x);
2219 if (((fSPhi - halfAngTolerance) <= vphi)
2220 && ((ePhi + halfAngTolerance) >= vphi))
2225 else if ((yi * cosCPhi - xi * sinCPhi) <= 0)
2232 if (pDistE > -halfCarTolerance)
2249 sphi = pDistE / compE;
2250 xi = p.
x + sphi * v.
x;
2251 yi = p.
y + sphi * v.
y;
2258 vphi = std::atan2(v.
y, v.
x);
2260 if (((fSPhi - halfAngTolerance) <= vphi)
2261 && ((ePhi + halfAngTolerance) >= vphi))
2266 else if ((yi * cosCPhi - xi * sinCPhi) <= 0)
2289 if (fDPhi > UUtils::kPi)
2293 sphi = pDistS / compS;
2294 xi = p.
x + sphi * v.
x;
2295 yi = p.
y + sphi * v.
y;
2302 vphi = std::atan2(v.
y, v.
x);
2304 if (((fSPhi - halfAngTolerance) <= vphi)
2305 && ((ePhi + halfAngTolerance) >= vphi))
2310 else if ((yi * cosCPhi - xi * sinCPhi) >= 0)
2317 if (pDistS > -halfCarTolerance)
2334 sphi = pDistS / compS;
2335 xi = p.
x + sphi * v.
x;
2336 yi = p.
y + sphi * v.
y;
2343 vphi = std::atan2(v.
y, v.
x);
2345 if (((fSPhi - halfAngTolerance) <= vphi)
2346 && ((ePhi + halfAngTolerance) >= vphi))
2351 else if ((yi * cosCPhi - xi * sinCPhi) >= 0)
2380 vphi = std::atan2(v.
y, v.
x);
2381 if ((fSPhi - halfAngTolerance < vphi) && (vphi < ePhi + halfAngTolerance))
2411 xi = p.
x + snxt * v.
x;
2412 yi = p.
y + snxt * v.
y;
2413 zi = p.
z + snxt * v.
z;
2414 n =
UVector3(xi / fRmax, yi / fRmax, zi / fRmax);
2423 if (fDPhi <= UUtils::kPi)
2425 n =
UVector3(sinSPhi, -cosSPhi, 0);
2435 if (fDPhi <= UUtils::kPi)
2437 n =
UVector3(-sinEPhi, cosEPhi, 0);
2447 if (fSTheta == UUtils::kPi / 2)
2452 else if (fSTheta > UUtils::kPi / 2)
2454 xi = p.
x + snxt * v.
x;
2455 yi = p.
y + snxt * v.
y;
2456 rho2 = xi * xi + yi * yi;
2459 rhoSecTheta = std::sqrt(rho2 * (1 + tanSTheta2));
2460 n =
UVector3(xi / rhoSecTheta, yi / rhoSecTheta,
2461 -tanSTheta / std::sqrt(1 + tanSTheta2));
2476 if (eTheta == UUtils::kPi / 2)
2481 else if (eTheta < UUtils::kPi / 2)
2483 xi = p.
x + snxt * v.
x;
2484 yi = p.
y + snxt * v.
y;
2485 rho2 = xi * xi + yi * yi;
2488 rhoSecTheta = std::sqrt(rho2 * (1 + tanETheta2));
2489 n =
UVector3(xi / rhoSecTheta, yi / rhoSecTheta,
2490 -tanETheta / std::sqrt(1 + tanETheta2));
2507 std::ostringstream message;
2508 int oldprc = message.precision(16);
2509 message <<
"Undefined side for valid surface normal to solid."
2511 <<
"Position:" << std::endl << std::endl
2512 <<
"p.x = " << p.
x <<
" mm" << std::endl
2513 <<
"p.y = " << p.
y <<
" mm" << std::endl
2514 <<
"p.z = " << p.
z <<
" mm" << std::endl << std::endl
2515 <<
"Direction:" << std::endl << std::endl
2516 <<
"v.x = " << v.
x << std::endl
2517 <<
"v.y = " << v.
y << std::endl
2518 <<
"v.z = " << v.
z << std::endl << std::endl
2519 <<
"Proposed distance :" << std::endl << std::endl
2520 <<
"snxt = " << snxt <<
" mm" << std::endl;
2521 message.precision(oldprc);
2523 "GeomSolids1002",
Warning, 1, message.str().c_str());
2530 std::ostringstream message;
2531 int oldprc = message.precision(16);
2532 message <<
"Logic error: snxt = UUtils::Infinity() ???" << std::endl
2533 <<
"Position:" << std::endl << std::endl
2534 <<
"p.x = " << p.
x <<
" mm" << std::endl
2535 <<
"p.y = " << p.
y <<
" mm" << std::endl
2536 <<
"p.z = " << p.
z <<
" mm" << std::endl << std::endl
2537 <<
"Rp = " << std::sqrt(p.
x * p.
x + p.
y * p.
y + p.
z * p.
z)
2538 <<
" mm" << std::endl << std::endl
2539 <<
"Direction:" << std::endl << std::endl
2540 <<
"v.x = " << v.
x << std::endl
2541 <<
"v.y = " << v.
y << std::endl
2542 <<
"v.z = " << v.
z << std::endl << std::endl
2543 <<
"Proposed distance :" << std::endl << std::endl
2544 <<
"snxt = " << snxt <<
" mm" << std::endl;
2545 message.precision(oldprc);
2547 "GeomSolids1002",
Warning, 1, message.str().c_str());
2559 double safe = 0.0, safeRMin, safeRMax, safePhi, safeTheta;
2560 double rho2, rds, rho;
2561 double pTheta, dTheta1, dTheta2;
2562 rho2 = p.
x * p.
x + p.
y * p.
y;
2563 rds = std::sqrt(rho2 + p.
z * p.
z);
2564 rho = std::sqrt(rho2);
2569 int old_prc = cout.precision(16);
2572 cout <<
"Position:" << std::endl << std::endl;
2573 cout <<
"p.x = " << p.
x <<
" mm" << std::endl;
2574 cout <<
"p.y = " << p.
y <<
" mm" << std::endl;
2575 cout <<
"p.z = " << p.
z <<
" mm" << std::endl << std::endl;
2576 cout.precision(old_prc);
2578 "GeomSolids1002",
Warning, 1,
"Point p is outside !?");
2587 safeRMin = rds - fRmin;
2588 safeRMax = fRmax - rds;
2589 if (safeRMin < safeRMax)
2606 if (!fFullPhiSphere && rho)
2608 if ((p.
y * cosCPhi - p.
x * sinCPhi) <= 0)
2610 safePhi = -(p.
x * sinSPhi - p.
y * cosSPhi);
2614 safePhi = (p.
x * sinEPhi - p.
y * cosEPhi);
2627 pTheta = std::acos(p.
z / rds);
2630 pTheta += UUtils::kPi;
2632 dTheta1 = pTheta - fSTheta;
2633 dTheta2 = eTheta - pTheta;
2634 if (dTheta1 < dTheta2)
2636 safeTheta = rds * std::sin(dTheta1);
2640 safeTheta = rds * std::sin(dTheta2);
2642 if (safe > safeTheta)
2798 return std::string(
"Sphere");
2816 int oldprc = os.precision(16);
2817 os <<
"-----------------------------------------------------------\n"
2818 <<
" *** Dump for solid - " <<
GetName() <<
" ***\n"
2819 <<
" ===================================================\n"
2820 <<
" Solid type: USphere\n"
2821 <<
" Parameters: \n"
2822 <<
" inner radius: " << fRmin <<
" mm \n"
2823 <<
" outer radius: " << fRmax <<
" mm \n"
2824 <<
" starting phi of segment : " << fSPhi / (UUtils::kPi / 180.0) <<
" degrees \n"
2825 <<
" delta phi of segment : " << fDPhi / (UUtils::kPi / 180.0) <<
" degrees \n"
2826 <<
" starting theta of segment: " << fSTheta / (UUtils::kPi / 180.0) <<
" degrees \n"
2827 <<
" delta theta of segment : " << fDTheta / (UUtils::kPi / 180.0) <<
" degrees \n"
2828 <<
"-----------------------------------------------------------\n";
2829 os.precision(oldprc);
2840 double zRand, aOne, aTwo, aThr, aFou, aFiv, chose, phi, sinphi, cosphi;
2841 double height1, height2, slant1, slant2, costheta, sintheta, rRand;
2843 height1 = (fRmax - fRmin) * cosSTheta;
2844 height2 = (fRmax - fRmin) * cosETheta;
2845 slant1 = std::sqrt(
UUtils::sqr((fRmax - fRmin) * sinSTheta) + height1 * height1);
2846 slant2 = std::sqrt(
UUtils::sqr((fRmax - fRmin) * sinETheta) + height2 * height2);
2849 aOne = fRmax * fRmax * fDPhi * (cosSTheta - cosETheta);
2850 aTwo = fRmin * fRmin * fDPhi * (cosSTheta - cosETheta);
2851 aThr = fDPhi * ((fRmax + fRmin) * sinSTheta) * slant1;
2852 aFou = fDPhi * ((fRmax + fRmin) * sinETheta) * slant2;
2853 aFiv = 0.5 * fDTheta * (fRmax * fRmax - fRmin * fRmin);
2856 cosphi = std::cos(phi);
2857 sinphi = std::sin(phi);
2869 if (eTheta == UUtils::kPi)
2873 if (fSTheta == UUtils::kPi / 2)
2875 aThr = UUtils::kPi * (fRmax * fRmax - fRmin * fRmin);
2877 if (eTheta == UUtils::kPi / 2)
2879 aFou = UUtils::kPi * (fRmax * fRmax - fRmin * fRmin);
2883 if ((chose >= 0.) && (chose < aOne))
2885 return UVector3(fRmax * sintheta * cosphi,
2886 fRmax * sintheta * sinphi, fRmax * costheta);
2888 else if ((chose >= aOne) && (chose < aOne + aTwo))
2890 return UVector3(fRmin * sintheta * cosphi,
2891 fRmin * sintheta * sinphi, fRmin * costheta);
2893 else if ((chose >= aOne + aTwo) && (chose < aOne + aTwo + aThr))
2895 if (fSTheta != UUtils::kPi / 2)
2898 return UVector3(tanSTheta * zRand * cosphi,
2899 tanSTheta * zRand * sinphi, zRand);
2903 return UVector3(rRand * cosphi, rRand * sinphi, 0.);
2906 else if ((chose >= aOne + aTwo + aThr) && (chose < aOne + aTwo + aThr + aFou))
2908 if (eTheta != UUtils::kPi / 2)
2911 return UVector3(tanETheta * zRand * cosphi,
2912 tanETheta * zRand * sinphi, zRand);
2916 return UVector3(rRand * cosphi, rRand * sinphi, 0.);
2919 else if ((chose >= aOne + aTwo + aThr + aFou) && (chose < aOne + aTwo + aThr + aFou + aFiv))
2921 return UVector3(rRand * sintheta * cosSPhi,
2922 rRand * sintheta * sinSPhi, rRand * costheta);
2926 return UVector3(rRand * sintheta * cosEPhi,
2927 rRand * sintheta * sinEPhi, rRand * costheta);
2937 if (fSurfaceArea != 0.)
2943 double Rsq = fRmax * fRmax;
2944 double rsq = fRmin * fRmin;
2946 fSurfaceArea = fDPhi * (rsq + Rsq) * (cosSTheta - cosETheta);
2947 if (!fFullPhiSphere)
2949 fSurfaceArea = fSurfaceArea + fDTheta * (Rsq - rsq);
2953 double acos1 = std::acos(std::pow(sinSTheta, 2) * std::cos(fDPhi)
2954 + std::pow(cosSTheta, 2));
2955 if (fDPhi > UUtils::kPi)
2957 fSurfaceArea = fSurfaceArea + 0.5 * (Rsq - rsq) * (2 * UUtils::kPi - acos1);
2961 fSurfaceArea = fSurfaceArea + 0.5 * (Rsq - rsq) * acos1;
2964 if (eTheta < UUtils::kPi)
2966 double acos2 = std::acos(std::pow(sinETheta, 2) * std::cos(fDPhi)
2967 + std::pow(cosETheta, 2));
2968 if (fDPhi > UUtils::kPi)
2970 fSurfaceArea = fSurfaceArea + 0.5 * (Rsq - rsq) * (2 * UUtils::kPi - acos2);
2974 fSurfaceArea = fSurfaceArea + 0.5 * (Rsq - rsq) * acos2;
2978 return fSurfaceArea;
static double frTolerance
double GetInnerRadius() const
const std::string & GetName() const
VUSolid::EnumInside Inside(const UVector3 &p) const
void Extent(UVector3 &aMin, UVector3 &aMax) const
double DistanceToOut(const UVector3 &p, const UVector3 &v, UVector3 &n, bool &validNorm, double aPstep=UUtils::kInfinity) const
double GetDeltaThetaAngle() const
USphere & operator=(const USphere &rhs)
double GetOuterRadius() const
double DistanceToIn(const UVector3 &p, const UVector3 &v, double aPstep=UUtils::kInfinity) const
static double Tolerance()
UVector3 GetPointOnSurface() const
double SafetyFromOutside(const UVector3 &p, bool aAccurate=false) const
UGeometryType GetEntityType() const
static double faTolerance
double GetRadiusInRing(double rmin, double rmax)
USphere(const std::string &pName, double pRmin, double pRmax, double pSPhi, double pDPhi, double pSTheta, double pDTheta)
void Set(double xx, double yy, double zz)
void GetParametersList(int, double *) const
T max(const T t1, const T t2)
brief Return the largest of the two arguments
double GetStartThetaAngle() const
std::ostream & StreamInfo(std::ostream &os) const
std::string UGeometryType
bool Normal(const UVector3 &p, UVector3 &n) const
double GetStartPhiAngle() const
void Exception(const char *originOfException, const char *exceptionCode, ExceptionSeverity severity, int level, const char *description)
double Random(double min=0.0, double max=1.0)
double GetDeltaPhiAngle() const
double SafetyFromInside(const UVector3 &p, bool aAccurate=false) const