Mantid
Loading...
Searching...
No Matches
MeshObject2D.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
13#include "MantidKernel/V3D.h"
14
15#include <algorithm>
16#include <cmath>
17#include <memory>
18#include <numeric>
19#include <utility>
20
21namespace Mantid::Geometry {
22
23namespace CoplanarChecks {
24bool sufficientPoints(const std::vector<Kernel::V3D> &vertices) {
25 return vertices.size() >= 3; // Not a plane with < 3 points
26}
27
34Kernel::V3D surfaceNormal(const std::vector<Kernel::V3D> &vertices) {
35 auto v0 = vertices[1] - vertices[0];
36 Kernel::V3D normal{0, 0, 0};
37 const static double tolerance_sq = std::pow(1e-9, 2);
38 // Look for normal amongst first 3 non-colinear points
39 for (size_t i = 1; i < vertices.size() - 1; ++i) {
40 auto v1 = vertices[i + 1] - vertices[i];
41 normal = v0.cross_prod(v1);
42 if (normal.norm2() > tolerance_sq) {
43 break;
44 }
45 }
46 return normal;
47}
48
55bool allCoplanar(const std::vector<Kernel::V3D> &vertices, const Kernel::V3D &normal) {
56 bool in_plane = true;
57 auto v0 = vertices[0];
58 const auto nx = normal[0];
59 const auto ny = normal[1];
60 const auto nz = normal[2];
61 const auto k = nx * v0.X() + ny * v0.Y() + nz * v0.Z();
62 const auto denom = normal.norm();
63 const static double tolerance = 1e-9; // Fixed Tolerance. Too expensive to
64 // calculate based on machine
65 // uncertaintly for each vertex.
66
67 for (const auto &vertex : vertices) {
68 auto d = (nx * vertex.X() + ny * vertex.Y() + nz * vertex.Z() - k) / denom;
69 if (d > tolerance || d < -1 * tolerance) {
70 in_plane = false;
71 break;
72 }
73 }
74 return in_plane;
75}
76
83Kernel::V3D validatePointsCoplanar(const std::vector<Kernel::V3D> &vertices) {
84 if (!sufficientPoints(vertices))
85 throw std::invalid_argument("Insufficient vertices to create a plane");
86
87 const auto normal = CoplanarChecks::surfaceNormal(vertices);
88 // Check that a valid normal was found amongst collection of vertices
89 if (normal.norm2() == 0) {
90 // If all points are colinear. Not a plane.
91 throw std::invalid_argument("All vertices are colinear. This does not define a plane");
92 }
93
94 if (!allCoplanar(vertices, normal))
95 throw std::invalid_argument("Vertices do not define a plane");
96 return normal;
97}
98} // namespace CoplanarChecks
99namespace {
110bool getTriangle(const size_t index, const std::vector<uint32_t> &triangles, const std::vector<Kernel::V3D> &vertices,
111 Kernel::V3D &vertex1, Kernel::V3D &vertex2, Kernel::V3D &vertex3) {
112 bool triangleExists = index < triangles.size() / 3;
113 if (triangleExists) {
114 vertex1 = vertices[triangles[3 * index]];
115 vertex2 = vertices[triangles[3 * index + 1]];
116 vertex3 = vertices[triangles[3 * index + 2]];
117 }
118 return triangleExists;
119}
120} // namespace
121
122const double MeshObject2D::MinThickness = 0.001;
123const std::string MeshObject2D::Id = "MeshObject2D";
124
130bool MeshObject2D::pointsCoplanar(const std::vector<Kernel::V3D> &vertices) {
132 return false;
133
135 // Check that a valid normal was found amongst collection of vertices
136 if (normal.norm2() == 0) {
137 // If all points are colinear. Not a plane.
138 return false;
139 }
140
141 return CoplanarChecks::allCoplanar(vertices, normal);
142}
143
147MeshObject2D::MeshObject2D(std::vector<uint32_t> faces, std::vector<Kernel::V3D> vertices,
148 const Kernel::Material &material)
149 : m_triangles(std::move(faces)), m_vertices(std::move(vertices)), m_material(material) {
150 initialize();
151}
152
156MeshObject2D::MeshObject2D(std::vector<uint32_t> &&faces, std::vector<Kernel::V3D> &&vertices,
157 const Kernel::Material &&material)
158 : m_triangles(std::move(faces)), m_vertices(std::move(vertices)), m_material(material) {
159 initialize();
160}
161
167 const auto v0 = m_vertices[0];
168 const auto n_mag = surfaceNormal.norm();
169 PlaneParameters parameters;
170 parameters.a = surfaceNormal.X() / n_mag;
171 parameters.b = surfaceNormal.Y() / n_mag;
172 parameters.c = surfaceNormal.Z() / n_mag;
173 parameters.k = parameters.a * v0.X() + parameters.b * v0.Y() + parameters.c * v0.Z();
174 parameters.normal = surfaceNormal;
175 parameters.abs_normal = surfaceNormal.norm();
176 parameters.p0 = v0;
177 m_planeParameters = parameters;
178
180 m_handler = std::make_shared<GeometryHandler>(*this);
181}
183 // 3 or more points define a plane.
184 return (!m_triangles.empty() && m_vertices.size() >= 3);
185}
186
187double MeshObject2D::distanceToPlane(const Kernel::V3D &point) const {
188 return ((point.X() * m_planeParameters.a) + (point.Y() * m_planeParameters.b) + (point.Z() * m_planeParameters.c) +
190}
191
199bool MeshObject2D::isValid(const Kernel::V3D &point) const {
200
201 static const double tolerance = 1e-9;
202 if (distanceToPlane(point) < tolerance) {
203 for (size_t i = 0; i < m_triangles.size(); i += 3) {
204
206 m_vertices[m_triangles[i + 2]]))
207 return true;
208 }
209 }
210 return false;
211}
212
218bool MeshObject2D::isOnSide(const Kernel::V3D &point) const { return isValid(point); }
219
226 const int originalCount = ut.count(); // Number of intersections original track
227
228 const auto &norm = m_planeParameters.normal;
229 const auto t =
231
232 // Intersects infinite plane. No point evaluating individual segements if this
233 // fails
234 if (t >= 0) {
236 TrackDirection entryExit;
237 for (size_t i = 0; i < m_vertices.size(); i += 3) {
239 m_vertices[i + 2], intersection, entryExit)) {
240 ut.addPoint(entryExit, intersection, *this);
241 ut.buildLink();
242 // All vertices on plane. So only one triangle intersection possible
243 break;
244 }
245 }
246 }
247
248 return ut.count() - originalCount;
249}
250
257double MeshObject2D::distance(const Track &ut) const {
258 const auto &norm = m_planeParameters.normal;
259 const auto t =
261
262 // Intersects infinite plane. No point evaluating individual segements if this
263 // fails
264 if (t >= 0) {
266 TrackDirection entryExit;
267 for (size_t i = 0; i < m_vertices.size(); i += 3) {
269 m_vertices[i + 2], intersection, entryExit)) {
270 // All vertices on plane. So only one triangle intersection possible
271 return intersection.distance(ut.startPoint());
272 }
273 }
274 }
275 std::ostringstream os;
276 os << "Unable to find intersection with object with track starting at " << ut.startPoint() << " in direction "
277 << ut.direction() << "\n";
278 throw std::runtime_error(os.str());
279}
280
282 return new MeshObject2D(this->m_triangles, this->m_vertices, this->m_material);
283}
284
286 return new MeshObject2D(this->m_triangles, this->m_vertices, material);
287}
288
290 return 0; // This is a hack. See how "names" are assigned in
291 // InstrumentDefinitionParser. Also see vtkGeometryCacheReader for
292 // where this is used.
293}
294
307double MeshObject2D::solidAngle(const Kernel::V3D &observer) const {
308 double solidAngleSum(0);
309 Kernel::V3D vertex1, vertex2, vertex3;
310 for (size_t i = 0; getTriangle(i, m_triangles, m_vertices, vertex1, vertex2, vertex3); ++i) {
311 double sa = MeshObjectCommon::getTriangleSolidAngle(vertex1, vertex2, vertex3, observer);
312 if (sa > 0) {
313 solidAngleSum += sa;
314 }
315 }
316 return solidAngleSum;
317}
318
319double MeshObject2D::solidAngle(const Kernel::V3D &observer, const Kernel::V3D &scaleFactor) const {
320 std::vector<Kernel::V3D> scaledVertices;
321 scaledVertices.reserve(m_vertices.size());
322 std::transform(m_vertices.cbegin(), m_vertices.cend(), std::back_inserter(scaledVertices),
323 [&scaleFactor](const auto &vertex) { return vertex * scaleFactor; });
324 MeshObject2D meshScaled(m_triangles, scaledVertices, m_material);
325 return meshScaled.solidAngle(observer);
326}
327
328bool MeshObject2D::operator==(const MeshObject2D &other) const {
329 return m_vertices.size() == other.m_vertices.size() && m_triangles.size() == other.m_triangles.size() &&
330 m_planeParameters.a == other.m_planeParameters.a && m_planeParameters.b == other.m_planeParameters.b &&
331 m_planeParameters.c == other.m_planeParameters.c && m_planeParameters.k == other.m_planeParameters.k &&
332 m_planeParameters.p0 == other.m_planeParameters.p0 && m_material.name() == other.m_material.name();
333}
334
335double MeshObject2D::volume() const {
336 return 0; // Volume is always 0 for a plane
337}
338
348}
349
350void MeshObject2D::getBoundingBox(double &xmax, double &ymax, double &zmax, double &xmin, double &ymin,
351 double &zmin) const {
352 return MeshObjectCommon::getBoundingBox(m_vertices, m_boundingBox, xmax, ymax, zmax, xmin, ymin, zmin);
353}
354
360int MeshObject2D::getPointInObject(Kernel::V3D &point) const { return this->isValid(point) ? 1 : 0; }
361
363 const size_t /*unused*/) const {
364 // How this would work for a finite plane is not clear. Points within the
365 // plane can of course be generated, but most implementations of this method
366 // use the bounding box
367 throw std::runtime_error("Not implemented.");
368}
369
371 const BoundingBox & /*activeRegion*/,
372 const size_t /*unused*/) const {
373
374 // How this would work for a finite plane is not clear. Points within the
375 // plane can of course be generated, but most implementations of this method
376 // in sibling types use the bounding box
377 throw std::runtime_error("Not implemented");
378}
379
381
386
387const std::string &MeshObject2D::id() const { return MeshObject2D::Id; }
388
389std::shared_ptr<GeometryHandler> MeshObject2D::getGeometryHandler() const { return m_handler; }
390
391size_t MeshObject2D::numberOfVertices() const { return m_vertices.size(); }
392
393size_t MeshObject2D::numberOfTriangles() const { return m_triangles.size() / 3; }
394
396
397std::vector<uint32_t> MeshObject2D::getTriangles() const { return m_triangles; }
398
400 // should be consistent with MeshObject2D::GetObjectGeom
402}
403
405 throw std::runtime_error("MeshObject2D::shapeInfo() is not implemented");
406}
407
408void MeshObject2D::GetObjectGeom(detail::ShapeInfo::GeometryShape &, std::vector<Kernel::V3D> &, double &, double &,
409 double &) const {
410 throw std::runtime_error("MeshObject2D::GetObjectGeom is not implemented");
411}
412
413void MeshObject2D::draw() const {
414 if (m_handler == nullptr)
415 return;
416 // Render the Object
417 m_handler->render();
418}
419
421 if (m_handler == nullptr)
422 return;
423 // Render the Object
424 m_handler->initialize();
425}
426
427} // namespace Mantid::Geometry
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
double tolerance
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition: BoundingBox.h:34
bool operator==(const MeshObject2D &other) const
bool isOnSide(const Kernel::V3D &) const override
Determine if point is on the side of the object.
int getPointInObject(Kernel::V3D &point) const override
Try to find a point that lies within (or on) the object.
detail::ShapeInfo::GeometryShape shape() const override
double solidAngle(const Kernel::V3D &observer) const override
Solid angle only considers triangle facing sample.
std::shared_ptr< GeometryHandler > m_handler
Geometry Handle for rendering.
Definition: MeshObject2D.h:106
std::vector< double > getVertices() const
const std::string & id() const override
static const double MinThickness
Definition: MeshObject2D.h:54
static const std::string Id
Id as static.
Definition: MeshObject2D.h:76
const detail::ShapeInfo & shapeInfo() const override
MeshObject2D * cloneWithMaterial(const Kernel::Material &material) const override
bool isValid(const Kernel::V3D &point) const override
Check if a point is inside.
std::vector< uint32_t > getTriangles() const
int getName() const override
struct Mantid::Geometry::MeshObject2D::PlaneParameters m_planeParameters
static bool pointsCoplanar(const std::vector< Kernel::V3D > &vertices)
Estalish if points are coplanar.
std::vector< uint32_t > m_triangles
Triangles are specified by indices into a list of vertices.
Definition: MeshObject2D.h:96
void draw() const override
std::shared_ptr< GeometryHandler > getGeometryHandler() const override
std::vector< Kernel::V3D > m_vertices
Vertices.
Definition: MeshObject2D.h:98
BoundingBox m_boundingBox
Bounding box.
Definition: MeshObject2D.h:104
const BoundingBox & getBoundingBox() const override
Returns an axis-aligned bounding box that will fit the shape.
Kernel::Material m_material
Material composition.
Definition: MeshObject2D.h:102
double distanceToPlane(const Kernel::V3D &point) const
void initialize()
Common initialization.
double distance(const Geometry::Track &ut) const override
Compute the distance to the first point of intersection with the mesh.
void GetObjectGeom(detail::ShapeInfo::GeometryShape &type, std::vector< Kernel::V3D > &vectors, double &innerRadius, double &radius, double &height) const override
int interceptSurface(Geometry::Track &ut) const override
Given a track, fill the track with valid section.
void initDraw() const override
MeshObject2D(std::vector< uint32_t > faces, std::vector< Kernel::V3D > vertices, const Kernel::Material &material)
Constructor.
const Kernel::Material & material() const override
bool hasValidShape() const override
double volume() const override
MeshObject2D * clone() const override
virtual void setMaterial(const Kernel::Material &material) override
boost::optional< Kernel::V3D > generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, const size_t) const override
Defines a track as a start point and a direction.
Definition: Track.h:165
const Kernel::V3D & startPoint() const
Returns the starting point.
Definition: Track.h:191
void addPoint(const TrackDirection direction, const Kernel::V3D &endPoint, const IObject &obj, const ComponentID compID=nullptr)
Adds a point of intersection to the track.
Definition: Track.cpp:124
void buildLink()
Construct links between added points.
Definition: Track.cpp:184
int count() const
Returns the number of links.
Definition: Track.h:219
const Kernel::V3D & direction() const
Returns the direction as a unit vector.
Definition: Track.h:193
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
Definition: Material.h:50
const std::string & name() const
Returns the name of the material.
Definition: Material.cpp:181
Defines a 1D pseudo-random number generator, i.e.
Class for 3D vectors.
Definition: V3D.h:34
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
Definition: V3D.h:274
constexpr double X() const noexcept
Get x.
Definition: V3D.h:232
constexpr double Y() const noexcept
Get y.
Definition: V3D.h:233
double norm() const noexcept
Definition: V3D.h:263
constexpr double norm2() const noexcept
Vector length squared.
Definition: V3D.h:265
constexpr double Z() const noexcept
Get z.
Definition: V3D.h:234
bool sufficientPoints(const std::vector< Kernel::V3D > &vertices)
Kernel::V3D validatePointsCoplanar(const std::vector< Kernel::V3D > &vertices)
Establish the surface normal for a set of vertices.
bool allCoplanar(const std::vector< Kernel::V3D > &vertices, const Kernel::V3D &normal)
Establish if all vertices are coplanar.
Kernel::V3D surfaceNormal(const std::vector< Kernel::V3D > &vertices)
Establish the first surface normal.
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.
MANTID_GEOMETRY_DLL bool isOnTriangle(const Kernel::V3D &point, const Kernel::V3D &v1, const Kernel::V3D &v2, const Kernel::V3D &v3)
isOnTriangle
bool MANTID_GEOMETRY_DLL intersection(const ConvexPolygon &P, const ConvexPolygon &Q, ConvexPolygon &out)
Compute the instersection of two convex polygons.
STL namespace.