https://mooseframework.inl.gov
GeometryUtils.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 "GeometryUtils.h"
11 #include "MooseUtils.h"
12 
13 namespace geom_utils
14 {
15 
16 bool
17 isPointZero(const Point & pt)
18 {
19  const Point zero(0.0, 0.0, 0.0);
20  return pt.absolute_fuzzy_equals(zero);
21 }
22 
23 Point
24 unitVector(const Point & pt, const std::string & name)
25 {
26  if (isPointZero(pt))
27  mooseError("'" + name + "' cannot have zero norm!");
28 
29  return pt.unit();
30 }
31 
32 Real
33 minDistanceToPoints(const Point & pt,
34  const std::vector<Point> & candidates,
35  const unsigned int axis)
36 {
37  const auto idx = projectedIndices(axis);
38 
40  for (const auto & c : candidates)
41  {
42  const Real dx = c(idx.first) - pt(idx.first);
43  const Real dy = c(idx.second) - pt(idx.second);
44  const Real d = std::sqrt(dx * dx + dy * dy);
46  }
47 
48  return distance;
49 }
50 
51 Point
52 projectPoint(const Real x0, const Real x1, const unsigned int axis)
53 {
54  const auto i = projectedIndices(axis);
55  Point point;
56  point(i.first) = x0;
57  point(i.second) = x1;
58  point(axis) = 0.0;
59 
60  return point;
61 }
62 
63 Real
64 projectedLineHalfSpace(Point pt1, Point pt2, Point pt3, const unsigned int axis)
65 {
66  // project points onto plane perpendicular to axis
67  pt1(axis) = 0.0;
68  pt2(axis) = 0.0;
69  pt3(axis) = 0.0;
70 
71  const auto i = projectedIndices(axis);
72 
73  return (pt1(i.first) - pt3(i.first)) * (pt2(i.second) - pt3(i.second)) -
74  (pt2(i.first) - pt3(i.first)) * (pt1(i.second) - pt3(i.second));
75 }
76 
77 bool
78 pointInPolygon(const Point & point, const std::vector<Point> & corners, const unsigned int axis)
79 {
80  const auto n_pts = corners.size();
81 
82  std::vector<bool> negative_half_space;
83  std::vector<bool> positive_half_space;
84  for (const auto i : index_range(corners))
85  {
86  const int next = (i == n_pts - 1) ? 0 : i + 1;
87  const auto half = projectedLineHalfSpace(point, corners[i], corners[next], axis);
88  negative_half_space.push_back(half < 0);
89  positive_half_space.push_back(half > 0);
90  }
91 
92  const bool negative = std::find(negative_half_space.begin(), negative_half_space.end(), true) !=
93  negative_half_space.end();
94  const bool positive = std::find(positive_half_space.begin(), positive_half_space.end(), true) !=
95  positive_half_space.end();
96 
97  const bool in_polygon = !(negative && positive);
98  if (in_polygon)
99  return true;
100 
101  if (pointOnEdge(point, corners, axis))
102  return true;
103 
104  return false;
105 }
106 
107 bool
108 pointOnEdge(const Point & point, const std::vector<Point> & corners, const unsigned int axis)
109 {
110  const auto n_pts = corners.size();
111  const auto idx = projectedIndices(axis);
112 
113  constexpr Real tol = 1e-8;
114  for (const auto i : index_range(corners))
115  {
116  const int next = (i == n_pts - 1) ? 0 : i + 1;
117  const auto & pt1 = corners[i];
118  const auto & pt2 = corners[next];
119  const bool close_to_line = projectedDistanceFromLine(point, pt1, pt2, axis) < tol;
120 
121  // we can stop early if we know we're not close to the line
122  if (!close_to_line)
123  continue;
124 
125  // check that the point is "between" the two points; TODO: first pass
126  // we can just compare x and y coordinates
127  const bool between_points = (point(idx.first) >= std::min(pt1(idx.first), pt2(idx.first))) &&
128  (point(idx.first) <= std::max(pt1(idx.first), pt2(idx.first))) &&
129  (point(idx.second) >= std::min(pt1(idx.second), pt2(idx.second))) &&
130  (point(idx.second) <= std::max(pt1(idx.second), pt2(idx.second)));
131 
132  // point needs to be close to the line AND "between" the two points
133  if (close_to_line && between_points)
134  return true;
135  }
136 
137  return false;
138 }
139 
140 std::pair<unsigned int, unsigned int>
141 projectedIndices(const unsigned int axis)
142 {
143  std::pair<unsigned int, unsigned int> indices;
144 
145  if (axis == 0)
146  {
147  indices.first = 1;
148  indices.second = 2;
149  }
150  else if (axis == 1)
151  {
152  indices.first = 0;
153  indices.second = 2;
154  }
155  else
156  {
157  indices.first = 0;
158  indices.second = 1;
159  }
160 
161  return indices;
162 }
163 
164 Point
165 projectedUnitNormal(Point pt1, Point pt2, const unsigned int axis)
166 {
167  // project the points to the plane perpendicular to the axis
168  pt1(axis) = 0.0;
169  pt2(axis) = 0.0;
170 
171  const auto i = projectedIndices(axis);
172 
173  const Real dx = pt2(i.first) - pt1(i.first);
174  const Real dy = pt2(i.second) - pt1(i.second);
175 
176  const Point normal = projectPoint(dy, -dx, axis);
177  const Point gap_line = pt2 - pt1;
178 
179  const auto cross_product = gap_line.cross(normal);
180 
181  if (cross_product(axis) > 0)
182  return normal.unit();
183  else
184  return projectPoint(-dy, dx, axis).unit();
185 }
186 
187 Real
188 distanceFromLine(const Point & pt, const Point & line0, const Point & line1)
189 {
190  const Point a = pt - line0;
191  const Point b = pt - line1;
192  const Point c = line1 - line0;
193 
194  return (a.cross(b).norm()) / c.norm();
195 }
196 
197 Real
198 projectedDistanceFromLine(Point pt, Point line0, Point line1, const unsigned int axis)
199 {
200  // project all the points to the plane perpendicular to the axis
201  pt(axis) = 0.0;
202  line0(axis) = 0.0;
203  line1(axis) = 0.0;
204 
205  return distanceFromLine(pt, line0, line1);
206 }
207 
208 std::vector<Point>
209 polygonCorners(const unsigned int num_sides, const Real radius, const unsigned int axis)
210 {
211  std::vector<Point> corners;
212  const Real theta = 2.0 * M_PI / num_sides;
213  const Real first_angle = M_PI / 2.0 - theta / 2.0;
214 
215  for (const auto i : make_range(num_sides))
216  {
217  const Real angle = first_angle + i * theta;
218  const Real x = radius * cos(angle);
219  const Real y = radius * sin(angle);
220 
221  corners.push_back(projectPoint(x, y, axis));
222  }
223 
224  return corners;
225 }
226 
227 Point
228 rotatePointAboutAxis(const Point & p, const Real angle, const Point & axis)
229 {
230  const Real cos_theta = cos(angle);
231  const Real sin_theta = sin(angle);
232 
233  Point pt;
234  const Real xy = axis(0) * axis(1);
235  const Real xz = axis(0) * axis(2);
236  const Real yz = axis(1) * axis(2);
237 
238  const Point x_op(cos_theta + axis(0) * axis(0) * (1.0 - cos_theta),
239  xy * (1.0 - cos_theta) - axis(2) * sin_theta,
240  xz * (1.0 - cos_theta) + axis(1) * sin_theta);
241 
242  const Point y_op(xy * (1.0 - cos_theta) + axis(2) * sin_theta,
243  cos_theta + axis(1) * axis(1) * (1.0 - cos_theta),
244  yz * (1.0 - cos_theta) - axis(0) * sin_theta);
245 
246  const Point z_op(xz * (1.0 - cos_theta) - axis(1) * sin_theta,
247  yz * (1.0 - cos_theta) + axis(0) * sin_theta,
248  cos_theta + axis(2) * axis(2) * (1.0 - cos_theta));
249 
250  pt(0) = x_op * p;
251  pt(1) = y_op * p;
252  pt(2) = z_op * p;
253  return pt;
254 }
255 
256 std::vector<Point>
257 boxCorners(const libMesh::BoundingBox & box, const Real factor)
258 {
259  Point diff = (box.max() - box.min()) / 2.0;
260  const Point origin = box.min() + diff;
261 
262  // Rescale side length of box by specified factor
263  diff *= factor;
264 
265  // Vectors for sides of box
266  const Point dx(2.0 * diff(0), 0.0, 0.0);
267  const Point dy(0.0, 2.0 * diff(1), 0.0);
268  const Point dz(0.0, 0.0, 2.0 * diff(2));
269 
270  std::vector<Point> verts(8, origin - diff);
271  const unsigned int pts_per_dim = 2;
272  for (const auto z : make_range(pts_per_dim))
273  for (const auto y : make_range(pts_per_dim))
274  for (const auto x : make_range(pts_per_dim))
275  verts[pts_per_dim * pts_per_dim * z + pts_per_dim * y + x] += x * dx + y * dy + z * dz;
276 
277  return verts;
278 }
279 
280 } // end namespace geom_utils
std::string name(const ElemQuality q)
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sin(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tan
const Real radius
libMesh::Point projectPoint(const libMesh::Real x0, const libMesh::Real x1, const unsigned int axis)
Given two coordinates, construct a point in the 2-D plane perpendicular to the specified axis...
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
libMesh::Real projectedDistanceFromLine(libMesh::Point pt, libMesh::Point line0, libMesh::Point line1, const unsigned int axis)
Compute the distance from a 3-D line, provided in terms of two points on the line.
libMesh::Real projectedLineHalfSpace(libMesh::Point pt1, libMesh::Point pt2, libMesh::Point pt3, const unsigned int axis)
If positive, point is on the positive side of the half space (and vice versa).
libMesh::Point projectedUnitNormal(libMesh::Point pt1, libMesh::Point pt2, const unsigned int axis)
Get the unit normal vector between two points (which are first projected onto the plane perpendicular...
libMesh::Point rotatePointAboutAxis(const libMesh::Point &p, const libMesh::Real angle, const libMesh::Point &axis)
Rotate point about an axis.
const Number zero
std::vector< libMesh::Point > polygonCorners(const unsigned int num_sides, const libMesh::Real radius, const unsigned int axis)
Get the corner coordinates of a regular 2-D polygon, assuming a face of the polygon is parallel to th...
Real distance(const Point &p)
auto max(const L &left, const R &right)
TypeVector< Real > unit() const
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cos(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cos
bool pointOnEdge(const libMesh::Point &point, const std::vector< libMesh::Point > &corners, const unsigned int axis)
Whether a point is on the edge of a 2-D polygon in the plane perpendicular to the specified axis...
const Point & min() const
libMesh::Point unitVector(const libMesh::Point &pt, const std::string &name)
Get the unit vector for a point parameter.
bool isPointZero(const libMesh::Point &pt)
Check whether a point is equal to zero.
std::pair< unsigned int, unsigned int > projectedIndices(const unsigned int axis)
Get the indices of the plane perpendicular to the specified axis.
libMesh::Real distanceFromLine(const libMesh::Point &pt, const libMesh::Point &line0, const libMesh::Point &line1)
Compute the distance from a 3-D line, provided in terms of two points on the line.
libMesh::Real minDistanceToPoints(const libMesh::Point &pt, const std::vector< libMesh::Point > &candidates, const unsigned int axis)
Get the minimum distance from a point to another set of points, in the plane perpendicular to the spe...
std::vector< libMesh::Point > boxCorners(const libMesh::BoundingBox &box, const libMesh::Real factor)
Get corner points of a bounding box, with side length re-scaled.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool pointInPolygon(const libMesh::Point &point, const std::vector< libMesh::Point > &corners, const unsigned int axis)
Whether a point is in 2-D a polygon in the plane perpendicular to the specified axis, given by corner points.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
IntRange< T > make_range(T beg, T end)
const Point & max() const
auto min(const L &left, const R &right)
auto index_range(const T &sizable)
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)