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 EigMatNX<Float, dim> vn0 = v_.rightCols(1) - v_.col(0);
60
61 EigRowVec<Float> x = (v10.transpose() * vn0) / v_2d.col(1)[0];
62 EigRowVec<Float> y = vn0.colwise().squaredNorm();
63
64 y.array() -= x.array() * x.array();
65 v_2d.topRightCorner(1, 1) = x;
66 v_2d.bottomRightCorner(1, 1) = Eigen::sqrt(y.array()).matrix();
67
68 return Triangle<2> (v_2d, edge_polarities_);
69};
70
71
72template <uint8_t dim>
74{
76 v_3d.topRows(dim) = v_.topRows(dim);
77 return Triangle<3> (v_3d, edge_polarities_);
78};
79
80
81template <uint8_t dim>
83{
84 EigColVecN<Float, dim> v10 = v_.col(1) - v_.col(0);
85
86 Float norm_v10 = v10.norm();
87 if (norm_v10 == 0.0)
88 throw std::domain_error("Triangle::local_coordinate_basis(): zero-length edge encountered.");
89
91
92 uvw.col(0) = v10 / norm_v10;
93
95 u_3d.topRows(dim) = uvw.col(0);
96 EigColVecN<Float, 3> nxu = normal_.cross(u_3d);
97 Float norm_nxu = nxu.norm();
98 if (norm_nxu == 0.0)
99 throw std::domain_error("Triangle::local_coordinate_basis(): zero-division encountered.");
100
101 uvw.col(1) = nxu.topRows(dim) / norm_nxu;
102 if constexpr (dim == 3)
103 uvw.col(2) = normal_;
104
105 return uvw;
106};
107
108
109template <uint8_t dim>
115 ) const
116{
118 r_diff.topRows(dim).colwise() -= v_.col(ref_idx);
119 d = normal_.transpose() * r_diff;
120 r_proj = (r - (normal_ * d)).topRows(dim);
121 // r_proj = (r_diff.topRows(dim) - (normal_ * d).topRows(dim)).colwise() + v_.col(ref_idx);
122
123 return;
124};
125
126
127template <uint8_t dim>
129{
131 v.setZero();
132 v(0, 1) = 1.0;
133 v(1, 2) = 1.0;
134 Triangle<dim> tri (v);
135 return tri;
136};
137
138
139template <uint8_t dim>
141{
142
143 EigColVecN<Float, dim> v0 = v_.col(1) - v_.col(0);
144 EigColVecN<Float, dim> v1 = v_.col(2) - v_.col(0);
145 EigMatNX<Float, dim> v2 = p.colwise() - v_.col(0);
146
147 Float d00 = v0.dot(v0);
148 Float d01 = v0.dot(v1);
149 Float d11 = v1.dot(v1);
150
151 Float denom = (d00 * d11 - d01 * d01);
152
153 if (denom == 0.0)
154 throw std::domain_error("Triangle::barycentric_coords(): divide by zero.");
155 Float inv_denom = 1.0 / denom;
156
157 EigRowVec<Float> d20 = v0.transpose() * v2;
158 EigRowVec<Float> d21 = v1.transpose() * v2;
159
161 lambda.row(1).noalias() = (d11 * d20 - d01 * d21) * inv_denom;
162 lambda.row(2).noalias() = (d00 * d21 - d01 * d20) * inv_denom;
163 lambda.row(0).noalias() = EigMatNX<Float, 1>::Ones(1, p.cols()) - lambda.row(1) - lambda.row(2);
164
165 return lambda;
166
167};
168
169
170template <uint8_t dim>
172{
173 Float tol = TRIANGLE_DEFAULT_TOL * shortest_edge_length();
174
175 auto between_0_and_1 = [&tol] (Float val) -> bool
176 {
177 if (val > tol && val - 1 < -tol)
178 return true;
179 return false;
180 };
181
182 auto is_0 = [&tol] (Float val) -> bool
183 {
184 if (std::abs(val) < tol)
185 return true;
186 return false;
187 };
188
189 auto is_1 = [&tol] (Float val) -> bool
190 {
191 if (std::abs(val - 1) < tol)
192 return true;
193 return false;
194 };
195
196 EigMatNX<Float, 3> lambda = barycentric_coords(r.topRows(dim));
198
199 for (uint32_t col = 0; col < r.cols(); ++col)
200 {
202
203 if (between_0_and_1(lambda_c[0]) &&
206 {
207 // strictly inside
208 loc[col] = 0;
209 }
210 else if ((is_0(lambda_c[0]) && is_0(lambda_c[1]) && is_1(lambda_c[2])) ||
211 (is_0(lambda_c[0]) && is_0(lambda_c[2]) && is_1(lambda_c[1])) ||
212 (is_0(lambda_c[2]) && is_0(lambda_c[1]) && is_1(lambda_c[0])))
213 {
214 // at a vertex
215 loc[col] = 1;
216 }
218 && is_0(lambda_c[2])) ||
220 && is_0(lambda_c[1])) ||
222 && is_0(lambda_c[0])))
223 {
224 // on an edge
225 loc[col] = 2;
226 }
227 else
228 {
229 // strictly outside
230 loc[col] = 3;
231 }
232 }
233
234 return loc;
235
236};
237
238
239template <uint8_t dim>
241{
242 Float abs_tol = tol * shortest_edge_length();
243
244 for (uint8_t ii = 0; ii < 3; ++ii)
245 {
246 Edge<dim> edge (v_.col(ii), v_.col((ii + 1) % 3));
247 if (edge.point_on_edge(r, tol))
248 return true;
249 }
250
252
253 p.col(0) = v_.col(0);
254 p.col(1) = v_.col(1);
255 p.col(2) = r;
257
258 if (tri1.shortest_edge_length() < abs_tol)
259 return true;
260
261 p.col(0) = v_.col(1);
262 p.col(1) = v_.col(2);
263 p.col(2) = r;
265
266 if (tri2.shortest_edge_length() < abs_tol)
267 return true;
268
269 p.col(0) = v_.col(2);
270 p.col(1) = v_.col(0);
271 p.col(2) = r;
273
274 if (tri3.shortest_edge_length() < abs_tol)
275 return true;
276
277 if (std::abs(tri1.normal().dot(tri2.normal()) - 1.0) < abs_tol &&
278 std::abs(tri2.normal().dot(tri3.normal()) - 1.0) < abs_tol)
279 return true;
280
281 return false;
282};
283
284
285template <uint8_t dim>
287{
288 Float area = 0;
289
290 if constexpr (dim == 2)
291 {
292 area = 0.5 * std::abs(v(0, 0) * (v(1, 1) - v(1, 2)) -
293 v(1, 0) * (v(0, 1) - v(0, 2)) +
294 (v(0, 1) * v(1, 2) - v(1, 1) * v(0, 2)));
295 }
296 else if constexpr (dim == 3)
297 {
298 area = ((v.col(1) - v.col(0)).cross(v.col(2) - v.col(0))).norm() / 2.0;
299 }
300
301 return area;
302};
303
304
305template <uint8_t dim>
307{
308 if constexpr (dim == 2)
309 return {0.0, 0.0, 1.0};
310 else if constexpr (dim == 3)
311 {
312 EigColVecN<Float, 3> orth = (v.col(1) - v.col(0)).cross(v.col(2) - v.col(1));
313 Float norm = orth.norm();
314 return orth / norm;
315 }
316};
317
318
319template class Triangle<2>;
320template class Triangle<3>;
321
322}
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:73
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:110
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:82
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:128
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:140
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:240
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:171
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