MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
geometryanalytic.h
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#ifndef ANALYTICGEOMETRY_H
8#define ANALYTICGEOMETRY_H
9#include <iostream>
11#include "INCLUDE/maiatypes.h"
12#include "UTIL/functions.h"
13#include "UTIL/maiamath.h"
14
15namespace maia {
16namespace geom {
17
18template <typename T, MInt nDim>
19MBool doBoxesOverlap(const T* const a, const T* const b) {
20 for(MInt dim = 0; dim < nDim; dim++) {
21 if((a[dim] > b[dim + nDim]) || b[dim] > a[dim + nDim]) {
22 return false;
23 }
24 }
25 return true;
26}
27
28template <typename T, MInt nDim>
29MBool isBoxInsideBox(const T* const a, const T* const b) {
30 for(MInt dim = 0; dim < nDim; dim++) {
31 if((a[dim] < b[dim]) || a[dim + nDim] > b[dim + nDim]) {
32 return false;
33 }
34 }
35 return true;
36}
37
38template <typename T, MInt nDim>
39MBool isPointInsideBox(const T* const p, const T* const b) {
40 for(MInt dim = 0; dim < nDim; dim++) {
41 if((p[dim] < b[dim]) || p[dim] > b[dim + nDim]) {
42 return false;
43 }
44 }
45 return true;
46}
47
48template <MInt nDim>
49MBool isPointInsideSphere(const MFloat* const p, const MFloat* const c, const MFloat R) {
50 MFloat r = F0;
51 for(MInt dim = 0; dim < nDim; dim++) {
52 r += POW2(p[dim] - c[dim]);
53 }
54 return std::sqrt(r) < R;
55}
56
57
58// checks if point p is within a ring segment centered around c. The ring segment is given by r_min and r_max (R),
59// phi_min and phi_max (phi) and its rotational axis. Note, that R[0] < R[1] and phi[0] < phi[1] for this to work as
60// intended.
61template <MInt nDim>
62MBool isPointInsideRingSegment(const MFloat* const p, const MFloat* const c, const MFloat* const R,
63 const MFloat* const phi, const MInt axis) {
64 IF_CONSTEXPR(nDim == 2) {
65 std::cerr << "H-Patch not implemented for 2D, not refining any cells! Take care with the angle calculation in 2D "
66 "when fixing this!"
67 << std::endl;
68 return false;
69 }
70
71 std::array<MFloat, nDim> normalVector;
72 MFloat distance = F0;
73
74 // compute normal vector from axis to current point
75 for(MInt d = 0; d < nDim; d++) {
76 if(d == axis) {
77 normalVector[d] = F0;
78 } else {
79 normalVector[d] = p[d] - c[d];
80 distance += normalVector[d] * normalVector[d];
81 }
82 }
83
84 // check if cell is within r_min and r_max
85 distance = sqrt(distance);
86 if(distance < R[0] || distance > R[1]) return false;
87
88 // check if cell is within phi_min and phi_max
89 MFloat angle = atan2(normalVector[(axis + 2) % nDim], normalVector[(axis + 1) % nDim]) * 180.0 / PI;
90 if(angle < phi[0] || angle > phi[1]) return false;
91
92 return true;
93}
94
95template <MInt nDim>
96MBool isBoxInsideSphere(const MFloat* const p, const MFloat* const c, const MFloat R) {
97 MFloat pp[nDim];
98 const MInt cornerCode[8][3] = {{0, 0, 0}, {nDim, 0, 0}, {0, nDim, 0}, {nDim, nDim, 0},
99 {0, 0, nDim}, {nDim, 0, nDim}, {0, nDim, nDim}, {nDim, nDim, nDim}};
100 for(MInt corner = 0; corner < IPOW2(nDim); corner++) {
101 for(MInt dim = 0; dim < nDim; dim++) {
102 pp[dim] = p[dim + cornerCode[corner][dim]];
103 }
104 if(!(maia::geom::isPointInsideSphere<nDim>(pp, c, R))) {
105 return false;
106 }
107 }
108 return true;
109}
110
111template <typename T, MInt nDim>
112MBool isSphereInsideBox(const T* const c, const T R, const T* const p) {
113 T bbox[2 * nDim];
114 for(MInt dim = 0; dim < nDim; dim++) {
115 bbox[dim] = c[dim] - R;
116 bbox[dim + nDim] = c[dim] + R;
117 }
118 return maia::geom::isBoxInsideBox<T, nDim>(bbox, p);
119}
120
121
122template <MInt nDim>
123MBool doBoxAndSphereOverlap(const MFloat* const b, const MFloat* const c, const MFloat R) {
124 MFloat cp[nDim];
125 const MInt cornerCode[8][3] = {{0, 0, 0}, {nDim, 0, 0}, {0, nDim, 0}, {nDim, nDim, 0},
126 {0, 0, nDim}, {nDim, 0, nDim}, {0, nDim, nDim}, {nDim, nDim, nDim}};
127
128 // easy part
129 // is sphere center inside box?
130 if(maia::geom::isPointInsideBox<MFloat, nDim>(c, b)) {
131 return true;
132 }
133
134 // is a box corner in sphere?
135 for(MInt corner = 0; corner < IPOW2(nDim); corner++) {
136 for(MInt dim = 0; dim < nDim; dim++) {
137 cp[dim] = b[dim + cornerCode[corner][dim]];
138 }
139 if(maia::geom::isPointInsideSphere<nDim>(cp, c, R)) {
140 return true;
141 }
142 }
143
144 // 'tricky part' reducing the dimensions
145 // what region relative to the cube is the sphere center located in
146 MInt insideCnt = 0;
147 MFloat p[nDim];
148 MFloat lc[nDim];
149 for(MInt dim = 0; dim < nDim; dim++) {
150 if(c[dim] > b[dim] && c[dim] < b[dim + nDim]) {
151 p[dim] = F0;
152 lc[dim] = F0;
153 insideCnt++;
154 } else {
155 lc[dim] = c[dim];
156 p[dim] = (c[dim] <= b[dim]) ? b[dim] : b[dim + nDim];
157 }
158 }
159
160 // the closest point is a corner, we already checked them
161 if(insideCnt == 0) {
162 return false;
163 }
164
165 // the cosest point is found checking the outside dimensions
166 return maia::geom::isPointInsideSphere<nDim>(p, lc, R);
167}
168
169template <MInt nDim>
170MBool doesLinePenetrateBox(const MFloat* const line, const MFloat* const bbox) {
171 IF_CONSTEXPR(nDim > 3 || nDim < 2) { mTerm(1, AT_, "neither 2 nor 3 dimensional"); }
172
173 // create a line bounding box
174 MFloat bbox_line[2 * nDim];
175 for(MInt dim = 0; dim < nDim; dim++) {
176 if(line[dim] < line[dim + nDim]) {
177 bbox_line[dim] = line[dim];
178 bbox_line[dim + nDim] = line[dim + nDim];
179 } else {
180 bbox_line[dim] = line[dim + nDim];
181 bbox_line[dim + nDim] = line[dim];
182 }
183 }
184
185 // check bounding boxes for overlap
186 // a separation axis can be found in the cartesian axis
187 if(!maia::geom::doBoxesOverlap<MFloat, nDim>(bbox_line, bbox)) {
188 return false;
189 }
190
191 // translate box to center and scale to unit cube
192 MFloat line_c[2 * nDim];
193 for(MInt dim = 0; dim < nDim; dim++) {
194 const MFloat halfLength = (bbox[dim + nDim] - bbox[dim]) / F2;
195 line_c[dim] = (line[dim] - bbox[dim]) / halfLength - 0.5;
196 line_c[dim + nDim] = (line[dim + nDim] - bbox[dim]) / halfLength - 0.5;
197 }
198
199 MFloat line_span[3] = {F0, F0, F0};
200 MFloat lineLength = F0;
201 for(MInt dim = 0; dim < nDim; dim++) {
202 line_span[dim] = line_c[dim + nDim] - line_c[dim];
203 lineLength += POW2(line_span[dim]);
204 }
205 lineLength = std::sqrt(lineLength);
206 for(MInt dim = 0; dim < nDim; dim++) {
207 line_span[dim] /= lineLength;
208 }
209
210 const MFloat radius = nDim * F1B4;
211 for(MInt e = 2; e > ((nDim == 2) ? 1 : -1); e--) {
212 // generate separation axis
213 MFloat axis[3];
214 MFloat e_vec[3] = {F0, F0, F0};
215 e_vec[e] = F1;
216 maia::math::cross(line_span, e_vec, axis);
217
218 // project one of the points on the axis
219 MFloat line_projection = F0;
220 for(MInt dim = 0; dim < nDim; dim++) {
221 line_projection += axis[dim] * line_c[dim];
222 }
223
224 // larger equal radius means no penetration but maybe a contactpoint
225 if(POW2(line_projection) >= radius) {
226 return false;
227 }
228
229 // project the corner of the cube ...
230 // which corner to project
231 MFloat corner_projection = F0;
232 for(MInt dim = 0; dim < nDim; dim++) {
233 corner_projection += axis[dim] * ((axis[dim] > 0) ? 0.5 : -0.5);
234 }
235
236 // larger equal radius means no penetration but maybe a contactpoint
237 if(std::fabs(line_projection) >= std::fabs(corner_projection)) {
238 return false;
239 }
240 }
241
242 // if no separation axis can be found, there has to be a penetration
243 return true;
244}
245
246template <MInt nDim>
247MBool doesLinePenetrateSphere(const MFloat* const line, const MFloat* const center, const MFloat radius) {
248 const MBool p1_inside = maia::geom::isPointInsideSphere<nDim>(line, center, radius);
249 const MBool p2_inside = maia::geom::isPointInsideSphere<nDim>(line + nDim, center, radius);
250
251 if(p1_inside && p2_inside) {
252 return false;
253 }
254
255 if(p1_inside != p2_inside) {
256 return true;
257 }
258
259 // at this point both end points of the line are outside the sphere
260
261 // create a line and sphere bounding box
262 MFloat bbox_line[2 * nDim];
263 MFloat bbox_sphere[2 * nDim];
264 for(MInt dim = 0; dim < nDim; dim++) {
265 bbox_sphere[dim] = center[dim] - radius;
266 bbox_sphere[dim + nDim] = center[dim] + radius;
267 if(line[dim] < line[dim + nDim]) {
268 bbox_line[dim] = line[dim];
269 bbox_line[dim + nDim] = line[dim + nDim];
270 } else {
271 bbox_line[dim] = line[dim + nDim];
272 bbox_line[dim + nDim] = line[dim];
273 }
274 }
275
276 // check bounding boxes for overlap
277 // a separation axis can be found in the cartesian axis
278 if(!maia::geom::doBoxesOverlap<MFloat, nDim>(bbox_line, bbox_sphere)) {
279 return false;
280 }
281
282 MFloat a = F0;
283 MFloat b = F0;
284 MFloat c = -POW2(radius);
285 for(MInt dim = 0; dim < nDim; dim++) {
286 const MFloat dl = line[dim + nDim] - line[dim];
287 const MFloat dlc = line[dim] - center[dim];
288 a += POW2(dl);
289 b += dl * dlc;
290 c += POW2(dlc);
291 }
292
293 const MFloat D = POW2(b / a) - c / a;
294 if(D <= F0) {
295 return false;
296 }
297
298 // at this point there have to be two valid intersections or none
299 // it should be enough to check one of them
300
301 const MFloat t_p = b / a + sqrt(D);
302
303 // check the intersection if they lie on the line segment
304 return (t_p <= F1) && (t_p >= F0);
305}
306
307} // namespace geom
308} // namespace maia
309#endif // ANALYTICGEOMETRY_H
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW2(const Real x)
Definition: functions.h:119
constexpr MLong IPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
MBool doesLinePenetrateSphere(const MFloat *const line, const MFloat *const center, const MFloat radius)
MBool isSphereInsideBox(const T *const c, const T R, const T *const p)
MBool isPointInsideSphere(const MFloat *const p, const MFloat *const c, const MFloat R)
MBool isPointInsideRingSegment(const MFloat *const p, const MFloat *const c, const MFloat *const R, const MFloat *const phi, const MInt axis)
MBool doBoxesOverlap(const T *const a, const T *const b)
MBool doBoxAndSphereOverlap(const MFloat *const b, const MFloat *const c, const MFloat R)
MBool doesLinePenetrateBox(const MFloat *const line, const MFloat *const bbox)
MBool isBoxInsideSphere(const MFloat *const p, const MFloat *const c, const MFloat R)
MBool isPointInsideBox(const T *const p, const T *const b)
MBool isBoxInsideBox(const T *const a, const T *const b)
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101
Namespace for auxiliary functions/classes.
Definition: contexttypes.h:19