diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt index 4ccc6c0ce16..3e1da4cc469 100644 --- a/source/blender/geometry/CMakeLists.txt +++ b/source/blender/geometry/CMakeLists.txt @@ -26,6 +26,7 @@ set(SRC intern/mesh_primitive_grid.cc intern/mesh_primitive_line.cc intern/mesh_primitive_uv_sphere.cc + intern/mesh_selection.cc intern/mesh_split_edges.cc intern/mesh_to_curve_convert.cc intern/mesh_to_volume.cc @@ -52,6 +53,7 @@ set(SRC GEO_mesh_primitive_grid.hh GEO_mesh_primitive_line.hh GEO_mesh_primitive_uv_sphere.hh + GEO_mesh_selection.hh GEO_mesh_split_edges.hh GEO_mesh_to_curve.hh GEO_mesh_to_volume.hh diff --git a/source/blender/geometry/GEO_mesh_selection.hh b/source/blender/geometry/GEO_mesh_selection.hh new file mode 100644 index 00000000000..8fd75be9417 --- /dev/null +++ b/source/blender/geometry/GEO_mesh_selection.hh @@ -0,0 +1,51 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "BLI_index_mask.hh" +#include "BLI_math_vector_types.hh" +#include "BLI_offset_indices.hh" +#include "BLI_span.hh" + +namespace blender::geometry { + +/** A vertex is selected if it's used by a selected edge. */ +IndexMask vert_selection_from_edge(Span edges, + const IndexMask &edge_mask, + int verts_num, + IndexMaskMemory &memory); + +/** A vertex is selected if it is used by a selected face. */ +IndexMask vert_selection_from_face(OffsetIndices faces, + const IndexMask &face_mask, + Span corner_verts, + int verts_num, + IndexMaskMemory &memory); + +/** An edge is selected if it is used by a selected face. */ +IndexMask edge_selection_from_face(OffsetIndices faces, + const IndexMask &face_mask, + Span corner_edges, + int edges_num, + IndexMaskMemory &memory); + +/** An edge is selected if both of its vertices are selected. */ +IndexMask edge_selection_from_vert(Span edges, + Span vert_selection, + IndexMaskMemory &memory); + +/** A face is selected if all of its vertices are selected. */ +IndexMask face_selection_from_vert(OffsetIndices faces, + Span corner_verts, + Span vert_selection, + IndexMaskMemory &memory); + +/** A face is selected if all of its edges are selected. */ +IndexMask face_selection_from_edge(OffsetIndices faces, + Span corner_edges, + Span edge_mask, + IndexMaskMemory &memory); + +} // namespace blender::geometry diff --git a/source/blender/geometry/intern/mesh_copy_selection.cc b/source/blender/geometry/intern/mesh_copy_selection.cc index fd492a151f1..2ab3d79d623 100644 --- a/source/blender/geometry/intern/mesh_copy_selection.cc +++ b/source/blender/geometry/intern/mesh_copy_selection.cc @@ -13,6 +13,7 @@ #include "BKE_mesh.hh" #include "GEO_mesh_copy_selection.hh" +#include "GEO_mesh_selection.hh" namespace blender::geometry { @@ -76,97 +77,6 @@ static void remap_edges(const OffsetIndices src_faces, }); } -/** A vertex is selected if it's used by a selected edge. */ -static IndexMask vert_selection_from_edge(const Span edges, - const IndexMask &edge_mask, - const int verts_num, - IndexMaskMemory &memory) -{ - Array array(verts_num, false); - edge_mask.foreach_index_optimized(GrainSize(4096), [&](const int i) { - array[edges[i][0]] = true; - array[edges[i][1]] = true; - }); - return IndexMask::from_bools(array, memory); -} - -static IndexMask mapped_corner_selection_from_face(const OffsetIndices faces, - const IndexMask &face_mask, - const Span corner_verts_or_edges, - const int verts_or_edges_num, - IndexMaskMemory &memory) -{ - Array array(verts_or_edges_num, false); - face_mask.foreach_index(GrainSize(512), [&](const int64_t i) { - array.as_mutable_span().fill_indices(corner_verts_or_edges.slice(faces[i]), true); - }); - return IndexMask::from_bools(array, memory); -} - -/** A vertex is selected if it is used by a selected face. */ -static IndexMask vert_selection_from_face(const OffsetIndices faces, - const IndexMask &face_mask, - const Span corner_verts, - const int verts_num, - IndexMaskMemory &memory) -{ - return mapped_corner_selection_from_face(faces, face_mask, corner_verts, verts_num, memory); -} - -/** An edge is selected if it is used by a selected face. */ -static IndexMask edge_selection_from_face(const OffsetIndices faces, - const IndexMask &face_mask, - const Span corner_edges, - const int edges_num, - IndexMaskMemory &memory) -{ - return mapped_corner_selection_from_face(faces, face_mask, corner_edges, edges_num, memory); -} - -/** An edge is selected if both of its vertices are selected. */ -static IndexMask edge_selection_from_vert(const Span edges, - const Span vert_selection, - IndexMaskMemory &memory) -{ - return IndexMask::from_predicate( - edges.index_range(), GrainSize(1024), memory, [&](const int64_t i) { - const int2 edge = edges[i]; - return vert_selection[edge[0]] && vert_selection[edge[1]]; - }); -} - -static IndexMask face_selection_from_mapped_corner(const OffsetIndices faces, - const Span corner_verts_or_edges, - const Span vert_or_edge_selection, - IndexMaskMemory &memory) -{ - return IndexMask::from_predicate( - faces.index_range(), GrainSize(1024), memory, [&](const int64_t i) { - const Span indices = corner_verts_or_edges.slice(faces[i]); - return std::all_of(indices.begin(), indices.end(), [&](const int i) { - return vert_or_edge_selection[i]; - }); - }); -} - -/** A face is selected if all of its vertices are selected. */ -static IndexMask face_selection_from_vert(const OffsetIndices faces, - const Span corner_verts, - const Span vert_selection, - IndexMaskMemory &memory) -{ - return face_selection_from_mapped_corner(faces, corner_verts, vert_selection, memory); -} - -/** A face is selected if all of its edges are selected. */ -static IndexMask face_selection_from_edge(const OffsetIndices faces, - const Span corner_edges, - const Span edge_mask, - IndexMaskMemory &memory) -{ - return face_selection_from_mapped_corner(faces, corner_edges, edge_mask, memory); -} - /** Create a mesh with no built-in attributes. */ static Mesh *create_mesh_no_attributes(const Mesh ¶ms_mesh, const int verts_num, diff --git a/source/blender/geometry/intern/mesh_selection.cc b/source/blender/geometry/intern/mesh_selection.cc new file mode 100644 index 00000000000..b58b82f6a9a --- /dev/null +++ b/source/blender/geometry/intern/mesh_selection.cc @@ -0,0 +1,96 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_index_mask.hh" + +#include "BKE_mesh.hh" + +namespace blender::geometry { + +IndexMask vert_selection_from_edge(const Span edges, + const IndexMask &edge_mask, + const int verts_num, + IndexMaskMemory &memory) +{ + Array array(verts_num, false); + edge_mask.foreach_index_optimized(GrainSize(4096), [&](const int i) { + array[edges[i][0]] = true; + array[edges[i][1]] = true; + }); + return IndexMask::from_bools(array, memory); +} + +static IndexMask mapped_corner_selection_from_face(const OffsetIndices faces, + const IndexMask &face_mask, + const Span corner_verts_or_edges, + const int verts_or_edges_num, + IndexMaskMemory &memory) +{ + Array array(verts_or_edges_num, false); + face_mask.foreach_index(GrainSize(512), [&](const int64_t i) { + array.as_mutable_span().fill_indices(corner_verts_or_edges.slice(faces[i]), true); + }); + return IndexMask::from_bools(array, memory); +} + +IndexMask vert_selection_from_face(const OffsetIndices faces, + const IndexMask &face_mask, + const Span corner_verts, + const int verts_num, + IndexMaskMemory &memory) +{ + return mapped_corner_selection_from_face(faces, face_mask, corner_verts, verts_num, memory); +} + +IndexMask edge_selection_from_face(const OffsetIndices faces, + const IndexMask &face_mask, + const Span corner_edges, + const int edges_num, + IndexMaskMemory &memory) +{ + return mapped_corner_selection_from_face(faces, face_mask, corner_edges, edges_num, memory); +} + +IndexMask edge_selection_from_vert(const Span edges, + const Span vert_selection, + IndexMaskMemory &memory) +{ + return IndexMask::from_predicate( + edges.index_range(), GrainSize(1024), memory, [&](const int64_t i) { + const int2 edge = edges[i]; + return vert_selection[edge[0]] && vert_selection[edge[1]]; + }); +} + +static IndexMask face_selection_from_mapped_corner(const OffsetIndices faces, + const Span corner_verts_or_edges, + const Span vert_or_edge_selection, + IndexMaskMemory &memory) +{ + return IndexMask::from_predicate( + faces.index_range(), GrainSize(1024), memory, [&](const int64_t i) { + const Span indices = corner_verts_or_edges.slice(faces[i]); + return std::all_of(indices.begin(), indices.end(), [&](const int i) { + return vert_or_edge_selection[i]; + }); + }); +} + +IndexMask face_selection_from_vert(const OffsetIndices faces, + const Span corner_verts, + const Span vert_selection, + IndexMaskMemory &memory) +{ + return face_selection_from_mapped_corner(faces, corner_verts, vert_selection, memory); +} + +IndexMask face_selection_from_edge(const OffsetIndices faces, + const Span corner_edges, + const Span edge_mask, + IndexMaskMemory &memory) +{ + return face_selection_from_mapped_corner(faces, corner_edges, edge_mask, memory); +} + +} // namespace blender::geometry