Visual Computing Library
Loading...
Searching...
No Matches
filter.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_ALGORITHMS_MESH_FILTER_H
24#define VCL_ALGORITHMS_MESH_FILTER_H
25
26#include <vclib/mesh/requirements.h>
27#include <vclib/misc/comparators.h>
28
29#include <set>
30
31namespace vcl {
32
33namespace detail {
34
35template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
36OutMeshType perElementMeshFilter(
37 const InMeshType& m,
38 Range auto&& elemFilterRng,
39 bool saveBirthIndicesInCustomComponent = true)
40{
41 using OutElemType = OutMeshType::template ElementType<ELEM_ID>;
42
43 std::string ccname = "birth" + elementEnumString<ELEM_ID>();
44
45 OutMeshType res;
46 res.enableSameOptionalComponentsOf(m);
47
48 // enable the custom component birth element
49 if constexpr (comp::HasCustomComponents<OutElemType>) {
50 if (saveBirthIndicesInCustomComponent) {
51 res.template addPerElementCustomComponent<ELEM_ID, uint>(ccname);
52 }
53 }
54
55 for (const auto& [birthV, filter] :
56 std::views::zip(m.template elements<ELEM_ID>(), elemFilterRng)) {
57 if (filter) {
58 uint v = res.template add<ELEM_ID>();
59 // import all the components from the input mesh
60 res.template element<ELEM_ID>(v).importFrom(birthV, false);
61 // set the birth element
62 if constexpr (comp::HasCustomComponents<OutElemType>) {
63 if (saveBirthIndicesInCustomComponent) {
64 res.template element<ELEM_ID>(v)
65 .template customComponent<uint>(ccname) =
66 m.index(birthV);
67 }
68 }
69 }
70 }
71
72 return res;
73}
74
75template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
76OutMeshType perElementMeshFilter(
77 const InMeshType& m,
78 const std::function<bool(
79 const typename InMeshType::template ElementType<ELEM_ID>&)>& elemFilter,
80 bool saveBirthIndicesInCustomComponent = true)
81{
82 auto view =
83 m.template elements<ELEM_ID>() | std::views::transform(elemFilter);
84
85 return perElementMeshFilter<OutMeshType, ELEM_ID, InMeshType>(
86 m, view, saveBirthIndicesInCustomComponent);
87}
88
89template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
90OutMeshType perElementMeshFilterWithVRefs(
91 const InMeshType& m,
92 Range auto&& elemFilterRng,
93 bool saveBirthIndicesInCustomComponent = true)
94{
95 using InVertexType = InMeshType::VertexType;
96 using OutElemType = OutMeshType::template ElementType<ELEM_ID>;
97
98 std::string ccname = "birth" + elementEnumString<ELEM_ID>();
99
100 OutMeshType res;
101 res.enableSameOptionalComponentsOf(m);
102
103 // enable the custom component birthVertex
104 if constexpr (HasPerVertexCustomComponents<OutMeshType>) {
105 if (saveBirthIndicesInCustomComponent) {
106 res.template addPerVertexCustomComponent<uint>("birthVertex");
107 }
108 }
109
110 // enable the custom component birth element
111 if constexpr (comp::HasCustomComponents<OutElemType>) {
112 if (saveBirthIndicesInCustomComponent) {
113 res.template addPerElementCustomComponent<ELEM_ID, uint>(ccname);
114 }
115 }
116
117 std::vector<uint> vertexMapping(m.vertexContainerSize(), UINT_NULL);
118
119 for (const auto& [birthF, filter] :
120 std::views::zip(m.template elements<ELEM_ID>(), elemFilterRng)) {
121 if (filter) {
122 std::vector<uint> verts(birthF.vertexNumber(), UINT_NULL);
123 uint vi = 0; // incremented with vertices of the element
124 // set all the vertex indices in the verts vector
125 // two cases here:
126 // - the ith vertex of the face has been already added, we need just
127 // to take its id in the out mesh from the vertexMapping vector
128 // - the ith vertex of the face has not been added: we need to add
129 // it and import all its components, and update the
130 // vertexMappingVector
131 for (const InVertexType* v : birthF.vertices()) {
132 // the vertex has not already added
133 if (vertexMapping[m.index(v)] == UINT_NULL) {
134 // add the vertex to the out mesh
135 uint ov = res.addVertex();
136 // import all the components from the input mesh
137 res.vertex(ov).importFrom(*v, false);
138 if constexpr (HasPerVertexCustomComponents<OutMeshType>) {
139 // set the birth vertex
140 if (saveBirthIndicesInCustomComponent) {
141 res.vertex(ov).template customComponent<uint>(
142 "birthVertex") = m.index(v);
143 }
144 }
145 vertexMapping[m.index(v)] = ov;
146 verts[vi] = ov;
147 }
148 else {
149 verts[vi] = vertexMapping[m.index(v)];
150 }
151 ++vi;
152 }
153
154 // now all the vertices of the elements are in the out mesh, we can
155 // add the actual element
156 uint f = res.template add<ELEM_ID>();
157 // import all the components from the input mesh
158 res.template element<ELEM_ID>(f).importFrom(birthF, false);
159
160 if constexpr (OutElemType::VERTEX_NUMBER < 0) {
161 res.template element<ELEM_ID>(f).resizeVertices(verts.size());
162 }
163
164 res.template element<ELEM_ID>(f).setVertices(verts);
165
166 if constexpr (comp::HasCustomComponents<OutElemType>) {
167 // set the birth elements
168 if (saveBirthIndicesInCustomComponent) {
169 res.template element<ELEM_ID>(f)
170 .template customComponent<uint>(ccname) =
171 m.index(birthF);
172 }
173 }
174 }
175 }
176 return res;
177}
178
179template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
180OutMeshType perElementMeshFilterWithVRefs(
181 const InMeshType& m,
182 const std::function<bool(
183 const typename InMeshType::template ElementType<ELEM_ID>&)>& elemFilter,
184 bool saveBirthIndicesInCustomComponent = true)
185{
186 auto view =
187 m.template elements<ELEM_ID>() | std::views::transform(elemFilter);
188
189 return perElementMeshFilterWithVRefs<OutMeshType, ELEM_ID, InMeshType>(
190 m, view, saveBirthIndicesInCustomComponent);
191}
192
193} // namespace detail
194
222template<MeshConcept InMeshType, MeshConcept OutMeshType = InMeshType>
223OutMeshType perVertexMeshFilter(
224 const InMeshType& m,
225 const std::function<bool(const typename InMeshType::VertexType&)>&
226 vertexFilter,
227 bool saveBirthIndicesInCustomComponent = true)
228{
229 return detail::
230 perElementMeshFilter<OutMeshType, ElemId::VERTEX, InMeshType>(
231 m, vertexFilter, saveBirthIndicesInCustomComponent);
232}
233
262template<MeshConcept InMeshType, MeshConcept OutMeshType = InMeshType>
263OutMeshType perVertexMeshFilter(
264 const InMeshType& m,
265 Range auto&& vertexFilterRng,
266 bool saveBirthIndicesInCustomComponent = true)
267{
268 return detail::
269 perElementMeshFilter<OutMeshType, ElemId::VERTEX, InMeshType>(
270 m, vertexFilterRng, saveBirthIndicesInCustomComponent);
271}
272
298template<MeshConcept InMeshType, MeshConcept OutMeshType = InMeshType>
299OutMeshType perVertexSelectionMeshFilter(
300 const InMeshType& m,
301 bool saveBirthIndicesInCustomComponent = true)
302{
303 auto selView = m.vertices() | views::selection;
304
305 return detail::
306 perElementMeshFilter<OutMeshType, ElemId::VERTEX, InMeshType>(
307 m, selView, saveBirthIndicesInCustomComponent);
308}
309
340template<FaceMeshConcept InMeshType, FaceMeshConcept OutMeshType = InMeshType>
341OutMeshType perFaceMeshFilter(
342 const InMeshType& m,
343 const std::function<bool(const typename InMeshType::FaceType&)>& faceFilter,
344 bool saveBirthIndicesInCustomComponent = true)
345{
346 return detail::
347 perElementMeshFilterWithVRefs<OutMeshType, ElemId::FACE, InMeshType>(
348 m, faceFilter, saveBirthIndicesInCustomComponent);
349}
350
381template<FaceMeshConcept InMeshType, FaceMeshConcept OutMeshType = InMeshType>
382OutMeshType perFaceMeshFilter(
383 const InMeshType& m,
384 Range auto&& faceFilterRng,
385 bool saveBirthIndicesInCustomComponent = true)
386{
387 return detail::
388 perElementMeshFilterWithVRefs<OutMeshType, ElemId::FACE, InMeshType>(
389 m, faceFilterRng, saveBirthIndicesInCustomComponent);
390}
391
419template<FaceMeshConcept InMeshType, FaceMeshConcept OutMeshType = InMeshType>
420OutMeshType perFaceSelectionMeshFilter(
421 const InMeshType& m,
422 bool saveBirthIndicesInCustomComponent = true)
423{
424 auto selView = m.faces() | views::selection;
425
426 return detail::
427 perElementMeshFilterWithVRefs<OutMeshType, ElemId::FACE, InMeshType>(
428 m, selView, saveBirthIndicesInCustomComponent);
429}
430
461template<EdgeMeshConcept InMeshType, EdgeMeshConcept OutMeshType = InMeshType>
462OutMeshType perEdgeMeshFilter(
463 const InMeshType& m,
464 const std::function<bool(const typename InMeshType::EdgeType&)>& edgeFilter,
465 bool saveBirthIndicesInCustomComponent = true)
466{
467 return detail::
468 perElementMeshFilterWithVRefs<OutMeshType, ElemId::EDGE, InMeshType>(
469 m, edgeFilter, saveBirthIndicesInCustomComponent);
470}
471
502template<EdgeMeshConcept InMeshType, EdgeMeshConcept OutMeshType = InMeshType>
503OutMeshType perEdgeMeshFilter(
504 const InMeshType& m,
505 Range auto&& edgeFilterRng,
506 bool saveBirthIndicesInCustomComponent = true)
507{
508 return detail::
509 perElementMeshFilterWithVRefs<OutMeshType, ElemId::EDGE, InMeshType>(
510 m, edgeFilterRng, saveBirthIndicesInCustomComponent);
511}
512
540template<EdgeMeshConcept InMeshType, EdgeMeshConcept OutMeshType = InMeshType>
541OutMeshType perEdgeSelectionMeshFilter(
542 const InMeshType& m,
543 bool saveBirthIndicesInCustomComponent = true)
544{
545 auto selView = m.edges() | views::selection;
546
547 return detail::
548 perElementMeshFilterWithVRefs<OutMeshType, ElemId::EDGE, InMeshType>(
549 m, selView, saveBirthIndicesInCustomComponent);
550}
551
580template<EdgeMeshConcept OutMeshType, FaceMeshConcept InMeshType>
581OutMeshType perFaceEdgeMeshFilter(
582 const InMeshType& m,
583 const std::function<bool(const typename InMeshType::FaceType&, uint)>&
584 faceEdgeFilter,
585 bool dontDuplicateEdges = true,
586 bool saveBirthIndicesInCustomComponent = true)
587{
588 using InVertexType = InMeshType::VertexType;
589 using OutEdgeType = OutMeshType::EdgeType;
590
591 OutMeshType res;
592 // todo: enable only per vertex same optional components of m
593 res.enableSameOptionalComponentsOf(m);
594
595 // enable the custom component birthVertex
596 if constexpr (HasPerVertexCustomComponents<OutMeshType>) {
597 if (saveBirthIndicesInCustomComponent) {
598 res.template addPerVertexCustomComponent<uint>("birthVertex");
599 }
600 }
601
602 std::vector<uint> vertexMapping(m.vertexContainerSize(), UINT_NULL);
603
604 std::set<std::pair<uint, uint>, UnorderedPairComparator<uint>>
605 unorderedEdges;
606
607 for (const auto& f : m.faces()) {
608 for (uint ei = 0; ei < f.vertexNumber(); ++ei) {
609 if (faceEdgeFilter(f, ei)) {
610 std::array<uint, 2> verts = {UINT_NULL, UINT_NULL};
611 for (uint i = 0; i < 2; ++i) {
612 const InVertexType* v = f.vertexMod(ei + i);
613 if (vertexMapping[m.index(v)] == UINT_NULL) {
614 uint ov = res.addVertex();
615 res.vertex(ov).importFrom(*v, false);
616 if constexpr (HasPerVertexCustomComponents<
617 OutMeshType>) {
618 if (saveBirthIndicesInCustomComponent) {
619 res.vertex(ov).template customComponent<uint>(
620 "birthVertex") = m.index(v);
621 }
622 }
623 vertexMapping[m.index(v)] = ov;
624 verts[i] = ov;
625 }
626 else {
627 verts[i] = vertexMapping[m.index(v)];
628 }
629 }
630
631 std::pair<uint, uint> ep {verts[0], verts[1]};
632 if (!dontDuplicateEdges || !unorderedEdges.contains(ep)) {
633 uint e = res.addEdge(verts[0], verts[1]);
634 unorderedEdges.insert(ep);
635 }
636 }
637 }
638 }
639
640 return res;
641}
642
671template<EdgeMeshConcept OutMeshType, FaceMeshConcept InMeshType>
672OutMeshType perFaceEdgeMeshFilter(
673 const InMeshType& m,
674 const std::function<bool(uint, uint)>& faceEdgeFilter,
675 bool dontDuplicateEdges = true,
676 bool saveBirthIndicesInCustomComponent = true)
677{
678 auto filter = [&](const typename InMeshType::FaceType& f, uint ei) {
679 return faceEdgeFilter(m.index(f), ei);
680 };
681
682 return perFaceEdgeMeshFilter<OutMeshType, InMeshType>(
683 m, filter, dontDuplicateEdges, saveBirthIndicesInCustomComponent);
684}
685
710template<EdgeMeshConcept OutMeshType, FaceMeshConcept InMeshType>
711OutMeshType perFaceEdgeSelectionMeshFilter(
712 const InMeshType& m,
713 bool dontDuplicateEdges = true,
714 bool saveBirthIndicesInCustomComponent = true)
715{
716 auto filter = [&](const typename InMeshType::FaceType& f, uint ei) {
717 return f.edgeSelected(ei);
718 };
719
720 return perFaceEdgeMeshFilter<OutMeshType, InMeshType>(
721 m, filter, dontDuplicateEdges, saveBirthIndicesInCustomComponent);
722}
723
724} // namespace vcl
725
726#endif // VCL_ALGORITHMS_MESH_FILTER_H
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:48
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60