OpenBEM
Open-source framework for electromagnetic simulation with the boundary element method.
Loading...
Searching...
No Matches
triangle.cpp
Go to the documentation of this file.
1// OpenBEM - Copyright (C) 2026 Shashwat Sharma
2
3// This file is part of OpenBEM.
4
5// OpenBEM is free software: you can redistribute it and/or modify it under the terms of the
6// GNU General Public License as published by the Free Software Foundation, either version 3
7// of the License, or (at your option) any later version.
8
9// You should have received a copy of the GNU General Public License along with OpenBEM.
10// If not, see <https://www.gnu.org/licenses/>.
11
12
20
21#include <stdexcept>
22
23#include <external/Eigen/Dense>
24
25#include "types.hpp"
26#include "constants.hpp"
27
28
29namespace bem
30{
31
32template <uint8_t dim>
35 EigRowVecN<Float, 3> edge_polarities
36 )
37{
38 v_ = v;
39 edge_polarities_ = edge_polarities;
40 area_ = area(v_);
41 normal_ = normal(v_);
42 centroid_ = centroid(v_);
43 return;
44};
45
46
47template <uint8_t dim>
49{
51 EigColVecN<Float, dim> v10 = v_.col(1) - v_.col(0);
52
53 v_2d.col(0) << 0.0, 0.0;
54 v_2d.col(1) << v10.norm(), 0.0;
55
56 if (v_2d.col(1)[0] == 0.0)
57 throw std::domain_error("Triangle::get_triangle_in_2d(): divide by zero.");
58
59 uint8_t nverts = 1;
60 EigMatNX<Float, dim> vn0 = v_.rightCols(1) - v_.col(0);
61
62 EigRowVec<Float> x = (v10.transpose() * vn0) / v_2d.col(1)[0];
63 EigRowVec<Float> y = vn0.colwise().squaredNorm();
64
65 y.array() -= x.array() * x.array();
66 v_2d.topRightCorner(1, 1) = x;
67 v_2d.bottomRightCorner(1, 1) = Eigen::sqrt(y.array()).matrix();
68
69 return Triangle<2> (v_2d, edge_polarities_);
70};
71
72
73template <uint8_t dim>
75{
77 v_3d.topRows(dim) = v_.topRows(dim);
78 return Triangle<3> (v_3d, edge_polarities_);
79};
80
81
82template <uint8_t dim>
84{
85 EigColVecN<Float, dim> v10 = v_.col(1) - v_.col(0);
86
87 Float norm_v10 = v10.norm();
88 if (norm_v10 == 0.0)
89 throw std::domain_error("Triangle::local_coordinate_basis(): zero-length edge encountered.");
90
92
93 uvw.col(0) = v10 / norm_v10;
94
96 u_3d.topRows(dim) = uvw.col(0);
97 EigColVecN<Float, 3> nxu = normal_.cross(u_3d);
98 Float norm_nxu = nxu.norm();
99 if (norm_nxu == 0.0)
100 throw std::domain_error("Triangle::local_coordinate_basis(): zero-division encountered.");
101
102 uvw.col(1) = nxu.topRows(dim) / norm_nxu;
103 if constexpr (dim == 3)
104 uvw.col(2) = normal_;
105
106 return uvw;
107};
108
109
110template <uint8_t dim>
116 ) const
117{
119 r_diff.topRows(dim).colwise() -= v_.col(ref_idx);
120 d = normal_.transpose() * r_diff;
121 r_proj = (r - (normal_ * d)).topRows(dim);
122 // r_proj = (r_diff.topRows(dim) - (normal_ * d).topRows(dim)).colwise() + v_.col(ref_idx);
123
124 return;
125};
126
127
128template <uint8_t dim>
130{
132 v.setZero();
133 v(0, 1) = 1.0;
134 v(1, 2) = 1.0;
135 Triangle<dim> tri (v);
136 return tri;
137};
138
139
140template <uint8_t dim>
142{
143
144 EigColVecN<Float, dim> v0 = v_.col(1) - v_.col(0);
145 EigColVecN<Float, dim> v1 = v_.col(2) - v_.col(0);
146 EigMatNX<Float, dim> v2 = p.colwise() - v_.col(0);
147
148 Float d00 = v0.dot(v0);
149 Float d01 = v0.dot(v1);
150 Float d11 = v1.dot(v1);
151
152 Float denom = (d00 * d11 - d01 * d01);
153
154 if (denom == 0.0)
155 throw std::domain_error("Triangle::barycentric_coords(): divide by zero.");
156 Float inv_denom = 1.0 / denom;
157
158 EigRowVec<Float> d20 = v0.transpose() * v2;
159 EigRowVec<Float> d21 = v1.transpose() * v2;
160
162 lambda.row(1).noalias() = (d11 * d20 - d01 * d21) * inv_denom;
163 lambda.row(2).noalias() = (d00 * d21 - d01 * d20) * inv_denom;
164 lambda.row(0).noalias() = EigMatNX<Float, 1>::Ones(1, p.cols()) - lambda.row(1) - lambda.row(2);
165
166 return lambda;
167
168};
169
170
171template <uint8_t dim>
173{
174 Float tol = TRIANGLE_DEFAULT_TOL * shortest_edge_length();
175
176 auto between_0_and_1 = [&tol] (Float val) -> bool
177 {
178 if (val > tol && val - 1 < -tol)
179 return true;
180 return false;
181 };
182
183 auto is_0 = [&tol] (Float val) -> bool
184 {
185 if (std::abs(val) < tol)
186 return true;
187 return false;
188 };
189
190 auto is_1 = [&tol] (Float val) -> bool
191 {
192 if (std::abs(val - 1) < tol)
193 return true;
194 return false;
195 };
196
197 EigMatNX<Float, 3> lambda = barycentric_coords(r.topRows(dim));
199
200 for (uint32_t col = 0; col < r.cols(); ++col)
201 {
203
204 if (between_0_and_1(lambda_c[0]) &&
207 {
208 // strictly inside
209 loc[col] = 0;
210 }
211 else if ((is_0(lambda_c[0]) && is_0(lambda_c[1]) && is_1(lambda_c[2])) ||
212 (is_0(lambda_c[0]) && is_0(lambda_c[2]) && is_1(lambda_c[1])) ||
213 (is_0(lambda_c[2]) && is_0(lambda_c[1]) && is_1(lambda_c[0])))
214 {
215 // at a vertex
216 loc[col] = 1;
217 }
219 && is_0(lambda_c[2])) ||
221 && is_0(lambda_c[1])) ||
223 && is_0(lambda_c[0])))
224 {
225 // on an edge
226 loc[col] = 2;
227 }
228 else
229 {
230 // strictly outside
231 loc[col] = 3;
232 }
233 }
234
235 return loc;
236
237};
238
239
240template <uint8_t dim>
242{
243 Float abs_tol = tol * shortest_edge_length();
244
245 for (uint8_t ii = 0; ii < 3; ++ii)
246 {
247 Edge<dim> edge (v_.col(ii), v_.col((ii + 1) % 3));
248 if (edge.point_on_edge(r, tol))
249 return true;
250 }
251
253
254 p.col(0) = v_.col(0);
255 p.col(1) = v_.col(1);
256 p.col(2) = r;
258
259 if (tri1.shortest_edge_length() < abs_tol)
260 return true;
261
262 p.col(0) = v_.col(1);
263 p.col(1) = v_.col(2);
264 p.col(2) = r;
266
267 if (tri2.shortest_edge_length() < abs_tol)
268 return true;
269
270 p.col(0) = v_.col(2);
271 p.col(1) = v_.col(0);
272 p.col(2) = r;
274
275 if (tri3.shortest_edge_length() < abs_tol)
276 return true;
277
278 if (std::abs(tri1.normal().dot(tri2.normal()) - 1.0) < abs_tol &&
279 std::abs(tri2.normal().dot(tri3.normal()) - 1.0) < abs_tol)
280 return true;
281
282 return false;
283};
284
285
286template <uint8_t dim>
288{
289 Float area = 0;
290
291 if constexpr (dim == 2)
292 {
293 area = 0.5 * std::abs(v(0, 0) * (v(1, 1) - v(1, 2)) -
294 v(1, 0) * (v(0, 1) - v(0, 2)) +
295 (v(0, 1) * v(1, 2) - v(1, 1) * v(0, 2)));
296 }
297 else if constexpr (dim == 3)
298 {
299 area = ((v.col(1) - v.col(0)).cross(v.col(2) - v.col(0))).norm() / 2.0;
300 }
301
302 return area;
303};
304
305
306template <uint8_t dim>
308{
309 if constexpr (dim == 2)
310 return {0.0, 0.0, 1.0};
311 else if constexpr (dim == 3)
312 {
313 EigColVecN<Float, 3> orth = (v.col(1) - v.col(0)).cross(v.col(2) - v.col(1));
314 Float norm = orth.norm();
315 return orth / norm;
316 }
317};
318
319
320template class Triangle<2>;
321template class Triangle<3>;
322
323}
Triangle< 3 > to_3d(const Float z=0.0) const
Adds a 0-valued third dimension if this Triangle is in 2D, otherwise just returns a copy of this Tria...
Definition triangle.cpp:74
void get_plane_projection(EigMatNX< Float, dim > &r_proj, EigRowVec< Float > &d, ConstEigRef< EigMatNX< Float, 3 > > r, uint8_t ref_idx=0) const
Returns the projection of given points on to the triangle's plane, along with the normal distance to ...
Definition triangle.cpp:111
EigMatMN< Float, dim, dim > local_coordinate_basis() const
Returns the unit vectors of a local coordinate system, defined in the global system,...
Definition triangle.cpp:83
Float area() const
Returns the area of this Triangle.
Definition triangle.hpp:162
EigColVecN< Float, 3 > normal() const
Returns the unit normal vector for this Triangle.
Definition triangle.hpp:170
static Triangle< dim > reference_triangle()
Returns a reference triangle in the specified dimension.
Definition triangle.cpp:129
void set_v(ConstEigRef< EigMatMN< Float, dim, 3 > > v, EigRowVecN< Float, 3 > edge_polarities=EigRowVecN< Float, 3 >::Constant(1, 3, 1))
Sets the vertices of this Triangle.
Definition triangle.cpp:33
EigMatNX< Float, 3 > barycentric_coords(ConstEigRef< EigMatNX< Float, dim > > p) const
Returns barycentric coordinates of given points lying in the Triangle's plane.
Definition triangle.cpp:141
Triangle< 2 > to_2d() const
Returns an equivalent triangle with coordinates in a local 2D system, with the local origin at this t...
Definition triangle.cpp:48
bool point_in_triangle(ConstEigRef< EigColVecN< Float, dim > > r, const Float tol=TRIANGLE_DEFAULT_TOL) const
Checks whether a given point is inside the triangle, inclusive of edges and vertices.
Definition triangle.cpp:241
EigRowVec< uint8_t > projection_loc(ConstEigRef< EigMatNX< Float, 3 > > r) const
Returns flags that indicate whether the given points project inside or outside the triangle,...
Definition triangle.cpp:172
const Eigen::Ref< const EigObj > ConstEigRef
Read-only reference to an Eigen object.
Definition types.hpp:98
Eigen::Matrix< T, 1, Eigen::Dynamic > EigRowVec
Dynamic-size row vector containing type T.
Definition types.hpp:90
Eigen::Matrix< T, M, N > EigMatMN
Fixed-size matrix with M rows and N columns containing type T.
Definition types.hpp:70
double Float
Floating point number.
Definition types.hpp:47
Eigen::Matrix< T, N, 1 > EigColVecN
Fixed-size column vector of size N containing type T.
Definition types.hpp:86
Eigen::Matrix< T, N, Eigen::Dynamic > EigMatNX
Fixed-height matrix with N rows containing type T.
Definition types.hpp:78
Primary namespace for the OpenBEM library.
Definition constants.hpp:31