Cleanup: Slightly simplify delaunay triangulation input gathering

Separate allocation of input arrays and assignment to input class.
The main purpose is to simplify #111061.
This commit is contained in:
Hans Goudey 2023-12-14 12:28:17 -05:00
parent bb2a289a9a
commit 34bf1f6c0c
3 changed files with 69 additions and 63 deletions

View File

@ -1686,7 +1686,7 @@ static void prepare_need_tri(CDT_data &cd, const IMesh &tm, int t)
cd.is_reversed.append(rev); cd.is_reversed.append(rev);
} }
static CDT_data prepare_cdt_input(const IMesh &tm, int t, const Vector<ITT_value> itts) static CDT_data prepare_cdt_input(const IMesh &tm, int t, const Span<ITT_value> itts)
{ {
CDT_data ans; CDT_data ans;
BLI_assert(tm.face(t)->plane_populated()); BLI_assert(tm.face(t)->plane_populated());
@ -1718,7 +1718,7 @@ static CDT_data prepare_cdt_input(const IMesh &tm, int t, const Vector<ITT_value
static CDT_data prepare_cdt_input_for_cluster(const IMesh &tm, static CDT_data prepare_cdt_input_for_cluster(const IMesh &tm,
const CoplanarClusterInfo &clinfo, const CoplanarClusterInfo &clinfo,
int c, int c,
const Vector<ITT_value> itts) const Span<ITT_value> itts)
{ {
CDT_data ans; CDT_data ans;
BLI_assert(c < clinfo.tot_cluster()); BLI_assert(c < clinfo.tot_cluster());
@ -2086,13 +2086,11 @@ static Array<Face *> polyfill_triangulate_poly(Face *f, IMeshArena *arena)
static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena) static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena)
{ {
int flen = f->size(); int flen = f->size();
CDT_input<mpq_class> cdt_in; Array<mpq2> in_verts(flen);
cdt_in.vert = Array<mpq2>(flen); Array<Vector<int>> faces;
cdt_in.face = Array<Vector<int>>(1); faces.first().resize(flen);
cdt_in.face[0].reserve(flen); std::iota(faces.first().begin(), faces.first().end(), 0);
for (int i : f->index_range()) {
cdt_in.face[0].append(i);
}
/* Project poly along dominant axis of normal to get 2d coords. */ /* Project poly along dominant axis of normal to get 2d coords. */
if (!f->plane_populated()) { if (!f->plane_populated()) {
f->populate_plane(false); f->populate_plane(false);
@ -2108,7 +2106,7 @@ static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena)
bool rev = rev1 ^ rev2; bool rev = rev1 ^ rev2;
for (int i = 0; i < flen; ++i) { for (int i = 0; i < flen; ++i) {
int ii = rev ? flen - i - 1 : i; int ii = rev ? flen - i - 1 : i;
mpq2 &p2d = cdt_in.vert[ii]; mpq2 &p2d = in_verts[ii];
int k = 0; int k = 0;
for (int j = 0; j < 3; ++j) { for (int j = 0; j < 3; ++j) {
if (j != axis) { if (j != axis) {
@ -2116,6 +2114,11 @@ static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena)
} }
} }
} }
CDT_input<mpq_class> cdt_in;
cdt_in.vert = std::move(in_verts);
cdt_in.face = std::move(faces);
CDT_result<mpq_class> cdt_out = delaunay_2d_calc(cdt_in, CDT_INSIDE); CDT_result<mpq_class> cdt_out = delaunay_2d_calc(cdt_in, CDT_INSIDE);
int n_tris = cdt_out.face.size(); int n_tris = cdt_out.face.size();
Array<Face *> ans(n_tris); Array<Face *> ans(n_tris);

View File

@ -24,38 +24,38 @@
namespace blender::io::obj { namespace blender::io::obj {
Vector<Vector<int>> fixup_invalid_polygon(Span<float3> vertex_coords, Vector<Vector<int>> fixup_invalid_polygon(Span<float3> vert_positions, Span<int> face_verts)
Span<int> face_vertex_indices)
{ {
using namespace blender::meshintersect; using namespace blender::meshintersect;
if (face_vertex_indices.size() < 3) { if (face_verts.size() < 3) {
return {}; return {};
} }
const float3 normal = bke::mesh::face_normal_calc(vertex_coords, face_vertex_indices); const float3 normal = bke::mesh::face_normal_calc(vert_positions, face_verts);
float axis_mat[3][3]; float axis_mat[3][3];
axis_dominant_v3_to_m3(axis_mat, normal); axis_dominant_v3_to_m3(axis_mat, normal);
/* Prepare data for CDT. */
CDT_input<double> input;
input.vert.reinitialize(face_vertex_indices.size());
input.face.reinitialize(1);
input.face[0].resize(face_vertex_indices.size());
for (int64_t i = 0; i < face_vertex_indices.size(); ++i) {
input.face[0][i] = i;
}
input.epsilon = 1.0e-6f;
input.need_ids = true;
/* Project vertices to 2D. */ /* Project vertices to 2D. */
for (size_t i = 0; i < face_vertex_indices.size(); ++i) { Array<double2> input_verts(face_verts.size());
int idx = face_vertex_indices[i]; for (const int i : face_verts.index_range()) {
BLI_assert(idx >= 0 && idx < vertex_coords.size()); int idx = face_verts[i];
float3 coord = vertex_coords[idx]; BLI_assert(idx >= 0 && idx < vert_positions.size());
float2 coord2d; float2 coord2d;
mul_v2_m3v3(coord2d, axis_mat, coord); mul_v2_m3v3(coord2d, axis_mat, vert_positions[idx]);
input.vert[i] = double2(coord2d.x, coord2d.y); input_verts[i] = double2(coord2d.x, coord2d.y);
} }
Array<Vector<int>> input_faces(1);
input_faces.first().resize(input_verts.size());
std::iota(input_faces.first().begin(), input_faces.first().end(), 0);
/* Prepare data for CDT. */
CDT_input<double> input;
input.vert = std::move(input_verts);
input.face = std::move(input_faces);
input.epsilon = 1.0e-6f;
input.need_ids = true;
CDT_result<double> res = delaunay_2d_calc(input, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES); CDT_result<double> res = delaunay_2d_calc(input, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES);
/* Emit new face information from CDT result. */ /* Emit new face information from CDT result. */
@ -77,7 +77,7 @@ Vector<Vector<int>> fixup_invalid_polygon(Span<float3> vertex_coords,
else { else {
/* Vertex corresponds to one or more of the input vertices, use it. */ /* Vertex corresponds to one or more of the input vertices, use it. */
idx = res.vert_orig[idx][0]; idx = res.vert_orig[idx][0];
BLI_assert(idx >= 0 && idx < face_vertex_indices.size()); BLI_assert(idx >= 0 && idx < face_verts.size());
face_verts.append(idx); face_verts.append(idx);
} }
} }

View File

@ -52,32 +52,39 @@ static void node_init(bNodeTree * /*tree*/, bNode *node)
node->storage = data; node->storage = data;
} }
static void fill_curve_vert_indices(const OffsetIndices<int> offsets,
MutableSpan<Vector<int>> faces)
{
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
faces[i].resize(offsets[i].size());
array_utils::fill_index_range<int>(faces[i], offsets[i].start());
}
});
}
static meshintersect::CDT_result<double> do_cdt(const bke::CurvesGeometry &curves, static meshintersect::CDT_result<double> do_cdt(const bke::CurvesGeometry &curves,
const CDT_output_type output_type) const CDT_output_type output_type)
{ {
const OffsetIndices points_by_curve = curves.evaluated_points_by_curve(); const OffsetIndices points_by_curve = curves.evaluated_points_by_curve();
const Span<float3> positions = curves.evaluated_positions(); const Span<float3> positions = curves.evaluated_positions();
Array<double2> positions_2d(positions.size());
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
positions_2d[i] = double2(positions[i].x, positions[i].y);
}
});
Array<Vector<int>> faces(curves.curves_num());
fill_curve_vert_indices(points_by_curve, faces);
meshintersect::CDT_input<double> input; meshintersect::CDT_input<double> input;
input.need_ids = false; input.need_ids = false;
input.vert.reinitialize(points_by_curve.total_size()); input.vert = std::move(positions_2d);
input.face.reinitialize(curves.curves_num()); input.face = std::move(faces);
for (const int i_curve : curves.curves_range()) { return delaunay_2d_calc(input, output_type);
const IndexRange points = points_by_curve[i_curve];
for (const int i : points) {
input.vert[i] = double2(positions[i].x, positions[i].y);
}
input.face[i_curve].resize(points.size());
MutableSpan<int> face_verts = input.face[i_curve];
for (const int i : face_verts.index_range()) {
face_verts[i] = points[i];
}
}
meshintersect::CDT_result<double> result = delaunay_2d_calc(input, output_type);
return result;
} }
static meshintersect::CDT_result<double> do_cdt_with_mask(const bke::CurvesGeometry &curves, static meshintersect::CDT_result<double> do_cdt_with_mask(const bke::CurvesGeometry &curves,
@ -87,34 +94,30 @@ static meshintersect::CDT_result<double> do_cdt_with_mask(const bke::CurvesGeome
const OffsetIndices points_by_curve = curves.evaluated_points_by_curve(); const OffsetIndices points_by_curve = curves.evaluated_points_by_curve();
const Span<float3> positions = curves.evaluated_positions(); const Span<float3> positions = curves.evaluated_positions();
int vert_len = 0;
mask.foreach_index([&](const int i) { vert_len += points_by_curve[i].size(); });
meshintersect::CDT_input<double> input;
input.need_ids = false;
input.vert.reinitialize(vert_len);
input.face.reinitialize(mask.size());
Array<int> offsets_data(mask.size() + 1); Array<int> offsets_data(mask.size() + 1);
const OffsetIndices points_by_curve_masked = offset_indices::gather_selected_offsets( const OffsetIndices points_by_curve_masked = offset_indices::gather_selected_offsets(
points_by_curve, mask, offsets_data); points_by_curve, mask, offsets_data);
Array<double2> positions_2d(points_by_curve_masked.total_size());
mask.foreach_index(GrainSize(1024), [&](const int src_curve, const int dst_curve) { mask.foreach_index(GrainSize(1024), [&](const int src_curve, const int dst_curve) {
const IndexRange src_points = points_by_curve[src_curve]; const IndexRange src_points = points_by_curve[src_curve];
const IndexRange dst_points = points_by_curve_masked[dst_curve]; const IndexRange dst_points = points_by_curve_masked[dst_curve];
for (const int i : src_points.index_range()) { for (const int i : src_points.index_range()) {
const int src = src_points[i]; const int src = src_points[i];
const int dst = dst_points[i]; const int dst = dst_points[i];
input.vert[dst] = double2(positions[src].x, positions[src].y); positions_2d[dst] = double2(positions[src].x, positions[src].y);
} }
input.face[dst_curve].resize(src_points.size());
array_utils::fill_index_range<int>(input.face[dst_curve], dst_points.start());
}); });
meshintersect::CDT_result<double> result = delaunay_2d_calc(input, output_type); Array<Vector<int>> faces(points_by_curve_masked.size());
return result; fill_curve_vert_indices(points_by_curve_masked, faces);
meshintersect::CDT_input<double> input;
input.need_ids = false;
input.vert = std::move(positions_2d);
input.face = std::move(faces);
return delaunay_2d_calc(input, output_type);
} }
static Array<meshintersect::CDT_result<double>> do_group_aware_cdt( static Array<meshintersect::CDT_result<double>> do_group_aware_cdt(