14#include <unordered_map>
16#include <lagrange/common.h>
17#include <lagrange/compute_facet_area.h>
18#include <lagrange/utils/assert.h>
19#include <lagrange/utils/range.h>
34template <
typename MeshType>
38 using Index =
typename MeshType::Index;
39 using IndexList =
typename MeshType::IndexList;
40 using VertexArray =
typename MeshType::VertexArray;
42 using BarycentricArray = Eigen::Matrix<
43 typename VertexArray::Scalar,
44 VertexArray::RowsAtCompileTime,
46 VertexArray::Options>;
49 Index num_samples = 0;
51 IndexList facet_ids = IndexList(0);
53 VertexArray positions = VertexArray();
55 BarycentricArray barycentrics = BarycentricArray();
68template <
typename MeshType>
71 const typename MeshType::Index approx_num_points,
72 const typename MeshType::IndexList& active_facets)
75 using Index =
typename MeshType::Index;
76 using Scalar =
typename MeshType::Scalar;
77 using VertexType =
typename MeshType::VertexType;
81 using RowVectorS = Eigen::Matrix<Scalar, 1, Eigen::Dynamic>;
82 using RowVector3S = Eigen::Matrix<Scalar, 1, 3>;
83 using RowVectorI = Eigen::Matrix<Index, 1, Eigen::Dynamic>;
84 using BoundingBox = Eigen::AlignedBox<Scalar, Eigen::Dynamic>;
87 la_runtime_assert(mesh.get_vertex_per_facet() == 3,
"only works for triangle meshes");
89 la_runtime_assert(active_facets.size() <= safe_cast<size_t>(mesh.get_num_facets()));
90 for (
const auto facet_id : active_facets) {
96 if (!mesh.has_facet_attribute(
"area")) {
99 const auto& facet_area = mesh.get_facet_attribute(
"area");
100 const auto& facets = mesh.get_facets();
101 const auto& vertices = mesh.get_vertices();
104 const Index n_dims = mesh.get_dim();
109 Scalar total_mesh_area = 0;
110 for (
auto facet_id :
range_sparse(mesh.get_num_facets(), active_facets)) {
111 total_mesh_area += facet_area(facet_id);
121 const Scalar sampling_length = 1.5 * sqrt((total_mesh_area / (approx_num_points * M_PI)));
124 BoundingBox bounding_box(n_dims);
125 for (
auto facet_id :
range_sparse(mesh.get_num_facets(), active_facets)) {
126 for (
auto vertex_offset :
range(mesh.get_vertex_per_facet())) {
127 const Index vertex_id = facets(facet_id, vertex_offset);
129 bounding_box.extend(vertices.row(vertex_id).transpose());
134 const RowVectorS grid_lens = bounding_box.sizes();
135 const RowVectorI grid_dims =
136 (grid_lens / sampling_length).array().ceil().template cast<Index>();
139 const Index num_grid_cells = grid_dims.prod();
142 auto get_flattend_index = [grid_dims, n_dims](
const RowVectorI& index_nd) -> Index {
144 assert(index_nd.minCoeff() >= 0);
145 assert((index_nd.array() < grid_dims.array()).all());
147 Index answer = invalid<Index>();
150 answer = index_nd(1) * grid_dims(0) + index_nd(0);
151 }
else if (n_dims == 3) {
153 answer = index_nd(2) * grid_dims(1) * grid_dims(0) + index_nd(1) * grid_dims(0) +
155 LA_IGNORE_ARRAY_BOUNDS_END
160 assert(answer >= 0 && answer < grid_dims.prod());
169 std::unordered_set<Index> is_grid_cell_marked_backend(num_grid_cells);
172 auto is_grid_cell_marked = [&is_grid_cell_marked_backend](
const Index cell_index) {
176 return is_grid_cell_marked_backend.count(cell_index) != 0;
180 auto mark_grid_cell = [&is_grid_cell_marked_backend](
const Index cell_index) {
184 is_grid_cell_marked_backend.insert(cell_index);
190 std::list<VertexType> sample_positions;
191 std::list<Index> sample_facet_ids;
192 std::list<RowVector3S> sample_barycentrics;
193 Index num_samples = 0;
203 const Index num_triangle_cols = 3 + n_dims;
204 using Triangle = Eigen::Matrix<Scalar, 3, Eigen::Dynamic>;
205 auto get_triangle_pos = [&n_dims](
const Triangle& tri,
const Index vert_offset) -> RowVectorS {
206 return tri.row(vert_offset).head(n_dims);
208 auto get_triangle_bary = [](
const Triangle& tri,
const Index vert_offset) -> RowVectorS {
209 return tri.row(vert_offset).tail(3);
211 auto set_triangle_pos =
212 [&n_dims](Triangle& tri,
const Index vert_offset,
const RowVectorS& v) ->
void {
213 tri.row(vert_offset).head(n_dims) = v;
215 auto set_triangle_bary = [](Triangle& tri,
216 const Index vert_offset,
217 const RowVectorS& v) ->
void { tri.row(vert_offset).tail(3) = v; };
218 std::queue<Triangle> sub_triangles;
226 for (
auto facet_id :
range_sparse(mesh.get_num_facets(), active_facets)) {
234 sub_triangles = std::queue<Triangle>();
237 Triangle mother_facet = Triangle::Zero(3, num_triangle_cols);
238 set_triangle_pos(mother_facet, 0, vertices.row(facets(facet_id, 0)));
239 set_triangle_pos(mother_facet, 1, vertices.row(facets(facet_id, 1)));
240 set_triangle_pos(mother_facet, 2, vertices.row(facets(facet_id, 2)));
241 set_triangle_bary(mother_facet, 0, RowVector3S(1, 0, 0));
242 set_triangle_bary(mother_facet, 1, RowVector3S(0, 1, 0));
243 set_triangle_bary(mother_facet, 2, RowVector3S(0, 0, 1));
246 sub_triangles.push(mother_facet);
249 while (!sub_triangles.empty()) {
250 const Triangle current_facet = sub_triangles.front();
254 Scalar longest_edge_length = -std::numeric_limits<Scalar>::max();
255 Index longest_edge_offset = invalid<Index>();
256 for (
auto edge_offset :
range(3)) {
257 const auto edge_offset_p1 = (edge_offset + 1) % 3;
258 const Scalar edge_length = (get_triangle_pos(current_facet, edge_offset)
259 - get_triangle_pos(current_facet, edge_offset_p1))
261 if (edge_length > longest_edge_length) {
262 longest_edge_length = edge_length;
263 longest_edge_offset = edge_offset;
268 if (longest_edge_length > 2 * sampling_length) {
269 Triangle f1 = Triangle::Zero(3, num_triangle_cols);
270 Triangle f2 = Triangle::Zero(3, num_triangle_cols);
272 f1.row(0) = (current_facet.row(longest_edge_offset) +
273 current_facet.row((longest_edge_offset + 1) % 3)) /
275 f1.row(1) = current_facet.row(longest_edge_offset);
276 f1.row(2) = current_facet.row((longest_edge_offset + 2) % 3);
278 f2.row(0) = f1.row(0);
279 f2.row(1) = current_facet.row((longest_edge_offset + 1) % 3);
280 f2.row(2) = current_facet.row((longest_edge_offset + 2) % 3);
282 sub_triangles.push(f1);
283 sub_triangles.push(f2);
285 const RowVector3S point_barycentric =
286 (get_triangle_bary(current_facet, 0) + get_triangle_bary(current_facet, 1) +
287 get_triangle_bary(current_facet, 2)) /
289 const VertexType point_position =
290 (get_triangle_pos(current_facet, 0) + get_triangle_pos(current_facet, 1) +
291 get_triangle_pos(current_facet, 2)) /
297 const RowVectorI grid_cell =
298 ((point_position - bounding_box.min().transpose()) / sampling_length)
301 .template cast<Index>();
302 const Index grid_cell_id = get_flattend_index(grid_cell);
304 if (!is_grid_cell_marked(grid_cell_id)) {
305 mark_grid_cell(grid_cell_id);
307 sample_facet_ids.push_back(facet_id);
309 sample_barycentrics.push_back(point_barycentric);
311 sample_positions.push_back(point_position);
323 output.num_samples = num_samples;
325 output.barycentrics.resize(num_samples, 3);
326 output.facet_ids.resize(num_samples);
327 output.positions.resize(num_samples, n_dims);
329 auto it_barycentric = sample_barycentrics.begin();
330 auto it_facet_id = sample_facet_ids.begin();
331 auto it_position = sample_positions.begin();
333 for (Index i :
range(num_samples)) {
334 output.barycentrics.row(i) = *it_barycentric;
335 output.facet_ids[i] = *it_facet_id;
336 output.positions.row(i) = *it_position;
351template <
typename MeshType>
352SamplePointsOnSurfaceOutput<MeshType> sample_points_on_surface(
354 const typename MeshType::Index approx_num_points,
355 const std::vector<bool>& is_facet_active)
357 typename MeshType::IndexList active_facets;
358 for (
auto i :
range(safe_cast<typename MeshType::Index>(is_facet_active.size()))) {
359 if (is_facet_active[i]) {
360 active_facets.push_back(i);
363 return sample_points_on_surface(mesh, approx_num_points, active_facets);
370template <
typename MeshType>
371SamplePointsOnSurfaceOutput<MeshType> sample_points_on_surface(
373 const typename MeshType::Index approx_num_points)
375 return sample_points_on_surface(mesh, approx_num_points,
typename MeshType::IndexList());
AttributeId compute_facet_area(SurfaceMesh< Scalar, Index > &mesh, FacetAreaOptions options={})
Compute per-facet area.
Definition: compute_area.cpp:304
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
internal::SparseRange< Index > range_sparse(Index max, const std::vector< Index > &active)
Returns an iterable object representing a subset of the range [0, max).
Definition: range.h:217
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
#define LA_IGNORE_ARRAY_BOUNDS_BEGIN
Ignore warning "out of bounds subscripts or offsets into arrays" This is used to bypass the following...
Definition: warning.h:157
Main namespace for Lagrange.
Definition: AABBIGL.h:30
Definition: sample_points_on_surface.h:36