16#include "MantidNexus/NexusFile.h"
25 : m_boundingBox(), m_id(
"MeshObject"), m_triangles(
std::move(faces)), m_vertices(
std::move(vertices)),
26 m_material(material) {
33 : m_boundingBox(), m_id(
"MeshObject"), m_triangles(
std::move(faces)), m_vertices(
std::move(vertices)),
34 m_material(material) {
43 m_handler = std::make_shared<GeometryHandler>(*
this);
80 std::vector<Kernel::V3D> intersectionPoints;
81 std::vector<TrackDirection> entryExitFlags;
85 if (intersectionPoints.empty()) {
90 const auto it = std::find_if(
91 intersectionPoints.cbegin(), intersectionPoints.cend(),
92 [
this, &point](
const auto &intersectionPoint) { return point.distance(intersectionPoint) < M_TOLERANCE; });
93 if (it != intersectionPoints.cend())
97 double nearestPointDistance = point.
distance(intersectionPoints[0]);
98 size_t nearestPointIndex = 0;
99 for (
size_t i = 1; i < intersectionPoints.size(); ++i) {
100 if (point.
distance(intersectionPoints[i]) < nearestPointDistance) {
101 nearestPointDistance = point.
distance(intersectionPoints[i]);
102 nearestPointIndex = i;
124 for (
const auto &direction : directions) {
125 std::vector<Kernel::V3D> intersectionPoints;
126 std::vector<TrackDirection> entryExitFlags;
130 if (intersectionPoints.empty()) {
134 const auto it = std::find_if(
135 intersectionPoints.cbegin(), intersectionPoints.cend(),
136 [
this, &point](
const auto &intersectionPoint) { return point.distance(intersectionPoint) < M_TOLERANCE; });
137 if (it != intersectionPoints.cend())
149 int originalCount = UT.
count();
155 std::vector<Kernel::V3D> intersectionPoints;
156 std::vector<TrackDirection> entryExit;
159 if (intersectionPoints.empty())
163 for (
size_t i = 0; i < intersectionPoints.size(); ++i) {
164 UT.
addPoint(entryExit[i], intersectionPoints[i], *
this);
168 return UT.
count() - originalCount;
180 for (
size_t i = 0;
getTriangle(i, vertex1, vertex2, vertex3); ++i) {
186 std::ostringstream os;
187 os <<
"Unable to find intersection with object with track starting at " << track.
startPoint() <<
" in direction "
189 throw std::runtime_error(os.str());
200 std::vector<Kernel::V3D> &intersectionPoints,
201 std::vector<TrackDirection> &entryExitFlags)
const {
205 for (
size_t i = 0;
getTriangle(i, vertex1, vertex2, vertex3); ++i) {
208 entryExitFlags.emplace_back(entryExit);
225 if (triangleExists) {
230 return triangleExists;
245 const int flagA =
isValid(testA);
246 const int flagB =
isValid(testB);
247 if (!(flagA ^ flagB))
249 return (flagA) ? -1 : 1;
265 double &zmin)
const {
275 double solidAngleSum(0), solidAngleNegativeSum(0);
277 for (
size_t i = 0; this->
getTriangle(i, vertex1, vertex2, vertex3); ++i) {
282 solidAngleNegativeSum += sa;
292 return 0.5 * (solidAngleSum - solidAngleNegativeSum);
303 std::vector<Kernel::V3D> scaledVertices;
306 [&scaleFactor](
const auto &vertex) { return scaleFactor * vertex; });
322 double cX = 0.5 * (bb.
xMax() + bb.
xMin());
323 double cY = 0.5 * (bb.
yMax() + bb.
yMin());
324 double cZ = 0.5 * (bb.
zMax() + bb.
zMin());
327 double volumeTimesSix(0.0);
330 for (
size_t i = 0;
getTriangle(i, vertex1, vertex2, vertex3); ++i) {
337 return volumeTimesSix / 6.0;
379 const size_t maxAttempts)
const {
382 throw std::runtime_error(
"Object::generatePointInObject() - Invalid "
383 "bounding box. Cannot generate new point.");
400 const size_t maxAttempts)
const {
423 point = tr.
cbegin()->entryPoint;
483 [&rotationMatrix](
auto &vertex) { vertex.rotate(rotationMatrix); });
502 [&translationVector](
const auto &vertex) { return vertex + translationVector; });
511 [&scaleFactor](
const auto &vertex) { return vertex * scaleFactor; });
525 throw std::invalid_argument(
"Transformation matrix must be 4 x 4");
531 std::vector<double> vertexin(4);
532 vertexin[0] = vertex.X();
533 vertexin[1] = vertex.Y();
534 vertexin[2] = vertex.Z();
536 std::vector<double> vertexout(4);
538 Kernel::V3D newvertex(vertexout[0], vertexout[1], vertexout[2]);
578 throw std::runtime_error(
"MeshObject::shapeInfo() is not implemented");
585 double &innerRadius,
double &radius,
double &
height)
const {
596 file->makeGroup(
group,
"NXoff_geometry",
true);
601 std::vector<uint32_t> faceIndices(nTriangles);
602 for (
size_t i = 0; i < nTriangles; ++i) {
603 faceIndices[i] =
static_cast<uint32_t
>(i * 3);
605 file->writeData(
"faces", faceIndices);
616 file->openGroup(
group,
"NXoff_geometry");
618 std::vector<double> flatVertices;
619 file->readData(
"vertices", flatVertices);
621 std::vector<uint32_t> windingOrder;
622 file->readData(
"winding_order", windingOrder);
624 std::vector<uint32_t> faceIndices;
625 file->readData(
"faces", faceIndices);
629 std::vector<double> appliedRotation;
630 const bool hasAppliedRotation = file->hasData(
"applied_goniometer_rotation");
631 if (hasAppliedRotation) {
632 file->readData(
"applied_goniometer_rotation", appliedRotation);
638 const size_t nVerts = flatVertices.size() / 3;
639 std::vector<Kernel::V3D> vertices;
640 vertices.reserve(nVerts);
641 for (
size_t i = 0; i < nVerts; ++i) {
642 vertices.emplace_back(flatVertices[3 * i], flatVertices[3 * i + 1], flatVertices[3 * i + 2]);
646 std::vector<uint32_t> triangles;
647 triangles.reserve(windingOrder.size());
648 for (
size_t f = 0; f < faceIndices.size(); ++f) {
649 const uint32_t start = faceIndices[f];
650 const uint32_t end = (f + 1 < faceIndices.size()) ? faceIndices[f + 1] :
static_cast<uint32_t
>(windingOrder.size());
651 const uint32_t nVertsInFace = end - start;
653 for (uint32_t v = 1; v + 1 < nVertsInFace; ++v) {
654 triangles.push_back(windingOrder.at(start));
655 triangles.push_back(windingOrder.at(start + v));
656 triangles.push_back(windingOrder.at(start + v + 1));
660 auto object = std::make_shared<MeshObject>(std::move(triangles), std::move(vertices),
material);
661 if (hasAppliedRotation) {
663 if (appliedRotation.size() != 9) {
664 throw std::invalid_argument(
"applied_goniometer_rotation in '" +
group +
"' must hold 9 values, not " +
std::map< DeltaEMode::Type, std::string > index
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 xMax() const
Return the maximum value of X.
bool isNonNull() const
Is the box considered valid. Convenience for !isNull()
double zMin() const
Return the minimum value of Z.
double zMax() const
Return the maximum value of Z.
double yMax() const
Return the maximum value of Y.
double xMin() const
Return the minimum value of X.
bool doesLineIntersect(const Track &track) const
Does a specified track intersect the bounding box.
Kernel::V3D centrePoint() const
Returns the centre of the bounding box.
double yMin() const
Return the minimum value of Y.
Kernel::Material m_material
material composition
void setAppliedGoniometerRotation(const Kernel::Matrix< double > &)
Record a bake without touching the vertices, for when they are already rotated - Nexus load.
std::optional< Kernel::V3D > generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, const size_t) const override
Select a random point within the object.
void translate(const Kernel::V3D &)
Translate the mesh according to the supplied x, y, z vector.
void bakeGoniometerRotation(const Kernel::Matrix< double > &)
Rotate the vertices and record it as a goniometer bake - only for a move into the lab frame.
int getPointInObject(Kernel::V3D &point) const override
Try to find a point that lies within (or on) the object.
size_t numberOfTriangles() const
Output functions for rendering, may also be used internally.
int interceptSurface(Geometry::Track &) const override
Given a track, fill the track with valid section.
const detail::ShapeInfo & shapeInfo() const override
std::vector< double > getVertices() const
get vertices
detail::ShapeInfo::GeometryShape shape() const override
std::vector< Kernel::V3D > m_vertices
bool hasValidShape() const override
Return whether this object has a valid shape.
bool isValid(const Kernel::V3D &) const override
Check if a point is inside.
void setMaterial(const Kernel::Material &material) override
void draw() const override
Draws the Object using geometry handler, If the handler is not set then this function does nothing.
MeshObject(std::vector< uint32_t > faces, std::vector< Kernel::V3D > vertices, const Kernel::Material &material)
Constructor.
const BoundingBox & getBoundingBox() const override
Return cached value of axis-aligned bounding box.
void getIntersections(const Kernel::V3D &start, const Kernel::V3D &direction, std::vector< Kernel::V3D > &intersectionPoints, std::vector< Mantid::Geometry::TrackDirection > &entryExitFlags) const
Get intersections.
const std::vector< Kernel::V3D > & getV3Ds() const
get vertices in V3D form
double volume() const override
Calculates the volume of this object.
void saveNexus(Nexus::File *file, const std::string &group) const
Save mesh to an NXoff_geometry group in a NeXus file.
std::vector< uint32_t > m_triangles
Contents Triangles are specified by indices into a list of vertices.
void scale(const double scaleFactor)
Scale the mesh according to the supplied scale factor.
bool searchForObject(Kernel::V3D &point) const
Search object for valid point.
void initDraw() const override
Initializes/prepares the object to be rendered, this will generate geometry for object,...
size_t numberOfVertices() const
Read access to mesh object for rendering.
void updateGeometryHandler()
Updates the geometry handler if needed.
static std::shared_ptr< MeshObject > loadNexus(Nexus::File *file, const std::string &group, const Kernel::Material &material)
Load mesh from an NXoff_geometry group in a NeXus file.
const Kernel::Material & material() const override
Kernel::Matrix< double > m_appliedRotation
How far the mesh has been baked out of the frame its vertices were defined in.
std::shared_ptr< GeometryHandler > m_handler
Geometry Handle for rendering.
std::shared_ptr< GeometryHandler > getGeometryHandler() const override
Returns the geometry handler.
void multiply(const Kernel::Matrix< double > &)
Transform the mesh (scale, translate, rotate) according to the supplied transformation matrix.
bool getTriangle(const size_t index, Kernel::V3D &v1, Kernel::V3D &v2, Kernel::V3D &v3) const
Get triangle.
void rotate(const Kernel::Matrix< double > &)
Rotate the vertices within the shape's own frame, leaving getAppliedRotation() unchanged.
const std::vector< uint32_t > & getTriangles() const
get faces
int calcValidType(const Kernel::V3D &Pt, const Kernel::V3D &uVec) const
Calculate if a point PT is a valid point on the track.
BoundingBox m_boundingBox
Cache for object's bounding box.
double solidAngle(const SolidAngleParams ¶ms) const override
Find solid angle of object wrt the observer.
bool isOnSide(const Kernel::V3D &) const override
Determines wither point is on the surface.
void GetObjectGeom(detail::ShapeInfo::GeometryShape &type, std::vector< Kernel::V3D > &vectors, double &innerRadius, double &radius, double &height) const override
get info on standard shapes (none for Mesh Object)
void setGeometryHandler(const std::shared_ptr< GeometryHandler > &h)
Set Geometry Handler.
double distance(const Track &track) const override
Compute the distance to the first point of intersection with the surface.
const Kernel::V3D & observer() const
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)
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
void multiplyPoint(const std::vector< T > &in, std::vector< T > &out) const
Multiply M*Vec.
std::vector< T > getVector() const
size_t numRows() const
Return the number of rows in the matrix.
size_t numCols() const
Return the number of columns in the matrix.
Defines a 1D pseudo-random number generator, i.e.
double distance(const V3D &v) const noexcept
Calculates the distance between two vectors.
std::size_t size() const noexcept
Number of components in V3D.
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
MANTID_GEOMETRY_DLL bool rayIntersectsTriangle(const Kernel::V3D &start, const Kernel::V3D &direction, const Kernel::V3D &v1, const Kernel::V3D &v2, const Kernel::V3D &v3, Kernel::V3D &intersection, TrackDirection &entryExit)
Get intersection points and their in out directions on the given ray.
MANTID_GEOMETRY_DLL void checkVertexLimit(size_t nVertices)
MANTID_GEOMETRY_DLL std::vector< double > getVertices(const std::vector< Kernel::V3D > &vertices)
getVertices converts vector Kernel::V3D to vector doubles.
MANTID_GEOMETRY_DLL double getTriangleSolidAngle(const Kernel::V3D &a, const Kernel::V3D &b, const Kernel::V3D &c, const Kernel::V3D &observer)
Find the solid angle of a triangle defined by vectors a,b,c from point "observer".
MANTID_GEOMETRY_DLL const BoundingBox & getBoundingBox(const std::vector< Kernel::V3D > &vertices, BoundingBox &cacheBB)
Takes input vertices and calculates bounding box.
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.
bool MANTID_GEOMETRY_DLL intersection(const ConvexPolygon &P, const ConvexPolygon &Q, ConvexPolygon &out)
Compute the instersection of two convex polygons.
constexpr double Tolerance
Standard tolerance value.
std::string to_string(const wide_integer< Bits, Signed > &n)