Geometry Nodes: Rewrite mesh delete geometry node #108435
|
@ -9,6 +9,7 @@
|
|||
#include "BLI_generic_span.hh"
|
||||
#include "BLI_generic_virtual_array.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_set.hh"
|
||||
|
||||
#include "BKE_anonymous_attribute_id.hh"
|
||||
|
@ -926,6 +927,15 @@ void gather_attributes(AttributeAccessor src_attributes,
|
|||
const IndexMask &selection,
|
||||
MutableAttributeAccessor dst_attributes);
|
||||
|
||||
void gather_attributes_group_to_group(AttributeAccessor src_attributes,
|
||||
eAttrDomain domain,
|
||||
const AnonymousAttributePropagationInfo &propagation_info,
|
||||
HooglyBoogly marked this conversation as resolved
Outdated
|
||||
const Set<std::string> &skip,
|
||||
OffsetIndices<int> src_offsets,
|
||||
OffsetIndices<int> dst_offsets,
|
||||
const IndexMask &selection,
|
||||
MutableAttributeAccessor dst_attributes);
|
||||
|
||||
void copy_attributes(const AttributeAccessor src_attributes,
|
||||
const eAttrDomain domain,
|
||||
const AnonymousAttributePropagationInfo &propagation_info,
|
||||
|
|
|
@ -1026,6 +1026,59 @@ void gather_attributes(const AttributeAccessor src_attributes,
|
|||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
|
||||
const OffsetIndices<int> dst_offsets,
|
||||
const IndexMask &selection,
|
||||
const Span<T> src,
|
||||
MutableSpan<T> dst)
|
||||
{
|
||||
selection.foreach_index(GrainSize(512), [&](const int64_t src_i, const int64_t dst_i) {
|
||||
dst.slice(dst_offsets[dst_i]).copy_from(src.slice(src_offsets[src_i]));
|
||||
});
|
||||
}
|
||||
|
||||
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
|
||||
const OffsetIndices<int> dst_offsets,
|
||||
const IndexMask &selection,
|
||||
const GSpan src,
|
||||
GMutableSpan dst)
|
||||
{
|
||||
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
gather_group_to_group(src_offsets, dst_offsets, selection, src.typed<T>(), dst.typed<T>());
|
||||
});
|
||||
}
|
||||
|
||||
void gather_attributes_group_to_group(const AttributeAccessor src_attributes,
|
||||
const eAttrDomain domain,
|
||||
const AnonymousAttributePropagationInfo &propagation_info,
|
||||
const Set<std::string> &skip,
|
||||
const OffsetIndices<int> src_offsets,
|
||||
const OffsetIndices<int> dst_offsets,
|
||||
const IndexMask &selection,
|
||||
MutableAttributeAccessor dst_attributes)
|
||||
{
|
||||
const int src_size = src_attributes.domain_size(domain);
|
||||
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
if (meta_data.domain != domain) {
|
||||
return true;
|
||||
}
|
||||
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
||||
return true;
|
||||
}
|
||||
if (skip.contains(id.name())) {
|
||||
return true;
|
||||
}
|
||||
const GVArraySpan src = *src_attributes.lookup(id, domain);
|
||||
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
id, domain, meta_data.data_type);
|
||||
gather_group_to_group(src_offsets, dst_offsets, selection, src, dst.span);
|
||||
dst.finish();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void copy_attributes(const AttributeAccessor src_attributes,
|
||||
const eAttrDomain domain,
|
||||
const AnonymousAttributePropagationInfo &propagation_info,
|
||||
|
|
|
@ -1174,62 +1174,28 @@ void CurvesGeometry::remove_points(const IndexMask &points_to_delete,
|
|||
*this = curves_copy_point_selection(*this, points_to_copy, propagation_info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
|
||||
const OffsetIndices<int> dst_offsets,
|
||||
const IndexMask &selection,
|
||||
const Span<T> src,
|
||||
MutableSpan<T> dst)
|
||||
{
|
||||
selection.foreach_index(GrainSize(256), [&](const int64_t src_i, const int64_t dst_i) {
|
||||
dst.slice(dst_offsets[dst_i]).copy_from(src.slice(src_offsets[src_i]));
|
||||
});
|
||||
}
|
||||
|
||||
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
|
||||
const OffsetIndices<int> dst_offsets,
|
||||
const IndexMask &selection,
|
||||
const GSpan src,
|
||||
GMutableSpan dst)
|
||||
{
|
||||
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
gather_group_to_group(src_offsets, dst_offsets, selection, src.typed<T>(), dst.typed<T>());
|
||||
});
|
||||
}
|
||||
|
||||
CurvesGeometry curves_copy_curve_selection(
|
||||
const CurvesGeometry &curves,
|
||||
const IndexMask &curves_to_copy,
|
||||
const AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
CurvesGeometry dst_curves(0, curves_to_copy.size());
|
||||
MutableSpan<int> new_curve_offsets = dst_curves.offsets_for_write();
|
||||
offset_indices::gather_group_sizes(
|
||||
curves.points_by_curve(), curves_to_copy, new_curve_offsets.drop_back(1));
|
||||
offset_indices::accumulate_counts_to_offsets(new_curve_offsets);
|
||||
dst_curves.resize(new_curve_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
const OffsetIndices src_points_by_curve = curves.points_by_curve();
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
const OffsetIndices dst_points_by_curve = offset_indices::gather_selected_offsets(
|
||||
points_by_curve, curves_to_copy, dst_curves.offsets_for_write());
|
||||
dst_curves.resize(dst_points_by_curve.total_size(), dst_curves.curves_num());
|
||||
|
||||
const AttributeAccessor src_attributes = curves.attributes();
|
||||
MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
|
||||
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_POINT) {
|
||||
return true;
|
||||
}
|
||||
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
||||
return true;
|
||||
}
|
||||
const GVArraySpan src = *src_attributes.lookup(id);
|
||||
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
id, meta_data.domain, meta_data.data_type);
|
||||
gather_group_to_group(src_points_by_curve, dst_points_by_curve, curves_to_copy, src, dst.span);
|
||||
dst.finish();
|
||||
return true;
|
||||
});
|
||||
gather_attributes_group_to_group(src_attributes,
|
||||
ATTR_DOMAIN_CURVE,
|
||||
propagation_info,
|
||||
{},
|
||||
points_by_curve,
|
||||
dst_points_by_curve,
|
||||
curves_to_copy,
|
||||
dst_attributes);
|
||||
|
||||
gather_attributes(
|
||||
src_attributes, ATTR_DOMAIN_CURVE, propagation_info, {}, curves_to_copy, dst_attributes);
|
||||
|
|
|
@ -144,6 +144,9 @@ void copy_group_sizes(OffsetIndices<int> offsets, const IndexMask &mask, Mutable
|
|||
/** Gather the number of indices in each indexed group to sizes. */
|
||||
void gather_group_sizes(OffsetIndices<int> offsets, const IndexMask &mask, MutableSpan<int> sizes);
|
||||
|
||||
OffsetIndices<int> gather_selected_offsets(OffsetIndices<int> src_offsets,
|
||||
const IndexMask &selection,
|
||||
MutableSpan<int> dst_offsets);
|
||||
HooglyBoogly marked this conversation as resolved
Outdated
Jacques Lucke
commented
Add comment. Add comment.
|
||||
/**
|
||||
* Create a map from indexed elements to the source indices, in other words from the larger array
|
||||
* to the smaller array.
|
||||
|
|
|
@ -0,0 +1,452 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_multi_value_map.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_geometry_fields.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
|
||||
#include "GEO_mesh_separate.hh"
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
static void create_reverse_map(const IndexMask &mask, MutableSpan<int> r_map)
|
||||
{
|
||||
mask.foreach_index_optimized<int>(
|
||||
GrainSize(4049), [&](const int src_i, const int dst_i) { r_map[src_i] = dst_i; });
|
||||
}
|
||||
|
||||
static void remap_verts(const OffsetIndices<int> src_polys,
|
||||
const OffsetIndices<int> dst_polys,
|
||||
const int src_verts_num,
|
||||
const IndexMask &vert_selection,
|
||||
const IndexMask &edge_selection,
|
||||
const IndexMask &poly_selection,
|
||||
const Span<int2> src_edges,
|
||||
const Span<int> src_corner_verts,
|
||||
MutableSpan<int2> dst_edges,
|
||||
MutableSpan<int> dst_corner_verts)
|
||||
{
|
||||
Array<int> map(src_verts_num);
|
||||
create_reverse_map(vert_selection, map);
|
||||
threading::parallel_invoke(
|
||||
vert_selection.size() > 1024,
|
||||
[&]() {
|
||||
poly_selection.foreach_index(
|
||||
GrainSize(512), [&](const int64_t src_i, const int64_t dst_i) {
|
||||
const IndexRange src_poly = src_polys[src_i];
|
||||
const IndexRange dst_poly = dst_polys[dst_i];
|
||||
for (const int i : src_poly.index_range()) {
|
||||
dst_corner_verts[dst_poly[i]] = map[src_corner_verts[src_poly[i]]];
|
||||
}
|
||||
});
|
||||
},
|
||||
[&]() {
|
||||
edge_selection.foreach_index(GrainSize(512),
|
||||
[&](const int64_t src_i, const int64_t dst_i) {
|
||||
dst_edges[dst_i][0] = map[src_edges[src_i][0]];
|
||||
dst_edges[dst_i][1] = map[src_edges[src_i][1]];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static void remap_edges(const OffsetIndices<int> src_polys,
|
||||
const OffsetIndices<int> dst_polys,
|
||||
const int src_edges_num,
|
||||
const IndexMask &edge_selection,
|
||||
const IndexMask &poly_selection,
|
||||
const Span<int> src_corner_edges,
|
||||
MutableSpan<int> dst_corner_edges)
|
||||
{
|
||||
Array<int> map(src_edges_num);
|
||||
create_reverse_map(edge_selection, map);
|
||||
poly_selection.foreach_index(GrainSize(512), [&](const int64_t src_i, const int64_t dst_i) {
|
||||
const IndexRange src_poly = src_polys[src_i];
|
||||
const IndexRange dst_poly = dst_polys[dst_i];
|
||||
for (const int i : src_poly.index_range()) {
|
||||
dst_corner_edges[dst_poly[i]] = map[src_corner_edges[src_poly[i]]];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** A vertex is selected if it's used by a selected edge. */
|
||||
static IndexMask vert_selection_from_edge(const Span<int2> edges,
|
||||
const IndexMask &edge_selection,
|
||||
const int verts_num,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
Array<bool> span(verts_num, false);
|
||||
edge_selection.foreach_index_optimized<int>([&](const int i) {
|
||||
span[edges[i][0]] = true;
|
||||
span[edges[i][1]] = true;
|
||||
});
|
||||
return IndexMask::from_bools(span, memory);
|
||||
}
|
||||
|
||||
static IndexMask poly_selection_from_mapped_corner(const OffsetIndices<int> polys,
|
||||
const Span<int> corner_verts_or_edges,
|
||||
const IndexMask &vert_or_edge_selection,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
// TODO: To bits first?
|
||||
return IndexMask::from_predicate(
|
||||
polys.index_range(), GrainSize(1024), memory, [&](const int64_t i) {
|
||||
const Span<int> poly = corner_verts_or_edges.slice(polys[i]);
|
||||
return std::all_of(poly.begin(), poly.end(), [&](const int edge) {
|
||||
return vert_or_edge_selection.contains(edge);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** A face is selected if all of its vertices are selected. */
|
||||
static IndexMask poly_selection_from_vert(const OffsetIndices<int> polys,
|
||||
const Span<int> corner_verts,
|
||||
const IndexMask &vert_selection,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
return poly_selection_from_mapped_corner(polys, corner_verts, vert_selection, memory);
|
||||
}
|
||||
|
||||
/** A face is selected if all of its edges are selected. */
|
||||
static IndexMask poly_selection_from_edge(const OffsetIndices<int> polys,
|
||||
const Span<int> corner_edges,
|
||||
const IndexMask &edge_selection,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
return poly_selection_from_mapped_corner(polys, corner_edges, edge_selection, memory);
|
||||
}
|
||||
|
||||
static IndexMask mapped_corner_selection_from_poly(const OffsetIndices<int> polys,
|
||||
const IndexMask &poly_selection,
|
||||
const Span<int> corner_verts_or_edges,
|
||||
const int verts_or_edges_num,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
Array<bool> array(verts_or_edges_num);
|
||||
poly_selection.foreach_index(GrainSize(512), [&](const int64_t i) {
|
||||
const Span<int> poly_edges = corner_verts_or_edges.slice(polys[i]);
|
||||
array.as_mutable_span().fill_indices(poly_edges, true);
|
||||
});
|
||||
return IndexMask::from_bools(array, memory);
|
||||
}
|
||||
|
||||
/** A vertex is selected if it is used by a selected face. */
|
||||
static IndexMask vert_selection_from_poly(const OffsetIndices<int> polys,
|
||||
const IndexMask &poly_selection,
|
||||
const Span<int> corner_verts,
|
||||
const int verts_num,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
return mapped_corner_selection_from_poly(polys, poly_selection, corner_verts, verts_num, memory);
|
||||
}
|
||||
|
||||
/** An edge is selected if it is used by a selected face. */
|
||||
static IndexMask edge_selection_from_poly(const OffsetIndices<int> polys,
|
||||
const IndexMask &poly_selection,
|
||||
const Span<int> corner_edges,
|
||||
const int edges_num,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
return mapped_corner_selection_from_poly(polys, poly_selection, corner_edges, edges_num, memory);
|
||||
}
|
||||
|
||||
Mesh *mesh_copy_selection(const Mesh &src_mesh,
|
||||
const fn::Field<bool> &selection,
|
||||
const eAttrDomain selection_domain,
|
||||
const bke::AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
const Span<int2> src_edges = src_mesh.edges();
|
||||
const OffsetIndices src_polys = src_mesh.polys();
|
||||
const Span<int> src_corner_verts = src_mesh.corner_verts();
|
||||
const Span<int> src_corner_edges = src_mesh.corner_edges();
|
||||
|
||||
// TODO: Local
|
||||
IndexMaskMemory memory;
|
||||
IndexMask vert_selection;
|
||||
IndexMask edge_selection;
|
||||
IndexMask poly_selection;
|
||||
switch (selection_domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
const bke::MeshFieldContext context(src_mesh, ATTR_DOMAIN_POINT);
|
||||
fn::FieldEvaluator evaluator(context, src_mesh.totvert);
|
||||
evaluator.add(selection);
|
||||
evaluator.evaluate();
|
||||
vert_selection = evaluator.get_evaluated_as_mask(0);
|
||||
BitVector<> selected_verts(src_mesh.totvert);
|
||||
vert_selection.to_bits(selected_verts);
|
||||
threading::parallel_invoke(
|
||||
vert_selection.size() > 1024,
|
||||
[&]() {
|
||||
edge_selection = IndexMask::from_predicate(
|
||||
src_edges.index_range(), GrainSize(1024), memory, [&](const int64_t i) {
|
||||
const int2 edge = src_edges[i];
|
||||
return selected_verts[edge[0]] && selected_verts[edge[1]];
|
||||
});
|
||||
},
|
||||
[&]() {
|
||||
poly_selection = poly_selection_from_vert(
|
||||
src_polys, src_corner_verts, vert_selection, memory);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
const bke::MeshFieldContext context(src_mesh, ATTR_DOMAIN_EDGE);
|
||||
fn::FieldEvaluator evaluator(context, src_mesh.totedge);
|
||||
evaluator.add(selection);
|
||||
evaluator.evaluate();
|
||||
edge_selection = evaluator.get_evaluated_as_mask(0);
|
||||
threading::parallel_invoke(
|
||||
edge_selection.size() > 1024,
|
||||
[&]() {
|
||||
vert_selection = vert_selection_from_edge(
|
||||
src_edges, edge_selection, src_mesh.totvert, memory);
|
||||
},
|
||||
[&]() {
|
||||
poly_selection = poly_selection_from_edge(
|
||||
src_polys, src_corner_edges, edge_selection, memory);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
const bke::MeshFieldContext context(src_mesh, ATTR_DOMAIN_POINT);
|
||||
fn::FieldEvaluator evaluator(context, src_mesh.totpoly);
|
||||
evaluator.add(selection);
|
||||
evaluator.evaluate();
|
||||
poly_selection = evaluator.get_evaluated_as_mask(0);
|
||||
threading::parallel_invoke(
|
||||
poly_selection.size() > 1024,
|
||||
[&]() {
|
||||
vert_selection = vert_selection_from_poly(
|
||||
src_polys, poly_selection, src_corner_verts, src_mesh.totvert, memory);
|
||||
},
|
||||
[&]() {
|
||||
edge_selection = edge_selection_from_poly(
|
||||
src_polys, poly_selection, src_corner_edges, src_mesh.totedge, memory);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh *dst_mesh = BKE_mesh_new_nomain(
|
||||
vert_selection.size(), edge_selection.size(), poly_selection.size(), 0);
|
||||
BKE_mesh_copy_parameters_for_eval(dst_mesh, &src_mesh);
|
||||
|
||||
const OffsetIndices<int> dst_polys = offset_indices::gather_selected_offsets(
|
||||
src_polys, poly_selection, dst_mesh->poly_offsets_for_write());
|
||||
dst_mesh->totloop = dst_polys.total_size();
|
||||
|
||||
const bke::AttributeAccessor src_attributes = src_mesh.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
|
||||
|
||||
dst_attributes.add<int>(".corner_vert", ATTR_DOMAIN_CORNER, bke::AttributeInitConstruct());
|
||||
dst_attributes.add<int>(".corner_edge", ATTR_DOMAIN_CORNER, bke::AttributeInitConstruct());
|
||||
|
||||
threading::parallel_invoke(
|
||||
vert_selection.size() > 1024,
|
||||
[&]() {
|
||||
remap_verts(src_polys,
|
||||
dst_polys,
|
||||
src_mesh.totvert,
|
||||
vert_selection,
|
||||
edge_selection,
|
||||
poly_selection,
|
||||
src_edges,
|
||||
src_corner_verts,
|
||||
dst_mesh->edges_for_write(),
|
||||
dst_mesh->corner_verts_for_write());
|
||||
},
|
||||
[&]() {
|
||||
remap_edges(src_polys,
|
||||
dst_polys,
|
||||
src_edges.size(),
|
||||
edge_selection,
|
||||
poly_selection,
|
||||
src_corner_edges,
|
||||
dst_mesh->corner_edges_for_write());
|
||||
});
|
||||
|
||||
bke::gather_attributes(
|
||||
src_attributes, ATTR_DOMAIN_POINT, propagation_info, {}, vert_selection, dst_attributes);
|
||||
bke::gather_attributes(src_attributes,
|
||||
ATTR_DOMAIN_EDGE,
|
||||
propagation_info,
|
||||
{".edge_verts"},
|
||||
edge_selection,
|
||||
dst_attributes);
|
||||
bke::gather_attributes(
|
||||
src_attributes, ATTR_DOMAIN_FACE, propagation_info, {}, poly_selection, dst_attributes);
|
||||
bke::gather_attributes_group_to_group(src_attributes,
|
||||
ATTR_DOMAIN_CORNER,
|
||||
propagation_info,
|
||||
{".corner_edge", ".corner_vert"},
|
||||
src_polys,
|
||||
dst_polys,
|
||||
poly_selection,
|
||||
dst_attributes);
|
||||
|
||||
return dst_mesh;
|
||||
}
|
||||
|
||||
Mesh *mesh_copy_selection_keep_verts(
|
||||
const Mesh &src_mesh,
|
||||
const fn::Field<bool> &selection,
|
||||
const eAttrDomain selection_domain,
|
||||
const bke::AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
const Span<int2> src_edges = src_mesh.edges();
|
||||
const OffsetIndices src_polys = src_mesh.polys();
|
||||
const Span<int> src_corner_verts = src_mesh.corner_verts();
|
||||
const Span<int> src_corner_edges = src_mesh.corner_edges();
|
||||
|
||||
IndexMaskMemory memory;
|
||||
IndexMask edge_selection;
|
||||
IndexMask poly_selection;
|
||||
switch (selection_domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
const bke::MeshFieldContext context(src_mesh, ATTR_DOMAIN_POINT);
|
||||
fn::FieldEvaluator evaluator(context, src_mesh.totvert);
|
||||
evaluator.add(selection);
|
||||
evaluator.evaluate();
|
||||
const VArraySpan<bool> vert_selection = evaluator.get_evaluated<bool>(0);
|
||||
|
||||
// TODO: Deduplicate
|
||||
edge_selection = IndexMask::from_predicate(
|
||||
src_edges.index_range(), GrainSize(1024), memory, [&](const int64_t i) {
|
||||
const int2 edge = src_edges[i];
|
||||
return vert_selection[edge[0]] && vert_selection[edge[1]];
|
||||
});
|
||||
poly_selection = IndexMask::from_predicate(
|
||||
src_polys.index_range(), GrainSize(1024), memory, [&](const int64_t i) {
|
||||
const Span<int> poly_verts = src_corner_verts.slice(src_polys[i]);
|
||||
return std::all_of(poly_verts.begin(), poly_verts.end(), [&](const int vert) {
|
||||
return vert_selection[vert];
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
const bke::MeshFieldContext context(src_mesh, ATTR_DOMAIN_EDGE);
|
||||
fn::FieldEvaluator evaluator(context, src_mesh.totedge);
|
||||
evaluator.add(selection);
|
||||
evaluator.evaluate();
|
||||
edge_selection = evaluator.get_evaluated_as_mask(0);
|
||||
poly_selection = poly_selection_from_edge(
|
||||
src_polys, src_corner_edges, edge_selection, memory);
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
const bke::MeshFieldContext context(src_mesh, ATTR_DOMAIN_FACE);
|
||||
fn::FieldEvaluator evaluator(context, src_polys.size());
|
||||
evaluator.add(selection);
|
||||
evaluator.evaluate();
|
||||
poly_selection = evaluator.get_evaluated_as_mask(0);
|
||||
edge_selection = edge_selection_from_poly(
|
||||
src_polys, poly_selection, src_corner_edges, src_edges.size(), memory);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh *dst_mesh = BKE_mesh_new_nomain(
|
||||
src_mesh.totvert, edge_selection.size(), poly_selection.size(), 0);
|
||||
BKE_mesh_copy_parameters_for_eval(dst_mesh, &src_mesh);
|
||||
CustomData_free_layer_named(&dst_mesh->vdata, "position", 0);
|
||||
dst_mesh->totvert = src_mesh.totvert;
|
||||
|
||||
const bke::AttributeAccessor src_attributes = src_mesh.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
|
||||
|
||||
const OffsetIndices<int> dst_polys = offset_indices::gather_selected_offsets(
|
||||
src_polys, poly_selection, dst_mesh->poly_offsets_for_write());
|
||||
dst_mesh->totloop = dst_polys.total_size();
|
||||
|
||||
dst_attributes.add<int>(".corner_edge", ATTR_DOMAIN_CORNER, bke::AttributeInitConstruct());
|
||||
|
||||
remap_edges(src_polys,
|
||||
dst_polys,
|
||||
src_edges.size(),
|
||||
edge_selection,
|
||||
poly_selection,
|
||||
src_corner_edges,
|
||||
dst_mesh->corner_edges_for_write());
|
||||
|
||||
bke::copy_attributes(src_attributes, ATTR_DOMAIN_POINT, propagation_info, {}, dst_attributes);
|
||||
bke::gather_attributes(
|
||||
src_attributes, ATTR_DOMAIN_EDGE, propagation_info, {}, edge_selection, dst_attributes);
|
||||
bke::gather_attributes(
|
||||
src_attributes, ATTR_DOMAIN_FACE, propagation_info, {}, poly_selection, dst_attributes);
|
||||
bke::gather_attributes_group_to_group(src_attributes,
|
||||
ATTR_DOMAIN_CORNER,
|
||||
propagation_info,
|
||||
{".corner_edge"},
|
||||
src_polys,
|
||||
dst_polys,
|
||||
poly_selection,
|
||||
dst_attributes);
|
||||
|
||||
/* Positions are not changed by the operation, so the bounds are the same. */
|
||||
dst_mesh->runtime->bounds_cache = src_mesh.runtime->bounds_cache;
|
||||
return dst_mesh;
|
||||
}
|
||||
|
||||
Mesh *mesh_copy_selection_keep_verts_edges(
|
||||
const Mesh &mesh,
|
||||
const fn::Field<bool> &selection,
|
||||
const bke::AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
const bke::MeshFieldContext context(mesh, ATTR_DOMAIN_FACE);
|
||||
fn::FieldEvaluator evaluator(context, mesh.totpoly);
|
||||
evaluator.set_selection(selection);
|
||||
evaluator.evaluate();
|
||||
const IndexMask poly_selection = evaluator.get_evaluated_selection_as_mask();
|
||||
if (poly_selection.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (poly_selection.size() == mesh.totpoly) {
|
||||
return BKE_mesh_copy_for_eval(&mesh);
|
||||
}
|
||||
|
||||
Mesh *dst_mesh = BKE_mesh_new_nomain(0, 0, poly_selection.size(), 0);
|
||||
CustomData_free_layer_named(&dst_mesh->vdata, "position", 0);
|
||||
CustomData_free_layer_named(&dst_mesh->edata, ".edge_verts", 0);
|
||||
dst_mesh->totvert = mesh.totvert;
|
||||
dst_mesh->totedge = mesh.totedge;
|
||||
BKE_mesh_copy_parameters_for_eval(dst_mesh, &mesh);
|
||||
|
||||
const OffsetIndices src_polys = mesh.polys();
|
||||
|
||||
const OffsetIndices<int> dst_polys = offset_indices::gather_selected_offsets(
|
||||
src_polys, poly_selection, dst_mesh->poly_offsets_for_write());
|
||||
dst_mesh->totloop = dst_polys.total_size();
|
||||
|
||||
const bke::AttributeAccessor src_attributes = mesh.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
|
||||
|
||||
bke::copy_attributes(src_attributes, ATTR_DOMAIN_POINT, propagation_info, {}, dst_attributes);
|
||||
bke::copy_attributes(src_attributes, ATTR_DOMAIN_EDGE, propagation_info, {}, dst_attributes);
|
||||
bke::gather_attributes(
|
||||
src_attributes, ATTR_DOMAIN_FACE, propagation_info, {}, poly_selection, dst_attributes);
|
||||
bke::gather_attributes_group_to_group(src_attributes,
|
||||
ATTR_DOMAIN_CORNER,
|
||||
propagation_info,
|
||||
{},
|
||||
src_polys,
|
||||
dst_polys,
|
||||
poly_selection,
|
||||
dst_attributes);
|
||||
|
||||
/* Positions are not changed by the operation, so the bounds are the same. */
|
||||
dst_mesh->runtime->bounds_cache = mesh.runtime->bounds_cache;
|
||||
return dst_mesh;
|
||||
}
|
||||
|
||||
} // namespace blender::geometry
|
Loading…
Reference in New Issue
Add comment.