18#include <lagrange/utils/warnoff.h>
19#include <tbb/blocked_range.h>
20#include <tbb/enumerable_thread_specific.h>
21#include <tbb/parallel_for.h>
22#include <lagrange/utils/warnon.h>
25#include <lagrange/legacy/inline.h>
26#include <lagrange/Mesh.h>
27#include <lagrange/MeshTrait.h>
28#include <lagrange/common.h>
29#include <lagrange/utils/tbb.h>
50template <
typename MeshType,
typename Po
int3D>
53 const Eigen::PlainObjectBase<Point3D>& n0,
54 const Eigen::PlainObjectBase<Point3D>& p0,
55 const Eigen::PlainObjectBase<Point3D>& n1,
56 const Eigen::PlainObjectBase<Point3D>& p1,
57 const Eigen::PlainObjectBase<Point3D>& n2,
58 const Eigen::PlainObjectBase<Point3D>& p2,
59 const Eigen::PlainObjectBase<Point3D>& n3,
60 const Eigen::PlainObjectBase<Point3D>& p3,
63 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input is not a mesh.");
64 using AttributeArray =
typename MeshType::AttributeArray;
65 using Scalar =
typename MeshType::Scalar;
66 using Index =
typename MeshType::Index;
68 const auto num_facets = mesh.get_num_facets();
69 const auto& vertices = mesh.get_vertices();
70 const auto& facets = mesh.get_facets();
76 Point3D q0, q1, q2, q3;
77 std::array<double, 2> r0, r1, r2;
79 tbb::enumerable_thread_specific<LocalBuffers> temp_vars;
82 auto edge_overlap_with_negative_octant = [](
const Point3D& q0,
const Point3D& q1) ->
bool {
83 Scalar t_min = 0, t_max = 1;
84 const Point3D e = q0 - q1;
86 t_max = std::min(t_max, -q1[0] / e[0]);
87 }
else if (e[0] < 0) {
88 t_min = std::max(t_min, -q1[0] / e[0]);
90 if (q1[0] >= 0)
return false;
94 t_max = std::min(t_max, -q1[1] / e[1]);
95 }
else if (e[1] < 0) {
96 t_min = std::max(t_min, -q1[1] / e[1]);
98 if (q1[1] >= 0)
return false;
102 t_max = std::min(t_max, -q1[2] / e[2]);
103 }
else if (e[2] < 0) {
104 t_min = std::max(t_min, -q1[2] / e[2]);
106 if (q1[2] >= 0)
return false;
109 return t_max >= t_min;
113 [](
const Point3D& q0,
const Point3D& q1,
const Point3D& q2) -> std::pair<Point3D, Scalar> {
115 q0[2] * (q2[1] - q1[1]) + q1[2] * (q0[1] - q2[1]) + q2[2] * (q1[1] - q0[1]),
116 q0[0] * (q2[2] - q1[2]) + q1[0] * (q0[2] - q2[2]) + q2[0] * (q1[2] - q0[2]),
117 q0[1] * (q2[0] - q1[0]) + q1[1] * (q0[0] - q2[0]) + q2[1] * (q1[0] - q0[0])};
118 const Scalar c = (n.dot(q0) + n.dot(q1) + n.dot(q2)) / 3;
123 auto orient2D_inexact = [](
const std::array<double, 2>& v0,
124 const std::array<double, 2>& v1) ->
int {
125 const auto r = v0[0] * v1[1] - v0[1] * v1[0];
127 if (r < 0)
return -1;
131 auto triangle_intersects_negative_axis = [&](
const Point3D& q0,
136 const int axis) ->
bool {
137 auto& r0 = temp_vars.local().r0;
138 auto& r1 = temp_vars.local().r1;
139 auto& r2 = temp_vars.local().r2;
141 r0[0] = q0[(axis + 1) % 3];
142 r0[1] = q0[(axis + 2) % 3];
143 r1[0] = q1[(axis + 1) % 3];
144 r1[1] = q1[(axis + 2) % 3];
145 r2[0] = q2[(axis + 1) % 3];
146 r2[1] = q2[(axis + 2) % 3];
148 auto o01 = orient2D_inexact(r0, r1);
149 auto o12 = orient2D_inexact(r1, r2);
150 auto o20 = orient2D_inexact(r2, r0);
151 if (o01 == o12 && o01 == o20) {
160 return (c < 0 && n[axis] > 0) || (c > 0 && n[axis] < 0);
169 auto triangle_intersects_negative_axes =
170 [&](
const Point3D& q0,
const Point3D& q1,
const Point3D& q2) ->
bool {
171 const auto r = compute_plane(q0, q1, q2);
172 if (triangle_intersects_negative_axis(q0, q1, q2, r.first, r.second, 0))
return true;
173 if (triangle_intersects_negative_axis(q0, q1, q2, r.first, r.second, 1))
return true;
174 if (triangle_intersects_negative_axis(q0, q1, q2, r.first, r.second, 2))
return true;
178 auto tet_overlap_with_negative_octant =
179 [&](
const Point3D& q0,
const Point3D& q1,
const Point3D& q2,
const Point3D& q3) ->
bool {
181 if ((q0.array() < 0).all())
return true;
182 if ((q1.array() < 0).all())
return true;
183 if ((q2.array() < 0).all())
return true;
184 if ((q3.array() < 0).all())
return true;
187 if (edge_overlap_with_negative_octant(q0, q1))
return true;
188 if (edge_overlap_with_negative_octant(q0, q2))
return true;
189 if (edge_overlap_with_negative_octant(q0, q3))
return true;
190 if (edge_overlap_with_negative_octant(q1, q2))
return true;
191 if (edge_overlap_with_negative_octant(q1, q3))
return true;
192 if (edge_overlap_with_negative_octant(q2, q3))
return true;
195 if (triangle_intersects_negative_axes(q0, q1, q2))
return true;
196 if (triangle_intersects_negative_axes(q1, q2, q3))
return true;
197 if (triangle_intersects_negative_axes(q2, q3, q0))
return true;
198 if (triangle_intersects_negative_axes(q3, q0, q1))
return true;
206 attr.resize(num_facets, 1);
209 std::atomic_bool r{
false};
212 tbb::blocked_range<Index>(0, num_facets),
213 [&](
const tbb::blocked_range<Index>& tbb_range) {
214 for (
auto fi = tbb_range.begin(); fi != tbb_range.end(); fi++) {
215 if (tbb_utils::is_cancelled()) break;
221 auto& v0 = temp_vars.local().v0;
222 auto& v1 = temp_vars.local().v1;
223 auto& v2 = temp_vars.local().v2;
225 auto& q0 = temp_vars.local().q0;
226 auto& q1 = temp_vars.local().q1;
227 auto& q2 = temp_vars.local().q2;
228 auto& q3 = temp_vars.local().q3;
230 v0 = vertices.row(facets(fi, 0));
231 v1 = vertices.row(facets(fi, 1));
232 v2 = vertices.row(facets(fi, 2));
234 q0 = {(v0 - p0).dot(n0), (v1 - p0).dot(n0), (v2 - p0).dot(n0)};
235 q1 = {(v0 - p1).dot(n1), (v1 - p1).dot(n1), (v2 - p1).dot(n1)};
236 q2 = {(v0 - p2).dot(n2), (v1 - p2).dot(n2), (v2 - p2).dot(n2)};
237 q3 = {(v0 - p3).dot(n3), (v1 - p3).dot(n3), (v2 - p3).dot(n3)};
239 const auto ri = !tet_overlap_with_negative_octant(q0, q1, q2, q3);
248 tbb_utils::cancel_group_execution();
256 mesh.add_facet_attribute(
"is_selected");
257 mesh.import_facet_attribute(
"is_selected", attr);
bool select_facets_in_frustum(SurfaceMesh< Scalar, Index > &mesh, const Frustum< Scalar > &frustum, const FrustumSelectionOptions &options={})
Select all facets that intersect the cone/frustrum bounded by 4 planes defined by (n_i,...
Definition: select_facets_in_frustum.cpp:31
Main namespace for Lagrange.
Definition: AABBIGL.h:30