31#include <boost/accumulators/accumulators.hpp>
32#include <boost/accumulators/statistics/error_of_mean.hpp>
33#include <boost/accumulators/statistics/mean.hpp>
34#include <boost/accumulators/statistics/stats.hpp>
42#include <unordered_set>
51constexpr double VALID_INTERCEPT_POINT_SHIFT{2.5e-05};
65double triangleSolidAngle(
const V3D &a,
const V3D &b,
const V3D &c,
const V3D &observer) {
66 const V3D ao = a - observer;
67 const V3D bo = b - observer;
68 const V3D co = c - observer;
69 const double modao = ao.
norm();
70 const double modbo = bo.
norm();
71 const double modco = co.
norm();
76 const double denom = modao * modbo * modco + modco * aobo + modbo * aoco + modao * boco;
78 return 2.0 * atan2(scalTripProd, denom);
93 const double radius,
const double height) {
102 constexpr V3D initial_axis(0., 0., 1.0);
103 const Quat transform(initial_axis, axis_direction);
108 std::array<double, Mantid::Geometry::Cone::g_NSLICES> cos_table;
109 std::array<double, Mantid::Geometry::Cone::g_NSLICES> sin_table;
111 double solid_angle(0.0);
114 cos_table[vertex] = std::cos(angle_step * vertex);
115 sin_table[vertex] = std::sin(angle_step * vertex);
116 V3D pt2 =
V3D(radius * cos_table[vertex], radius * sin_table[vertex], 0.0);
120 cos_table[vertex] = std::cos(angle_step * vertex);
121 sin_table[vertex] = std::sin(angle_step * vertex);
125 V3D pt3 =
V3D(radius * cos_table[vertex], radius * sin_table[vertex], 0.0);
127 transform.rotate(pt2);
128 transform.rotate(pt3);
132 double sa = triangleSolidAngle(
centre, pt2, pt3, observer);
141 double z0(0.0), z1(z_step);
142 double r0(radius), r1(r0 - r_step);
149 V3D pt1 =
V3D(r0 * cos_table[vertex], r0 * sin_table[vertex], z0);
154 V3D pt3 =
V3D(r0 * cos_table[vertex], r0 * sin_table[vertex], z0);
157 V3D pt2 =
V3D(r1 * cos_table[vertex], r1 * sin_table[vertex], z1);
162 V3D pt4 =
V3D(r1 * cos_table[vertex], r1 * sin_table[vertex], z1);
164 transform.rotate(pt1);
165 transform.rotate(pt3);
166 transform.rotate(pt2);
167 transform.rotate(pt4);
173 double sa = triangleSolidAngle(pt1, pt4, pt3, observer);
177 sa = triangleSolidAngle(pt1, pt2, pt4, observer);
191 transform.
rotate(top_centre);
196 V3D pt2 =
V3D(r0 * cos_table[vertex], r0 * sin_table[vertex],
height);
202 V3D pt3 =
V3D(r0 * cos_table[vertex], r0 * sin_table[vertex],
height);
205 transform.rotate(pt2);
206 transform.rotate(pt3);
211 double sa = triangleSolidAngle(top_centre, pt3, pt2, observer);
228double cuboidSolidAngle(
const V3D &observer,
const std::vector<V3D> &vectors) {
233 std::vector<V3D> pts;
235 const V3D dx = vectors[1] - vectors[0];
236 const V3D dz = vectors[3] - vectors[0];
237 pts.emplace_back(vectors[2]);
238 pts.emplace_back(vectors[2] + dx);
239 pts.emplace_back(vectors[1]);
240 pts.emplace_back(vectors[0]);
241 pts.emplace_back(vectors[2] + dz);
242 pts.emplace_back(vectors[2] + dz + dx);
243 pts.emplace_back(vectors[1] + dz);
244 pts.emplace_back(vectors[0] + dz);
246 constexpr unsigned int ntriangles(12);
247 std::vector<std::vector<int>> triMap(ntriangles, std::vector<int>(3, 0));
285 for (
unsigned int i = 0; i < ntriangles; i++) {
286 const double sa = triangleSolidAngle(pts[triMap[i][0] - 1], pts[triMap[i][1] - 1], pts[triMap[i][2] - 1], observer);
303double cylinderSolidAngle(
const V3D &observer,
const V3D &
centre,
const V3D &axis,
const double radius,
304 const double height,
const int numberOfSlices) {
313 constexpr V3D initial_axis(0., 0., 1.0);
314 const Quat transform(initial_axis, axis);
317 const double angle_step = 2 * M_PI /
static_cast<double>(numberOfSlices);
320 double z0(0.0), z1(z_step);
321 double solid_angle(0.0);
328 for (
int sl = 0; sl < numberOfSlices; ++sl) {
329 double x = radius * std::cos(angle_step * sl);
330 double y = radius * std::sin(angle_step * sl);
333 int vertex = (sl + 1) % numberOfSlices;
334 x = radius * std::cos(angle_step * vertex);
335 y = radius * std::sin(angle_step * vertex);
339 transform.rotate(pt1);
340 transform.rotate(pt3);
341 transform.rotate(pt2);
342 transform.rotate(pt4);
349 double sa = triangleSolidAngle(pt1, pt4, pt3, observer);
353 sa = triangleSolidAngle(pt1, pt2, pt4, observer);
373double sphereSolidAngle(
const V3D &observer,
const std::vector<V3D> &vectors,
const double radius) {
374 const double distance = (observer - vectors[0]).norm();
375 if (distance > radius + Tolerance) {
376 const double sa = 2.0 * M_PI * (1.0 - cos(asin(radius / distance)));
378 }
else if (distance < radius - Tolerance)
400 : m_topRule(nullptr), m_boundingBox(), AABBxMax(0), AABByMax(0), AABBzMax(0), AABBxMin(0), AABByMin(0), AABBzMin(0),
401 boolBounded(false), m_objNum(0), m_handler(
std::make_shared<
GeometryHandler>(this)), bGeometryCaching(false),
480 static const boost::regex letters(
"[a-zA-Z]");
509 std::string::size_type pos = TopStr.find(
'#');
510 std::ostringstream cx;
511 while (pos != std::string::npos) {
513 cx << TopStr.substr(0, pos);
518 auto vc = MList.find(cN);
519 if (vc == MList.end())
523 cx << vc->second.cellStr(MList);
527 TopStr.erase(0, pos);
528 pos = TopStr.find(
'#');
554 std::deque<Rule *> rules;
556 while (!rules.empty()) {
557 Rule *T1 = rules.front();
561 auto *surface =
dynamic_cast<SurfPoint *
>(T1);
564 auto mapFound = surfMap.find(surface->getKeyN());
565 if (mapFound != surfMap.end()) {
566 surface->
setKey(mapFound->second);
576 rules.emplace_back(TA);
578 rules.emplace_back(TB);
597int CSGObject::procPair(std::string &lineStr, std::map<
int, std::unique_ptr<Rule>> &ruleMap,
int &compUnit)
const
604 for (Rstart = 0; Rstart < lineStr.size() && lineStr[Rstart] !=
'R'; Rstart++)
611 ruleMap.find(Ra) == ruleMap.end())
614 for (Rend = Rstart + 1; Rend < lineStr.size() && lineStr[Rend] !=
'R'; Rend++) {
615 if (lineStr[Rend] ==
':')
619 ruleMap.find(Rb) == ruleMap.end()) {
625 for (Rend++; Rend < lineStr.size() && lineStr[Rend] >=
'0' && lineStr[Rend] <=
'9'; Rend++)
630 (type) ? std::unique_ptr<Rule>(std::make_unique<Union>(std::move(ruleMap[Ra]), std::move(ruleMap[Rb])))
631 : std::unique_ptr<Rule>(std::make_unique<Intersection>(std::move(ruleMap[Ra]), std::move(ruleMap[Rb])));
632 ruleMap[Ra] = std::move(Join);
633 ruleMap.erase(ruleMap.find(Rb));
637 for (strPos = Rstart - 1; strPos >= 0 && lineStr[strPos] ==
' '; strPos--)
639 Rstart = (strPos < 0) ? 0 : strPos;
640 for (strPos = Rend; strPos < static_cast<int>(lineStr.size()) && lineStr[strPos] ==
' '; strPos++)
644 std::stringstream newRuleStr;
645 newRuleStr <<
" R" << Ra <<
" ";
646 lineStr.replace(Rstart, Rend, newRuleStr.str());
658 return std::make_unique<CompGrp>();
661 const Rule *RItemptr = ruleItem.get();
662 auto CG = std::make_unique<CompGrp>(Pptr, std::move(ruleItem));
664 const int Ln = Pptr->
findLeaf(RItemptr);
665 Pptr->
setLeaf(std::move(CG), Ln);
667 return std::make_unique<CompGrp>();
691 std::vector<Kernel::V3D> Snorms;
695 if ((*vc)->onSurface(point)) {
696 Snorms.emplace_back((*vc)->surfaceNormal(point));
704 for (
auto xs = Snorms.begin(); xs != Snorms.end(); ++xs)
705 for (
auto ys = std::next(xs); ys != Snorms.end(); ++ys) {
706 NormPair = (*ys) + (*xs);
711 }
catch (std::runtime_error &) {
767 std::stack<const Rule *> TreeLine;
769 while (!TreeLine.empty()) {
770 const Rule *tmpA = TreeLine.top();
780 const auto *SurX =
dynamic_cast<const SurfPoint *
>(tmpA);
787 std::unordered_set<const Surface *> uniqueSurfacePtrs;
790 if (uniqueSurfacePtrs.find(sPtr) != std::end(uniqueSurfacePtrs)) {
793 uniqueSurfacePtrs.insert(sPtr);
797 m_surList.erase(newEnd, m_surList.end());
801 std::vector<const Surface *>::const_iterator vc;
802 for (vc = m_surList.begin(); vc != m_surList.end(); ++vc) {
803 logger.debug() <<
"Point == " << *vc <<
'\n';
804 logger.debug() << (*vc)->getName() <<
'\n';
815 std::vector<int> out;
816 transform(
m_surList.begin(),
m_surList.end(), std::insert_iterator<std::vector<int>>(out, out.begin()),
847 const int out =
m_topRule->substituteSurf(surfNum, newSurfNum, surfPtr);
857 std::deque<Rule *> rst;
858 std::vector<int> Cells;
863 while (!rst.empty()) {
864 const Rule *T1 = rst.front();
868 const auto *surface =
dynamic_cast<const SurfPoint *
>(T1);
870 Cells.emplace_back(surface->getKeyN());
875 rst.emplace_back(TA);
877 rst.emplace_back(TB);
882 logger.debug() <<
"Name == " <<
m_objNum <<
'\n';
883 logger.debug() <<
"Rules == " << Rcount <<
'\n';
884 std::vector<int>::const_iterator mc;
885 logger.debug() <<
"Surface included == ";
886 for (mc = Cells.begin(); mc < Cells.end(); ++mc) {
887 logger.debug() << (*mc) <<
" ";
889 logger.debug() <<
'\n';
904 logger.debug() <<
"Name == " <<
m_objNum <<
'\n';
905 logger.debug() <<
m_topRule->display() <<
'\n';
914 std::ostringstream objStr;
926 std::ostringstream objStr;
940 std::ostringstream objStr;
941 objStr.precision(10);
953 std::map<int, std::unique_ptr<Rule>> RuleList;
957 std::unique_ptr<SurfPoint> TmpR;
958 std::unique_ptr<CompObj> TmpO;
960 std::string Ln = lineStr;
962 std::ostringstream cx;
963 const std::string::size_type length = Ln.length();
964 for (
size_t i = 0; i < length; i++) {
965 if (isdigit(Ln[i]) || Ln[i] ==
'-') {
969 throw std::invalid_argument(
"Invalid surface string in Object::ProcString : " + lineStr);
971 if (i != 0 && Ln[i - 1] ==
'#') {
972 TmpO = std::make_unique<CompObj>();
974 RuleList[Ridx] = std::move(TmpO);
977 TmpR = std::make_unique<SurfPoint>();
979 RuleList[Ridx] = std::move(TmpR);
981 cx <<
" R" << Ridx <<
" ";
991 int brack_exists = 1;
992 while (brack_exists) {
993 std::string::size_type rbrack = Ln.find(
')');
994 std::string::size_type lbrack = Ln.rfind(
'(', rbrack);
995 if (rbrack != std::string::npos && lbrack != std::string::npos) {
996 std::string Lx = Ln.substr(lbrack + 1, rbrack - lbrack - 1);
999 while (
procPair(Lx, RuleList, compUnit))
1001 Ln.replace(lbrack, 1 + rbrack - lbrack, Lx);
1004 for (hCnt =
static_cast<int>(lbrack) - 1; hCnt >= 0 && isspace(Ln[hCnt]); hCnt--)
1006 if (hCnt >= 0 && Ln[hCnt] ==
'#') {
1007 RuleList[compUnit] =
procComp(std::move(RuleList[compUnit]));
1008 Ln.erase(hCnt, lbrack - hCnt);
1015 while (
procPair(Ln, RuleList, nullInt)) {
1018 if (RuleList.size() == 1) {
1019 m_topRule = std::move((RuleList.begin())->second);
1021 throw std::logic_error(
"Object::procString() - Unexpected number of "
1022 "surface rules found. Expected=1, found=" +
1034 int originalCount = track.
count();
1041 surface->acceptVisitor(LI);
1054 const size_t nPoints(IPoints.size());
1057 for (
size_t i = 0; i < nPoints; i++) {
1063 const auto ¤tPt(IPoints[i]);
1064 const auto &prePt((i == 0 || dPoints[i - 1] <= 0) ? track.
startPoint() : IPoints[i - 1]);
1065 const auto &nextPt(i + 1 < nPoints ? IPoints[i + 1] : currentPt + currentPt - prePt);
1071 track.
addPoint(trackType, currentPt, *
this);
1077 return (track.
count() - originalCount);
1089 surface->acceptVisitor(LI);
1093 if (!distances.empty()) {
1094 return std::abs(*std::min_element(std::begin(distances), std::end(distances)));
1096 std::ostringstream os;
1097 os <<
"Unable to find intersection with object with track starting at " << track.
startPoint() <<
" in direction "
1099 throw std::runtime_error(os.str());
1115 const Kernel::V3D shift(uVec * VALID_INTERCEPT_POINT_SHIFT);
1116 const int flagA =
isValid(point - shift);
1117 const int flagB =
isValid(point + shift);
1118 if (!(flagA ^ flagB))
1135 const auto upstreamPt = (prePt + curPt) * 0.5;
1136 const auto upstreamPtInsideShape =
isValid(upstreamPt);
1138 const auto downstreamPt = (curPt + nxtPt) * 0.5;
1139 const auto downstreamPtInsideShape =
isValid(downstreamPt);
1157 if (!(upstreamPtInsideShape ^ downstreamPtInsideShape))
1206 const int resNoBB = 200, resPhiMin = 10;
1207 int res = resNoBB, itheta, jphi, resPhi;
1208 double theta, phi, sum, dphi, dtheta;
1215 double thetaMax = M_PI;
1216 bool useBB =
false, usePt =
false;
1222 useBB = usePt =
true;
1225 const int resBB = 100;
1235 ptInObject -= observer;
1236 double theta0 = -180.0 / M_PI * acos(ptInObject.
Z() / ptInObject.
norm());
1241 zToPt(theta0, axis);
1243 dtheta = thetaMax / res;
1244 int count = 0, countPhi;
1246 for (itheta = 1; itheta <= res; itheta++) {
1248 theta = thetaMax * (itheta - 0.5) / res;
1249 resPhi =
static_cast<int>(res * sin(theta));
1250 if (resPhi < resPhiMin)
1252 dphi = 2 * M_PI / resPhi;
1254 for (jphi = 1; jphi <= resPhi; jphi++) {
1256 phi = 2.0 * M_PI * (jphi - 0.5) / resPhi;
1257 Kernel::V3D dir(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
1261 Track tr(observer, dir);
1263 sum += dtheta * dphi * sin(theta);
1270 if (!useBB && countPhi == 0)
1274 if (!useBB &&
count < resPhiMin + 1) {
1277 thetaMax = thetaMax * (itheta - 0.5) / res;
1278 dtheta = thetaMax / res;
1280 for (itheta = 1; itheta <= res; itheta++) {
1281 theta = thetaMax * (itheta - 0.5) / res;
1282 resPhi =
static_cast<int>(res * sin(theta));
1283 if (resPhi < resPhiMin)
1285 dphi = 2 * M_PI / resPhi;
1287 for (jphi = 1; jphi <= resPhi; jphi++) {
1288 phi = 2.0 * M_PI * (jphi - 0.5) / resPhi;
1289 Kernel::V3D dir(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
1292 Track tr(observer, dir);
1294 sum += dtheta * dphi * sin(theta);
1319 const auto &observer = params.
observer();
1324 return (2.0 * M_PI);
1326 return (4.0 * M_PI);
1331 double height(0.0), radius(0.0), innerRadius(0.0);
1333 std::vector<Mantid::Kernel::V3D> geometry_vectors;
1335 geometry_vectors.reserve(4);
1342 return cuboidSolidAngle(observer, geometry_vectors);
1345 return sphereSolidAngle(observer, geometry_vectors, radius);
1348 return cylinderSolidAngle(observer, geometry_vectors[0], geometry_vectors[1], radius,
height,
1352 return coneSolidAngle(observer, geometry_vectors[0], geometry_vectors[1], radius,
height);
1361 double sangle(0.0), sneg(0.0);
1362 for (
size_t i = 0; i < nTri; i++) {
1363 int p1 = faces[i * 3], p2 = faces[i * 3 + 1], p3 = faces[i * 3 + 2];
1364 V3D vp1 =
V3D(vertices[3 * p1], vertices[3 * p1 + 1], vertices[3 * p1 + 2]);
1365 V3D vp2 =
V3D(vertices[3 * p2], vertices[3 * p2 + 1], vertices[3 * p2 + 2]);
1366 V3D vp3 =
V3D(vertices[3 * p3], vertices[3 * p3 + 1], vertices[3 * p3 + 2]);
1367 double sa = triangleSolidAngle(vp1, vp2, vp3, observer);
1386 return 0.5 * (sangle - sneg);
1406 const auto &observer = params.
observer();
1408 double sx = scaleFactor[0], sy = scaleFactor[1], sz = scaleFactor[2];
1409 const V3D sObserver = observer;
1413 return (2.0 * M_PI);
1415 return (4.0 * M_PI);
1426 double height = 0.0, radius(0.0), innerRadius;
1428 std::vector<Kernel::V3D> vectors;
1432 std::transform(vectors.begin(), vectors.end(), vectors.begin(),
1433 [scaleFactor](
const V3D &v) { return v * scaleFactor; });
1434 return cuboidSolidAngle(observer, vectors);
1437 return sphereSolidAngle(observer, vectors, radius);
1450 double sangle(0.0), sneg(0.0);
1451 for (
size_t i = 0; i < nTri; i++) {
1452 int p1 = faces[i * 3], p2 = faces[i * 3 + 1], p3 = faces[i * 3 + 2];
1455 V3D vp1 =
V3D(sx * vertices[3 * p1], sy * vertices[3 * p1 + 1], sz * vertices[3 * p1 + 2]);
1456 V3D vp2 =
V3D(sx * vertices[3 * p2], sy * vertices[3 * p2 + 1], sz * vertices[3 * p2 + 2]);
1457 V3D vp3 =
V3D(sx * vertices[3 * p3], sy * vertices[3 * p3 + 1], sz * vertices[3 * p3 + 2]);
1458 double sa = triangleSolidAngle(vp1, vp2, vp3, observer);
1464 return (0.5 * (sangle - sneg));
1477 std::vector<Kernel::V3D> vectors;
1484 double volumeTri = 0.0;
1508 return volumeTri / 6;
1511 return 4.0 / 3.0 * M_PI * radius * radius * radius;
1513 return M_PI * radius * radius *
height;
1515 return M_PI *
height * (radius * radius - innerRadius * innerRadius);
1529 using namespace boost::accumulators;
1530 const int singleShotIterations = 10000;
1531 accumulator_set<double, features<tag::mean, tag::error_of<tag::mean>>> accumulate;
1533 std::ranlux48 rnEngine;
1535 for (
int i = 0; i < 10; ++i) {
1536 const auto seed = rnEngine();
1538 accumulate(volumeMc);
1540 const double relativeErrorTolerance = 1e-3;
1542 double currentError;
1544 const auto seed = rnEngine();
1546 accumulate(volumeMc);
1547 currentMean = mean(accumulate);
1548 currentError = error_of<tag::mean>(accumulate);
1549 if (std::isnan(currentError)) {
1552 }
while (currentError / currentMean > relativeErrorTolerance);
1564 if (boundingBox.isNull()) {
1565 throw std::runtime_error(
"Cannot calculate volume: invalid bounding box.");
1568 const double boundingDx = boundingBox.xMax() - boundingBox.xMin();
1569 const double boundingDy = boundingBox.yMax() - boundingBox.yMin();
1570 const double boundingDz = boundingBox.zMax() - boundingBox.zMin();
1574 size_t blocksize = shotSize / threadCount;
1576 if (currentThreadNum == threadCount - 1) {
1579 blocksize = shotSize - (threadCount - 1) * blocksize;
1581 std::mt19937 rnEngine(
static_cast<std::mt19937::result_type
>(seed));
1587 rnEngine.discard(currentThreadNum * 3 * blocksize);
1588 std::uniform_real_distribution<double> rnDistribution(0.0, 1.0);
1590 for (
int i = 0; i < static_cast<int>(blocksize); ++i) {
1591 double rnd = rnDistribution(rnEngine);
1592 const double x = boundingBox.xMin() + rnd * boundingDx;
1593 rnd = rnDistribution(rnEngine);
1594 const double y = boundingBox.yMin() + rnd * boundingDy;
1595 rnd = rnDistribution(rnEngine);
1596 const double z = boundingBox.zMin() + rnd * boundingDz;
1605 const double ratio =
static_cast<double>(totalHits) /
static_cast<double>(shotSize);
1606 const double boundingVolume = boundingDx * boundingDy * boundingDz;
1607 return ratio * boundingVolume;
1667 const double huge(1e10);
1668 const double big(1e4);
1669 double minX(-huge), minY(-huge), minZ(-huge);
1670 double maxX(huge), maxY(huge), maxZ(huge);
1673 m_topRule->getBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
1677 if (minX > -big && maxX < big && minY > -big && maxY < big && minZ > -big && maxZ < big && minX <= maxX &&
1678 minY <= maxY && minZ <= maxZ) {
1696 if (vertCount > 0) {
1699 constexpr double huge = 1e10;
1700 double minX, maxX, minY, maxY, minZ, maxZ;
1701 minX = minY = minZ = huge;
1702 maxX = maxY = maxZ = -huge;
1705 for (
size_t i = 0; i < vertCount; ++i) {
1706 auto vx = vertArray[3 * i + 0];
1707 auto vy = vertArray[3 * i + 1];
1708 auto vz = vertArray[3 * i + 2];
1710 minX = std::min(minX, vx);
1711 maxX = std::max(maxX, vx);
1712 minY = std::min(minY, vy);
1713 maxY = std::max(maxY, vy);
1714 minZ = std::min(minZ, vz);
1715 maxZ = std::max(maxZ, vz);
1735 double minX, maxX, minY, maxY, minZ, maxZ;
1739 std::vector<Kernel::V3D> vectors;
1750 const auto &lfb = vectors[0];
1751 const auto &lft = vectors[1];
1752 const auto &lbb = vectors[2];
1753 const auto &rfb = vectors[3];
1756 auto lbt = lft + (lbb - lfb);
1757 auto rft = rfb + (lft - lfb);
1758 auto rbb = lbb + (rfb - lfb);
1759 auto rbt = rbb + (rft - rfb);
1761 vectors.emplace_back(lbt);
1762 vectors.emplace_back(rft);
1763 vectors.emplace_back(rbb);
1764 vectors.emplace_back(rbt);
1767 constexpr double huge = 1e10;
1768 minX = minY = minZ = huge;
1769 maxX = maxY = maxZ = -huge;
1772 for (
const auto &vector : vectors) {
1773 minX = std::min(minX, vector.X());
1774 maxX = std::max(maxX, vector.X());
1775 minY = std::min(minY, vector.Y());
1776 maxY = std::max(maxY, vector.Y());
1777 minZ = std::min(minZ, vector.Z());
1778 maxZ = std::max(maxZ, vector.Z());
1783 minX = minY = minZ = std::numeric_limits<
decltype(minZ)>::max();
1784 maxX = maxY = maxZ = -std::numeric_limits<
decltype(maxZ)>::max();
1787 for (
const auto &vector : vectors) {
1788 minX = std::min(minX, vector.X());
1789 maxX = std::max(maxX, vector.X());
1790 minY = std::min(minY, vector.Y());
1791 maxY = std::max(maxY, vector.Y());
1792 minZ = std::min(minZ, vector.Z());
1793 maxZ = std::max(maxZ, vector.Z());
1798 const auto &base = vectors[0];
1799 const auto &axis = vectors[1];
1805 volatile auto rx = radius * sqrt(pow(axis.
Y(), 2) + pow(axis.
Z(), 2));
1806 volatile auto ry = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Z(), 2));
1807 volatile auto rz = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Y(), 2));
1811 minX = std::min(base.X(),
top.X()) - rx;
1812 maxX = std::max(base.X(),
top.X()) + rx;
1813 minY = std::min(base.Y(),
top.Y()) - ry;
1814 maxY = std::max(base.Y(),
top.Y()) + ry;
1815 minZ = std::min(base.Z(),
top.Z()) - rz;
1816 maxZ = std::max(base.Z(),
top.Z()) + rz;
1820 const auto &tip = vectors[0];
1821 const auto &axis = vectors[1];
1822 auto base = tip + (axis *
height);
1827 auto rx = radius * sqrt(pow(axis.
Y(), 2) + pow(axis.
Z(), 2));
1828 auto ry = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Z(), 2));
1829 auto rz = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Y(), 2));
1832 minX = std::min(tip.X(), base.X() - rx);
1833 maxX = std::max(tip.X(), base.X() + rx);
1834 minY = std::min(tip.Y(), base.Y() - ry);
1835 maxY = std::max(tip.Y(), base.Y() + ry);
1836 minZ = std::min(tip.Z(), base.Z() - rz);
1837 maxZ = std::max(tip.Z(), base.Z() + rz);
1861 double &zmin)
const {
1863 xmax = ymax = zmax = xmin = ymin = zmin = 0.0;
1874 if (
AABBxMax >= xmax || AABBxMin <= xmin || AABByMax >= ymax || AABByMin <= ymin || AABBzMax >= zmax ||
1903 const double &yMin,
const double &zMin) {
1962 const size_t maxAttempts)
const {
1963 std::optional<V3D> point{std::nullopt};
1971 const size_t bruteForceAttempts{std::min(
static_cast<size_t>(5), maxAttempts)};
2009 const size_t maxAttempts)
const {
2010 std::optional<V3D> point{std::nullopt};
2017 const size_t bruteForceAttempts{std::min(
static_cast<size_t>(5), maxAttempts)};
2021 std::vector<Kernel::V3D> shapeVectors;
2026 switch (shapeGeometry) {
2028 point = RandomPoint::bounded<RandomPoint::inCuboid>(
m_handler->shapeInfo(), rng, activeRegion,
2029 maxAttempts - bruteForceAttempts);
2032 point = RandomPoint::bounded<RandomPoint::inCylinder>(
m_handler->shapeInfo(), rng, activeRegion,
2033 maxAttempts - bruteForceAttempts);
2036 point = RandomPoint::bounded<RandomPoint::inHollowCylinder>(
m_handler->shapeInfo(), rng, activeRegion,
2037 maxAttempts - bruteForceAttempts);
2040 point = RandomPoint::bounded<RandomPoint::inSphere>(
m_handler->shapeInfo(), rng, activeRegion,
2041 maxAttempts - bruteForceAttempts);
2063 for (
const auto &dir :
2064 {
V3D(1., 0., 0.),
V3D(-1., 0., 0.),
V3D(0., 1., 0.),
V3D(0., -1., 0.),
V3D(0., 0., 1.),
V3D(0., 0., -1.)}) {
2067 point = tr.
cbegin()->entryPoint;
2168 static const std::vector<double> empty;
2171 return m_handler->getTriangleVertices();
2178 static const std::vector<uint32_t> empty;
2196 throw std::logic_error(
"CSGObject has no ShapeInfo to return");
2204 double &innerRadius,
double &radius,
double &
height)
const {
#define PARALLEL_THREAD_NUMBER
#define PARALLEL_CRITICAL(name)
#define PARALLEL_NUMBER_OF_THREADS
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
bool isPointInside(const Kernel::V3D &point) const
Is the given point within the bounding box?
double angularWidth(const Kernel::V3D &observer) const
Calculate the angular half width from the given point.
bool isNonNull() const
Is the box considered valid. Convenience for !isNull()
bool doesLineIntersect(const Track &track) const
Does a specified track intersect the bounding box.
static void checkValid(double xmax, double ymax, double zmax, double xmin, double ymin, double zmin)
Do the given arguments form a valid bounding box, throws std::invalid argument if not.
Kernel::V3D centrePoint() const
Returns the centre of the bounding box.
Constructive Solid Geometry object.
void setVtkGeometryCacheWriter(std::shared_ptr< vtkGeometryCacheWriter >)
set vtkGeometryCache writer
int m_objNum
Creation number.
std::shared_ptr< vtkGeometryCacheReader > vtkCacheReader
a pointer to a class for reading from the geometry cache
std::string cellCompStr() const
Write the object to a string.
std::string m_shapeXML
original shape xml used to generate this object.
bool isValid(const Kernel::V3D &) const override
Check if a point is valid.
void makeComplement()
Takes the complement of a group.
void updateGeometryHandler()
Updates the geometry handler if needed.
void GetObjectGeom(detail::ShapeInfo::GeometryShape &type, std::vector< Kernel::V3D > &vectors, double &innerRadius, double &radius, double &height) const override
get info on standard shapes
int createSurfaceList(const int outFlag=0)
create Surface list
int setObject(const int objName, const std::string &lineStr)
Object line == cell.
void setGeometryHandler(const std::shared_ptr< GeometryHandler > &h)
Set Geometry Handler.
int checkSurfaceValid(const Kernel::V3D &, const Kernel::V3D &) const
Determine if a point is valid by checking both directions of the normal away from the line A good poi...
double solidAngle(const SolidAngleParams ¶ms) const override
Find solid angle of object wrt the observer.
double AABByMin
xmin of Axis aligned bounding box cache
const BoundingBox & getBoundingBox() const override
Return cached value of axis-aligned bounding box.
const Kernel::Material & material() const override
std::string cellStr(const std::map< int, CSGObject > &) const
Returns just the cell string object.
std::vector< const Surface * > m_surList
Full surfaces (make a map.
int substituteSurf(const int surfNum, const int newSurfNum, const std::shared_ptr< Surface > &surfPtr)
Removes a surface and then re-builds the cell.
double AABBzMin
zmin of Axis Aligned Bounding Box Cache
double volume() const override
Calculates the volume of this object.
int getPointInObject(Kernel::V3D &point) const override
Try to find a point that lies within (or on) the object.
const std::vector< uint32_t > & getTriangleFaces() const
get faces
int removeSurface(const int surfNum)
Removes a surface and then re-builds the cell.
~CSGObject() override
Destructor.
std::unique_ptr< CompGrp > procComp(std::unique_ptr< Rule >) const
Takes a Rule item and makes it a complementary group.
void write(std::ostream &) const
MCNPX output.
int procPair(std::string &lineStr, std::map< int, std::unique_ptr< Rule > > &ruleMap, int &compUnit) const
This takes a string lineStr, finds the first two Rxxx function, determines their join type make the r...
double singleShotMonteCarloVolume(const int shotSize, const size_t seed) const
Returns the volume.
void convertComplement(const std::map< int, CSGObject > &)
Returns just the cell string object.
const std::vector< double > & getTriangleVertices() const
get vertices
std::string m_id
Optional string identifier.
std::unique_ptr< Kernel::Material > m_material
material composition
size_t numberOfTriangles() const
void setNullBoundingBox()
Set a null bounding box for this object.
std::string getShapeXML() const
Getter for the shape xml.
void setMaterial(const Kernel::Material &material) override
int searchForObject(Kernel::V3D &) const
Try to find a point that lies within (or on) the object, given a seed point.
double rayTraceSolidAngle(const Kernel::V3D &observer) const
Given an observer position find the approximate solid angle of the object.
std::shared_ptr< GeometryHandler > getGeometryHandler() const override
Returns the geometry handler.
void draw() const override
Draws the Object using geometry handler, If the handler is not set then this function does nothing.
double AABBzMax
zmax of Axis aligned bounding box cache
CSGObject & operator=(const CSGObject &)
Assignment operator.
double AABBxMin
xmin of Axis aligned bounding box cache
std::shared_ptr< GeometryHandler > m_handler
Geometry Handle for rendering.
virtual void print() const
Prints almost everything.
double distance(const Track &track) const override
Compute the distance to the first point of intersection with the surface.
const Rule * topRule() const
Return the top rule.
double AABByMax
ymax of Axis aligned bounding box cache
void calcBoundingBoxByRule()
Calculate bounding box using Rule system.
double triangulatedSolidAngle(const SolidAngleParams ¶ms) const
Find solid angle of object from point "observer" using the OC triangulation of the object,...
bool bGeometryCaching
Is geometry caching enabled?
CSGObject()
Default constructor.
std::string str() const
Write the object to a string.
double monteCarloVolume() const
Returns the volume.
std::vector< int > getSurfaceIndex() const
Returns all of the numbers of surfaces.
Mantid::Geometry::TrackDirection calcValidTypeBy3Points(const Kernel::V3D &prePt, const Kernel::V3D &curPt, const Kernel::V3D &nxtPt) const
Check if an intercept is guiding the ray into the shape or leaving the shape.
void initDraw() const override
Initializes/prepares the object to be rendered, this will generate geometry for object,...
void procString(const std::string &lineStr)
Processes the cell string.
bool hasValidShape() const override
Return whether this object has a valid shape.
std::shared_ptr< vtkGeometryCacheWriter > vtkCacheWriter
a pointer to a class for writing to the geometry cache
int hasComplement() const
Determine if the object has a complementary object.
double AABBxMax
xmax of Axis aligned bounding box cache
BoundingBox m_boundingBox
Object's bounding box.
const detail::ShapeInfo & shapeInfo() const override
Mantid::Geometry::TrackDirection calcValidType(const Kernel::V3D &Pt, const Kernel::V3D &uVec) const
Calculate if a point PT is a valid point on the track.
bool boolBounded
flag true if a bounding box exists, either by
bool isOnSide(const Kernel::V3D &) const override
void calcBoundingBoxByVertices()
Calculate bounding box using object's vertices.
detail::ShapeInfo::GeometryShape shape() const override
std::optional< Kernel::V3D > generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, const size_t) const override
Select a random point within the object.
size_t numberOfVertices() const
void printTree() const
Displays the rule tree.
std::unique_ptr< Rule > m_topRule
Top rule [ Geometric scope of object].
int populate(const std::map< int, std::shared_ptr< Surface > > &)
Goes through the cell objects and adds the pointers to the SurfPoint keys (using their keyN)
int interceptSurface(Geometry::Track &track) const override
Given a track, fill the track with valid section.
void setVtkGeometryCacheReader(std::shared_ptr< vtkGeometryCacheReader >)
set vtkGeometryCache reader
void defineBoundingBox(const double &xMax, const double &yMax, const double &zMax, const double &xMin, const double &yMin, const double &zMin)
Define axis-aligned bounding box.
void calcBoundingBoxByGeometry()
Calculate bounding box using object's geometric data.
static constexpr int g_NSLICES
The number of slices to approximate a cone.
static constexpr int g_NSTACKS
The number of stacks to approximate a cone.
static constexpr int g_NSTACKS
The number of stacks to approximate a cylinder.
Handles rendering of all object Geometry.
Interset of Line with a surface.
const Line::PType & getPoints() const
Get the intersection points.
const DistancesType & getDistance() const
Get the distance.
void sortAndRemoveDuplicates()
Prune out duplicated points and sort by distance to starting point.
Object generation rule tree.
Rule * getParent() const
Returns the parent object.
virtual Rule * leaf(const int=0) const
No leaf for a base rule.
virtual int findLeaf(const Rule *) const =0
Abstract find.
virtual void setLeaf(std::unique_ptr< Rule >, const int=0)=0
Abstract set.
static int removeItem(std::unique_ptr< Rule > &TRule, const int SurfN)
Given an item as a surface name, remove the surface from the Rule tree.
virtual std::string display() const =0
Abstract Display.
int cylinderSlices() const
const Kernel::V3D & observer() const
void setKey(const std::shared_ptr< Surface > &Spoint)
Sets the key pointer.
Holds a basic quadratic surface.
int getName() const
Get Name.
Defines a track as a start point and a direction.
const Kernel::V3D & startPoint() const
Returns the starting point.
void addPoint(const TrackDirection direction, const Kernel::V3D &endPoint, const IObject &obj, const ComponentID compID=nullptr)
Adds a point of intersection to the track.
void buildLink()
Construct links between added points.
int count() const
Returns the number of links.
const Kernel::V3D & direction() const
Returns the direction as a unit vector.
LType::const_iterator cbegin() const
Returns an interator to the start of the set of links (const version)
@ HOLLOWCYLINDER
HOLLOW CYLINDER.
Reads the Geometry Cache from the file to the Object.
Writes the Geometry from Object to Cache.
Exception for when an item is not found in a collection.
The Logger class is in charge of the publishing messages from the framework through various channels.
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
Defines a 1D pseudo-random number generator, i.e.
void rotate(V3D &) const
Rotate a vector.
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
constexpr double X() const noexcept
Get x.
double normalize()
Make a normalized vector (return norm value)
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
constexpr double Y() const noexcept
Get y.
void rotate(const Matrix< double > &) noexcept
Rotate a point by a matrix.
double norm() const noexcept
constexpr double Z() const noexcept
Get z.
bool nullVector(const double tolerance=1e-3) const noexcept
Determine if the point is null.
std::optional< Kernel::V3D > bounded(const detail::ShapeInfo &shapeInfo, Kernel::PseudoRandomNumberGenerator &rng, const BoundingBox &box, size_t maxAttempts)
Return a random point in a known shape restricted by a bounding box.
MANTID_GEOMETRY_DLL Kernel::V3D inCylinder(const detail::ShapeInfo &shapeInfo, Kernel::PseudoRandomNumberGenerator &rng)
Return a random point in cylinder.
MANTID_GEOMETRY_DLL Kernel::V3D inCuboid(const detail::ShapeInfo &shapeInfo, Kernel::PseudoRandomNumberGenerator &rng)
Return a random point in a cuboid shape.
MANTID_GEOMETRY_DLL Kernel::V3D inSphere(const detail::ShapeInfo &shapeInfo, Kernel::PseudoRandomNumberGenerator &rng)
Return a random point in sphere.
MANTID_GEOMETRY_DLL std::optional< Kernel::V3D > inGenericShape(const IObject &object, Kernel::PseudoRandomNumberGenerator &rng, size_t maxAttempts)
Return a random point in a generic shape.
MANTID_GEOMETRY_DLL Kernel::V3D inHollowCylinder(const detail::ShapeInfo &shapeInfo, Kernel::PseudoRandomNumberGenerator &rng)
Return a random point in a hollow cylinder.
int convPartNum(const std::string &A, T &out)
Takes a character string and evaluates the first [typename T] object.
MANTID_KERNEL_DLL int StrLook(const std::string &, const boost::regex &)
Find is a pattern matches.
MANTID_KERNEL_DLL void writeMCNPX(const std::string &Line, std::ostream &OX)
Write file in standard MCNPX input form.
int convert(const std::string &A, T &out)
Convert a string into a number.
constexpr double Tolerance
Standard tolerance value.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
std::string to_string(const wide_integer< Bits, Signed > &n)