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/Mesh.h>
26#include <lagrange/MeshTrait.h>
27#include <lagrange/common.h>
28#include <lagrange/legacy/inline.h>
29#include <lagrange/utils/tbb.h>
50template <
typename MeshType,
typename Po
int3D>
51bool select_facets_in_frustum(
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;
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>
84 auto edge_overlap_with_negative_octant = [](
const Point3D& q0,
const Point3D& q1) ->
bool {
85 Scalar t_min = 0, t_max = 1;
86 const Point3D e = q0 - q1;
88 t_max = std::min(t_max, -q1[0] / e[0]);
89 }
else if (e[0] < 0) {
90 t_min = std::max(t_min, -q1[0] / e[0]);
92 if (q1[0] >= 0)
return false;
96 t_max = std::min(t_max, -q1[1] / e[1]);
97 }
else if (e[1] < 0) {
98 t_min = std::max(t_min, -q1[1] / e[1]);
100 if (q1[1] >= 0)
return false;
104 t_max = std::min(t_max, -q1[2] / e[2]);
105 }
else if (e[2] < 0) {
106 t_min = std::max(t_min, -q1[2] / e[2]);
108 if (q1[2] >= 0)
return false;
111 return t_max >= t_min;
115 [](
const Point3D& q0,
const Point3D& q1,
const Point3D& q2) -> std::pair<Point3D, Scalar> {
117 q0[2] * (q2[1] - q1[1]) + q1[2] * (q0[1] - q2[1]) + q2[2] * (q1[1] - q0[1]),
118 q0[0] * (q2[2] - q1[2]) + q1[0] * (q0[2] - q2[2]) + q2[0] * (q1[2] - q0[2]),
119 q0[1] * (q2[0] - q1[0]) + q1[1] * (q0[0] - q2[0]) + q2[1] * (q1[0] - q0[0])};
120 const Scalar c = (n.dot(q0) + n.dot(q1) + n.dot(q2)) / 3;
125 auto orient2D_inexact = [](
const std::array<double, 2>& v0,
126 const std::array<double, 2>& v1) ->
int {
127 const auto r = v0[0] * v1[1] - v0[1] * v1[0];
129 if (r < 0)
return -1;
133 auto triangle_intersects_negative_axis = [&](
const Point3D& q0,
138 const int axis) ->
bool {
139 auto& r0 = temp_vars.local().r0;
140 auto& r1 = temp_vars.local().r1;
141 auto& r2 = temp_vars.local().r2;
143 r0[0] = q0[(axis + 1) % 3];
144 r0[1] = q0[(axis + 2) % 3];
145 r1[0] = q1[(axis + 1) % 3];
146 r1[1] = q1[(axis + 2) % 3];
147 r2[0] = q2[(axis + 1) % 3];
148 r2[1] = q2[(axis + 2) % 3];
150 auto o01 = orient2D_inexact(r0, r1);
151 auto o12 = orient2D_inexact(r1, r2);
152 auto o20 = orient2D_inexact(r2, r0);
153 if (o01 == o12 && o01 == o20) {
162 return (c < 0 && n[axis] > 0) || (c > 0 && n[axis] < 0);
171 auto triangle_intersects_negative_axes =
172 [&](
const Point3D& q0,
const Point3D& q1,
const Point3D& q2) ->
bool {
173 const auto r = compute_plane(q0, q1, q2);
174 if (triangle_intersects_negative_axis(q0, q1, q2, r.first, r.second, 0))
return true;
175 if (triangle_intersects_negative_axis(q0, q1, q2, r.first, r.second, 1))
return true;
176 if (triangle_intersects_negative_axis(q0, q1, q2, r.first, r.second, 2))
return true;
180 auto tet_overlap_with_negative_octant =
181 [&](
const Point3D& q0,
const Point3D& q1,
const Point3D& q2,
const Point3D& q3) ->
bool {
183 if ((q0.array() < 0).all())
return true;
184 if ((q1.array() < 0).all())
return true;
185 if ((q2.array() < 0).all())
return true;
186 if ((q3.array() < 0).all())
return true;
189 if (edge_overlap_with_negative_octant(q0, q1))
return true;
190 if (edge_overlap_with_negative_octant(q0, q2))
return true;
191 if (edge_overlap_with_negative_octant(q0, q3))
return true;
192 if (edge_overlap_with_negative_octant(q1, q2))
return true;
193 if (edge_overlap_with_negative_octant(q1, q3))
return true;
194 if (edge_overlap_with_negative_octant(q2, q3))
return true;
197 if (triangle_intersects_negative_axes(q0, q1, q2))
return true;
198 if (triangle_intersects_negative_axes(q1, q2, q3))
return true;
199 if (triangle_intersects_negative_axes(q2, q3, q0))
return true;
200 if (triangle_intersects_negative_axes(q3, q0, q1))
return true;
208 attr.resize(num_facets, 1);
211 std::atomic_bool r{
false};
214 tbb::blocked_range<Index>(0, num_facets),
215 [&](
const tbb::blocked_range<Index>& tbb_range) {
216 for (
auto fi = tbb_range.begin(); fi != tbb_range.end(); fi++) {
217 if (tbb_utils::is_cancelled())
break;
223 auto& v0 = temp_vars.local().v0;
224 auto& v1 = temp_vars.local().v1;
225 auto& v2 = temp_vars.local().v2;
227 auto& q0 = temp_vars.local().q0;
228 auto& q1 = temp_vars.local().q1;
229 auto& q2 = temp_vars.local().q2;
230 auto& q3 = temp_vars.local().q3;
232 v0 = vertices.row(facets(fi, 0));
233 v1 = vertices.row(facets(fi, 1));
234 v2 = vertices.row(facets(fi, 2));
236 q0 = {(v0 - p0).dot(n0), (v1 - p0).dot(n0), (v2 - p0).dot(n0)};
237 q1 = {(v0 - p1).dot(n1), (v1 - p1).dot(n1), (v2 - p1).dot(n1)};
238 q2 = {(v0 - p2).dot(n2), (v1 - p2).dot(n2), (v2 - p2).dot(n2)};
239 q3 = {(v0 - p3).dot(n3), (v1 - p3).dot(n3), (v2 - p3).dot(n3)};
241 const auto ri = !tet_overlap_with_negative_octant(q0, q1, q2, q3);
250 tbb_utils::cancel_group_execution();
257 mesh.add_facet_attribute(
"is_selected");
258 mesh.import_facet_attribute(
"is_selected", attr);
Index get_num_facets() const
Retrieves the number of facets.
Definition SurfaceMesh.h:678
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
Main namespace for Lagrange.