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);
192 top_centre += 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 ¢re,
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),
478 static const boost::regex letters(
"[a-zA-Z]");
507 std::string::size_type pos = TopStr.find(
'#');
508 std::ostringstream cx;
509 while (pos != std::string::npos) {
511 cx << TopStr.substr(0, pos);
516 auto vc = MList.find(cN);
517 if (vc == MList.end())
521 cx << vc->second.cellStr(MList);
525 TopStr.erase(0, pos);
526 pos = TopStr.find(
'#');
552 std::deque<Rule *> rules;
554 while (!rules.empty()) {
555 Rule *T1 = rules.front();
559 auto *surface =
dynamic_cast<SurfPoint *
>(T1);
562 auto mapFound = surfMap.find(surface->getKeyN());
563 if (mapFound != surfMap.end()) {
564 surface->
setKey(mapFound->second);
574 rules.emplace_back(TA);
576 rules.emplace_back(TB);
595int CSGObject::procPair(std::string &lineStr, std::map<
int, std::unique_ptr<Rule>> &ruleMap,
int &compUnit)
const
602 for (Rstart = 0; Rstart < lineStr.size() && lineStr[Rstart] !=
'R'; Rstart++)
609 ruleMap.find(Ra) == ruleMap.end())
612 for (Rend = Rstart + 1; Rend < lineStr.size() && lineStr[Rend] !=
'R'; Rend++) {
613 if (lineStr[Rend] ==
':')
617 ruleMap.find(Rb) == ruleMap.end()) {
623 for (Rend++; Rend < lineStr.size() && lineStr[Rend] >=
'0' && lineStr[Rend] <=
'9'; Rend++)
628 (type) ? std::unique_ptr<Rule>(std::make_unique<Union>(std::move(ruleMap[Ra]), std::move(ruleMap[Rb])))
629 : std::unique_ptr<Rule>(std::make_unique<Intersection>(std::move(ruleMap[Ra]), std::move(ruleMap[Rb])));
630 ruleMap[Ra] = std::move(Join);
631 ruleMap.erase(ruleMap.find(Rb));
635 for (strPos = Rstart - 1; strPos >= 0 && lineStr[strPos] ==
' '; strPos--)
637 Rstart = (strPos < 0) ? 0 : strPos;
638 for (strPos = Rend; strPos < static_cast<int>(lineStr.size()) && lineStr[strPos] ==
' '; strPos++)
642 std::stringstream newRuleStr;
643 newRuleStr <<
" R" << Ra <<
" ";
644 lineStr.replace(Rstart, Rend, newRuleStr.str());
656 return std::make_unique<CompGrp>();
659 const Rule *RItemptr = ruleItem.get();
660 auto CG = std::make_unique<CompGrp>(Pptr, std::move(ruleItem));
662 const int Ln = Pptr->
findLeaf(RItemptr);
663 Pptr->
setLeaf(std::move(CG), Ln);
665 return std::make_unique<CompGrp>();
689 std::vector<Kernel::V3D> Snorms;
693 if ((*vc)->onSurface(point)) {
694 Snorms.emplace_back((*vc)->surfaceNormal(point));
702 for (
auto xs = Snorms.begin(); xs != Snorms.end(); ++xs)
703 for (
auto ys = std::next(xs); ys != Snorms.end(); ++ys) {
704 NormPair = (*ys) + (*xs);
709 }
catch (std::runtime_error &) {
765 std::stack<const Rule *> TreeLine;
767 while (!TreeLine.empty()) {
768 const Rule *tmpA = TreeLine.top();
778 const auto *SurX =
dynamic_cast<const SurfPoint *
>(tmpA);
785 std::unordered_set<const Surface *> uniqueSurfacePtrs;
788 if (uniqueSurfacePtrs.find(sPtr) != std::end(uniqueSurfacePtrs)) {
791 uniqueSurfacePtrs.insert(sPtr);
795 m_surList.erase(newEnd, m_surList.end());
799 std::vector<const Surface *>::const_iterator vc;
800 for (vc = m_surList.begin(); vc != m_surList.end(); ++vc) {
801 logger.debug() <<
"Point == " << *vc <<
'\n';
802 logger.debug() << (*vc)->getName() <<
'\n';
813 std::vector<int> out;
814 transform(
m_surList.begin(),
m_surList.end(), std::insert_iterator<std::vector<int>>(out, out.begin()),
845 const int out =
m_topRule->substituteSurf(surfNum, newSurfNum, surfPtr);
855 std::deque<Rule *> rst;
856 std::vector<int> Cells;
861 while (!rst.empty()) {
862 const Rule *T1 = rst.front();
866 const auto *surface =
dynamic_cast<const SurfPoint *
>(T1);
868 Cells.emplace_back(surface->getKeyN());
873 rst.emplace_back(TA);
875 rst.emplace_back(TB);
880 logger.debug() <<
"Name == " <<
m_objNum <<
'\n';
881 logger.debug() <<
"Rules == " << Rcount <<
'\n';
882 std::vector<int>::const_iterator mc;
883 logger.debug() <<
"Surface included == ";
884 for (mc = Cells.begin(); mc < Cells.end(); ++mc) {
885 logger.debug() << (*mc) <<
" ";
887 logger.debug() <<
'\n';
902 logger.debug() <<
"Name == " <<
m_objNum <<
'\n';
903 logger.debug() <<
m_topRule->display() <<
'\n';
912 std::ostringstream objStr;
924 std::ostringstream objStr;
938 std::ostringstream objStr;
939 objStr.precision(10);
951 std::map<int, std::unique_ptr<Rule>> RuleList;
955 std::unique_ptr<SurfPoint> TmpR;
956 std::unique_ptr<CompObj> TmpO;
958 std::string Ln = lineStr;
960 std::ostringstream cx;
961 const std::string::size_type length = Ln.length();
962 for (
size_t i = 0; i < length; i++) {
963 if (isdigit(Ln[i]) || Ln[i] ==
'-') {
967 throw std::invalid_argument(
"Invalid surface string in Object::ProcString : " + lineStr);
969 if (i != 0 && Ln[i - 1] ==
'#') {
970 TmpO = std::make_unique<CompObj>();
972 RuleList[Ridx] = std::move(TmpO);
975 TmpR = std::make_unique<SurfPoint>();
977 RuleList[Ridx] = std::move(TmpR);
979 cx <<
" R" << Ridx <<
" ";
989 int brack_exists = 1;
990 while (brack_exists) {
991 std::string::size_type rbrack = Ln.find(
')');
992 std::string::size_type lbrack = Ln.rfind(
'(', rbrack);
993 if (rbrack != std::string::npos && lbrack != std::string::npos) {
994 std::string Lx = Ln.substr(lbrack + 1, rbrack - lbrack - 1);
997 while (
procPair(Lx, RuleList, compUnit))
999 Ln.replace(lbrack, 1 + rbrack - lbrack, Lx);
1002 for (hCnt =
static_cast<int>(lbrack) - 1; hCnt >= 0 && isspace(Ln[hCnt]); hCnt--)
1004 if (hCnt >= 0 && Ln[hCnt] ==
'#') {
1005 RuleList[compUnit] =
procComp(std::move(RuleList[compUnit]));
1006 Ln.erase(hCnt, lbrack - hCnt);
1013 while (
procPair(Ln, RuleList, nullInt)) {
1016 if (RuleList.size() == 1) {
1017 m_topRule = std::move((RuleList.begin())->second);
1019 throw std::logic_error(
"Object::procString() - Unexpected number of "
1020 "surface rules found. Expected=1, found=" +
1032 int originalCount = track.
count();
1039 surface->acceptVisitor(LI);
1052 const size_t nPoints(IPoints.size());
1055 for (
size_t i = 0; i < nPoints; i++) {
1061 const auto ¤tPt(IPoints[i]);
1062 const auto &prePt((i == 0 || dPoints[i - 1] <= 0) ? track.
startPoint() : IPoints[i - 1]);
1063 const auto &nextPt(i + 1 < nPoints ? IPoints[i + 1] : currentPt + currentPt - prePt);
1069 track.
addPoint(trackType, currentPt, *
this);
1075 return (track.
count() - originalCount);
1087 surface->acceptVisitor(LI);
1091 if (!distances.empty()) {
1092 return std::abs(*std::min_element(std::begin(distances), std::end(distances)));
1094 std::ostringstream os;
1095 os <<
"Unable to find intersection with object with track starting at " << track.
startPoint() <<
" in direction "
1097 throw std::runtime_error(os.str());
1113 const Kernel::V3D shift(uVec * VALID_INTERCEPT_POINT_SHIFT);
1114 const int flagA =
isValid(point - shift);
1115 const int flagB =
isValid(point + shift);
1116 if (!(flagA ^ flagB))
1133 const auto upstreamPt = (prePt + curPt) * 0.5;
1134 const auto upstreamPtInsideShape =
isValid(upstreamPt);
1136 const auto downstreamPt = (curPt + nxtPt) * 0.5;
1137 const auto downstreamPtInsideShape =
isValid(downstreamPt);
1155 if (!(upstreamPtInsideShape ^ downstreamPtInsideShape))
1204 const int resNoBB = 200, resPhiMin = 10;
1205 int res = resNoBB, itheta, jphi, resPhi;
1206 double theta, phi, sum, dphi, dtheta;
1213 double thetaMax = M_PI;
1214 bool useBB =
false, usePt =
false;
1220 useBB = usePt =
true;
1223 const int resBB = 100;
1233 ptInObject -= observer;
1234 double theta0 = -180.0 / M_PI * acos(ptInObject.
Z() / ptInObject.
norm());
1239 zToPt(theta0, axis);
1241 dtheta = thetaMax / res;
1242 int count = 0, countPhi;
1244 for (itheta = 1; itheta <= res; itheta++) {
1246 theta = thetaMax * (itheta - 0.5) / res;
1247 resPhi =
static_cast<int>(res * sin(theta));
1248 if (resPhi < resPhiMin)
1250 dphi = 2 * M_PI / resPhi;
1252 for (jphi = 1; jphi <= resPhi; jphi++) {
1254 phi = 2.0 * M_PI * (jphi - 0.5) / resPhi;
1255 Kernel::V3D dir(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
1259 Track tr(observer, dir);
1261 sum += dtheta * dphi * sin(theta);
1268 if (!useBB && countPhi == 0)
1272 if (!useBB &&
count < resPhiMin + 1) {
1275 thetaMax = thetaMax * (itheta - 0.5) / res;
1276 dtheta = thetaMax / res;
1278 for (itheta = 1; itheta <= res; itheta++) {
1279 theta = thetaMax * (itheta - 0.5) / res;
1280 resPhi =
static_cast<int>(res * sin(theta));
1281 if (resPhi < resPhiMin)
1283 dphi = 2 * M_PI / resPhi;
1285 for (jphi = 1; jphi <= resPhi; jphi++) {
1286 phi = 2.0 * M_PI * (jphi - 0.5) / resPhi;
1287 Kernel::V3D dir(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
1290 Track tr(observer, dir);
1292 sum += dtheta * dphi * sin(theta);
1317 const auto &observer = params.
observer();
1322 return (2.0 * M_PI);
1324 return (4.0 * M_PI);
1329 double height(0.0), radius(0.0), innerRadius(0.0);
1331 std::vector<Mantid::Kernel::V3D> geometry_vectors;
1333 geometry_vectors.reserve(4);
1340 return cuboidSolidAngle(observer, geometry_vectors);
1343 return sphereSolidAngle(observer, geometry_vectors, radius);
1346 return cylinderSolidAngle(observer, geometry_vectors[0], geometry_vectors[1], radius,
height,
1350 return coneSolidAngle(observer, geometry_vectors[0], geometry_vectors[1], radius,
height);
1359 double sangle(0.0), sneg(0.0);
1360 for (
size_t i = 0; i < nTri; i++) {
1361 int p1 = faces[i * 3], p2 = faces[i * 3 + 1], p3 = faces[i * 3 + 2];
1362 V3D vp1 =
V3D(vertices[3 * p1], vertices[3 * p1 + 1], vertices[3 * p1 + 2]);
1363 V3D vp2 =
V3D(vertices[3 * p2], vertices[3 * p2 + 1], vertices[3 * p2 + 2]);
1364 V3D vp3 =
V3D(vertices[3 * p3], vertices[3 * p3 + 1], vertices[3 * p3 + 2]);
1365 double sa = triangleSolidAngle(vp1, vp2, vp3, observer);
1384 return 0.5 * (sangle - sneg);
1404 const auto &observer = params.
observer();
1406 double sx = scaleFactor[0], sy = scaleFactor[1], sz = scaleFactor[2];
1407 const V3D sObserver = observer;
1411 return (2.0 * M_PI);
1413 return (4.0 * M_PI);
1424 double height = 0.0, radius(0.0), innerRadius;
1426 std::vector<Kernel::V3D> vectors;
1430 std::transform(vectors.begin(), vectors.end(), vectors.begin(),
1431 [scaleFactor](
const V3D &v) { return v * scaleFactor; });
1432 return cuboidSolidAngle(observer, vectors);
1435 return sphereSolidAngle(observer, vectors, radius);
1448 double sangle(0.0), sneg(0.0);
1449 for (
size_t i = 0; i < nTri; i++) {
1450 int p1 = faces[i * 3], p2 = faces[i * 3 + 1], p3 = faces[i * 3 + 2];
1453 V3D vp1 =
V3D(sx * vertices[3 * p1], sy * vertices[3 * p1 + 1], sz * vertices[3 * p1 + 2]);
1454 V3D vp2 =
V3D(sx * vertices[3 * p2], sy * vertices[3 * p2 + 1], sz * vertices[3 * p2 + 2]);
1455 V3D vp3 =
V3D(sx * vertices[3 * p3], sy * vertices[3 * p3 + 1], sz * vertices[3 * p3 + 2]);
1456 double sa = triangleSolidAngle(vp1, vp2, vp3, observer);
1462 return (0.5 * (sangle - sneg));
1475 std::vector<Kernel::V3D> vectors;
1482 double volumeTri = 0.0;
1506 return volumeTri / 6;
1509 return 4.0 / 3.0 * M_PI * radius * radius * radius;
1511 return M_PI * radius * radius *
height;
1513 return M_PI *
height * (radius * radius - innerRadius * innerRadius);
1527 using namespace boost::accumulators;
1528 const int singleShotIterations = 10000;
1529 accumulator_set<double, features<tag::mean, tag::error_of<tag::mean>>> accumulate;
1531 std::ranlux48 rnEngine;
1533 for (
int i = 0; i < 10; ++i) {
1534 const auto seed = rnEngine();
1536 accumulate(volumeMc);
1538 const double relativeErrorTolerance = 1e-3;
1540 double currentError;
1542 const auto seed = rnEngine();
1544 accumulate(volumeMc);
1545 currentMean = mean(accumulate);
1546 currentError = error_of<tag::mean>(accumulate);
1547 if (std::isnan(currentError)) {
1550 }
while (currentError / currentMean > relativeErrorTolerance);
1562 if (boundingBox.isNull()) {
1563 throw std::runtime_error(
"Cannot calculate volume: invalid bounding box.");
1566 const double boundingDx = boundingBox.xMax() - boundingBox.xMin();
1567 const double boundingDy = boundingBox.yMax() - boundingBox.yMin();
1568 const double boundingDz = boundingBox.zMax() - boundingBox.zMin();
1572 size_t blocksize = shotSize / threadCount;
1574 if (currentThreadNum == threadCount - 1) {
1577 blocksize = shotSize - (threadCount - 1) * blocksize;
1579 std::mt19937 rnEngine(
static_cast<std::mt19937::result_type
>(seed));
1585 rnEngine.discard(currentThreadNum * 3 * blocksize);
1586 std::uniform_real_distribution<double> rnDistribution(0.0, 1.0);
1588 for (
int i = 0; i < static_cast<int>(blocksize); ++i) {
1589 double rnd = rnDistribution(rnEngine);
1590 const double x = boundingBox.xMin() + rnd * boundingDx;
1591 rnd = rnDistribution(rnEngine);
1592 const double y = boundingBox.yMin() + rnd * boundingDy;
1593 rnd = rnDistribution(rnEngine);
1594 const double z = boundingBox.zMin() + rnd * boundingDz;
1603 const double ratio =
static_cast<double>(totalHits) /
static_cast<double>(shotSize);
1604 const double boundingVolume = boundingDx * boundingDy * boundingDz;
1605 return ratio * boundingVolume;
1665 const double huge(1e10);
1666 const double big(1e4);
1667 double minX(-huge), minY(-huge), minZ(-huge);
1668 double maxX(huge), maxY(huge), maxZ(huge);
1671 m_topRule->getBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
1675 if (minX > -big && maxX < big && minY > -big && maxY < big && minZ > -big && maxZ < big && minX <= maxX &&
1676 minY <= maxY && minZ <= maxZ) {
1694 if (vertCount > 0) {
1697 constexpr double huge = 1e10;
1698 double minX, maxX, minY, maxY, minZ, maxZ;
1699 minX = minY = minZ = huge;
1700 maxX = maxY = maxZ = -huge;
1703 for (
size_t i = 0; i < vertCount; ++i) {
1704 auto vx = vertArray[3 * i + 0];
1705 auto vy = vertArray[3 * i + 1];
1706 auto vz = vertArray[3 * i + 2];
1708 minX = std::min(minX, vx);
1709 maxX = std::max(maxX, vx);
1710 minY = std::min(minY, vy);
1711 maxY = std::max(maxY, vy);
1712 minZ = std::min(minZ, vz);
1713 maxZ = std::max(maxZ, vz);
1733 double minX, maxX, minY, maxY, minZ, maxZ;
1737 std::vector<Kernel::V3D> vectors;
1748 const auto &lfb = vectors[0];
1749 const auto &lft = vectors[1];
1750 const auto &lbb = vectors[2];
1751 const auto &rfb = vectors[3];
1754 auto lbt = lft + (lbb - lfb);
1755 auto rft = rfb + (lft - lfb);
1756 auto rbb = lbb + (rfb - lfb);
1757 auto rbt = rbb + (rft - rfb);
1759 vectors.emplace_back(lbt);
1760 vectors.emplace_back(rft);
1761 vectors.emplace_back(rbb);
1762 vectors.emplace_back(rbt);
1765 constexpr double huge = 1e10;
1766 minX = minY = minZ = huge;
1767 maxX = maxY = maxZ = -huge;
1770 for (
const auto &vector : vectors) {
1771 minX = std::min(minX, vector.X());
1772 maxX = std::max(maxX, vector.X());
1773 minY = std::min(minY, vector.Y());
1774 maxY = std::max(maxY, vector.Y());
1775 minZ = std::min(minZ, vector.Z());
1776 maxZ = std::max(maxZ, vector.Z());
1781 minX = minY = minZ = std::numeric_limits<
decltype(minZ)>::max();
1782 maxX = maxY = maxZ = -std::numeric_limits<
decltype(maxZ)>::max();
1785 for (
const auto &vector : vectors) {
1786 minX = std::min(minX, vector.X());
1787 maxX = std::max(maxX, vector.X());
1788 minY = std::min(minY, vector.Y());
1789 maxY = std::max(maxY, vector.Y());
1790 minZ = std::min(minZ, vector.Z());
1791 maxZ = std::max(maxZ, vector.Z());
1796 const auto &base = vectors[0];
1797 const auto &axis = vectors[1];
1803 volatile auto rx = radius * sqrt(pow(axis.
Y(), 2) + pow(axis.
Z(), 2));
1804 volatile auto ry = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Z(), 2));
1805 volatile auto rz = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Y(), 2));
1809 minX = std::min(base.X(),
top.X()) - rx;
1810 maxX = std::max(base.X(),
top.X()) + rx;
1811 minY = std::min(base.Y(),
top.Y()) - ry;
1812 maxY = std::max(base.Y(),
top.Y()) + ry;
1813 minZ = std::min(base.Z(),
top.Z()) - rz;
1814 maxZ = std::max(base.Z(),
top.Z()) + rz;
1818 const auto &tip = vectors[0];
1819 const auto &axis = vectors[1];
1820 auto base = tip + (axis *
height);
1825 auto rx = radius * sqrt(pow(axis.
Y(), 2) + pow(axis.
Z(), 2));
1826 auto ry = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Z(), 2));
1827 auto rz = radius * sqrt(pow(axis.
X(), 2) + pow(axis.
Y(), 2));
1830 minX = std::min(tip.X(), base.X() - rx);
1831 maxX = std::max(tip.X(), base.X() + rx);
1832 minY = std::min(tip.Y(), base.Y() - ry);
1833 maxY = std::max(tip.Y(), base.Y() + ry);
1834 minZ = std::min(tip.Z(), base.Z() - rz);
1835 maxZ = std::max(tip.Z(), base.Z() + rz);
1859 double &zmin)
const {
1861 xmax = ymax = zmax = xmin = ymin = zmin = 0.0;
1872 if (
AABBxMax >= xmax || AABBxMin <= xmin || AABByMax >= ymax || AABByMin <= ymin || AABBzMax >= zmax ||
1901 const double &yMin,
const double &zMin) {
1960 const size_t maxAttempts)
const {
1961 std::optional<V3D> point{std::nullopt};
1969 const size_t bruteForceAttempts{std::min(
static_cast<size_t>(5), maxAttempts)};
2007 const size_t maxAttempts)
const {
2008 std::optional<V3D> point{std::nullopt};
2015 const size_t bruteForceAttempts{std::min(
static_cast<size_t>(5), maxAttempts)};
2019 std::vector<Kernel::V3D> shapeVectors;
2024 switch (shapeGeometry) {
2026 point = RandomPoint::bounded<RandomPoint::inCuboid>(
m_handler->shapeInfo(), rng, activeRegion,
2027 maxAttempts - bruteForceAttempts);
2030 point = RandomPoint::bounded<RandomPoint::inCylinder>(
m_handler->shapeInfo(), rng, activeRegion,
2031 maxAttempts - bruteForceAttempts);
2034 point = RandomPoint::bounded<RandomPoint::inHollowCylinder>(
m_handler->shapeInfo(), rng, activeRegion,
2035 maxAttempts - bruteForceAttempts);
2038 point = RandomPoint::bounded<RandomPoint::inSphere>(
m_handler->shapeInfo(), rng, activeRegion,
2039 maxAttempts - bruteForceAttempts);
2061 for (
const auto &dir :
2062 {
V3D(1., 0., 0.),
V3D(-1., 0., 0.),
V3D(0., 1., 0.),
V3D(0., -1., 0.),
V3D(0., 0., 1.),
V3D(0., 0., -1.)}) {
2065 point = tr.
cbegin()->entryPoint;
2166 static const std::vector<double> empty;
2169 return m_handler->getTriangleVertices();
2176 static const std::vector<uint32_t> empty;
2194 throw std::logic_error(
"CSGObject has no ShapeInfo to return");
2202 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
for solid angle from triangulation
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)