https://mooseframework.inl.gov
Loading...
Searching...
No Matches
OrientedBoundingBox.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "OrientedBoundingBox.h"
11#include "MooseError.h"
12#include "MooseUtils.h"
13
14#include <cmath>
15
16#include "libmesh/replicated_mesh.h"
17#include "libmesh/mesh_generation.h"
18#include "libmesh/elem.h"
19#include "libmesh/node.h"
20#include "libmesh/enum_elem_type.h"
21
22namespace fs = std::filesystem;
23
25
26OrientedBoundingBox::OrientedBoundingBox(const std::vector<std::pair<Point, Point>> & axis_pairs)
27{
28 _dim = static_cast<unsigned int>(axis_pairs.size());
29 mooseAssert(_dim == 2 || _dim == 3, "OrientedBoundingBox requires 2 or 3 axis pairs");
30 _dirs.resize(_dim);
31 _len.resize(_dim);
32
33 _minimal_corner = axis_pairs[0].first;
34
36 // (a) Build orthonormal basis & lengths
37 for (const auto i : make_range(_dim))
38 {
39 const Point vec = axis_pairs[i].second - _minimal_corner;
40 _dirs[i] = vec.unit();
41 _len[i] = vec.norm();
42 _maximal_corner += _len[i] * _dirs[i];
43 }
44
45 // (b) Ensure orthogonality
46 for (const auto i : make_range(_dim))
47 for ([[maybe_unused]] const auto j : make_range(i + 1, _dim))
48 mooseAssert(MooseUtils::absoluteFuzzyEqual(_dirs[i] * _dirs[j], 0.0),
49 "Basis directions are not orthogonal");
50}
51
52void
53OrientedBoundingBox::print(std::ostream & os) const
54{
55 os << "OrientedBoundingBox: dim=" << _dim << ", origin=" << _minimal_corner << '\n';
56 for (const auto i : make_range(_dim))
57 os << " axis[" << i << "] dir=" << _dirs[i] << ", len=" << _len[i] << '\n';
58}
59
60bool
61OrientedBoundingBox::contains(const Point & pt, const Real tolerance) const
62{
63 const Point rel = pt - _minimal_corner;
64 for (const auto i : make_range(_dim))
65 {
66 const Real proj = rel * _dirs[i];
67 if (!MooseUtils::absoluteFuzzyGreaterEqual(proj, 0.0, tolerance) ||
68 !MooseUtils::absoluteFuzzyLessEqual(proj, _len[i], tolerance))
69 return false;
70 }
71 return true;
72}
73
74Point
79
80Point
82{
83 mooseAssert(i < _dim, "Invalid axis index");
84 return _dirs[i];
85}
86
87Real
89{
90 mooseAssert(i < _dim, "Invalid axis index");
91 return _len[i];
92}
93
94Real
95OrientedBoundingBox::getProjectedLength(const Point & pt, unsigned int i) const
96{
97 mooseAssert(i < _dim, "Invalid axis index");
98 const Point rel = pt - _minimal_corner;
99 return rel * _dirs[i];
100}
101
102Point
107
108Point
113
114void
115OrientedBoundingBox::writeMesh(const fs::path & path,
116 const libMesh::Parallel::Communicator & comm) const
117{
118 mooseAssert(_dim == 2 || _dim == 3, "writeMesh supports only 2D or 3D boxes.");
119
120 // Build a single reference element (unit square in 2D, unit cube in 3D) and let
121 // libMesh own the node ordering, connectivity, and output format.
123 if (_dim == 2)
125 else
127 mesh, 1, 1, 1, 0., 1., 0., 1., 0., 1., libMesh::HEX8);
128
129 // Map each reference corner onto the oriented box:
130 // x = origin + sum_axis r_axis * len_axis * dir_axis
131 for (auto * node : mesh.node_ptr_range())
132 {
133 const Point reference = *node;
134 Point mapped = _minimal_corner;
135 for (const auto axis : make_range(_dim))
136 mapped += reference(axis) * _len[axis] * _dirs[axis];
137 *node = mapped;
138 }
139
140 if (!path.parent_path().empty())
141 {
142 std::error_code ec;
143 fs::create_directories(path.parent_path(), ec);
144 }
145 mesh.write(path.string());
146}
147
148void
150 const libMesh::Parallel::Communicator & comm) const
151{
152 mooseAssert(_dim == 2 || _dim == 3, "Ray writing only supports 2D or 3D");
153
154 unsigned int i_min = 0;
155 for (const auto i : make_range(1u, _dim))
156 if (_len[i] < _len[i_min])
157 i_min = i;
158
159 Point start = _minimal_corner;
160 for (const auto i : make_range(_dim))
161 if (i != i_min)
162 start += 0.5 * _len[i] * _dirs[i];
163
164 const Point end = start + _len[i_min] * _dirs[i_min];
165
166 // A single EDGE2 spanning the ray; libMesh owns the output format.
168 libMesh::Node * n0 = mesh.add_point(start, 0);
169 libMesh::Node * n1 = mesh.add_point(end, 1);
170 auto edge = libMesh::Elem::build(libMesh::EDGE2);
171 edge->set_node(0, n0);
172 edge->set_node(1, n1);
173 mesh.add_elem(std::move(edge));
174 mesh.prepare_for_use();
175
176 if (!ray_path.parent_path().empty())
177 {
178 std::error_code ec;
179 fs::create_directories(ray_path.parent_path(), ec);
180 }
181 mesh.write(ray_path.string());
182}
OrientedBoundingBox()
Default-constructs an empty box (zero dimension, no axes).
std::vector< Real > _len
length along each basis (size = _dim)
Point _minimal_corner
shared minimal corner
Real getAxisLength(unsigned int i) const
unsigned int _dim
spatial dimension (2 or 3)
std::vector< Point > _dirs
orthonormal basis vectors (size = _dim)
bool contains(const Point &pt, const Real tolerance=libMesh::TOLERANCE) const
Test whether a point lies inside or on the box.
void writeRayAlongShortestAxis(const std::filesystem::path &ray_path, const libMesh::Parallel::Communicator &comm) const
Write a single-EDGE2 mesh representing a "ray" emanating from the box.
Point getAxisDirection(unsigned int i) const
Point _maximal_corner
shared maximal corner
void writeMesh(const std::filesystem::path &path, const libMesh::Parallel::Communicator &comm) const
Write the oriented box as a single libMesh element to a mesh file.
Real getProjectedLength(const Point &pt, unsigned int i) const
Get the length of the projection of a point onto axis i.
void print(std::ostream &os) const
Print a summary (dimension, origin, axes).
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)