Visual Computing Library  devel
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.h>
27
28#include <set>
29
30namespace vcl {
31
32namespace detail {
33
34template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
35OutMeshType perElementMeshFilter(
36 const InMeshType& m,
37 Range auto&& elemFilterRng,
38 bool saveBirthIndicesInCustomComponent = true)
39{
40 using OutElemType = OutMeshType::template ElementType<ELEM_ID>;
41
42 std::string ccname = "birth" + elementEnumString<ELEM_ID>();
43
44 OutMeshType res;
45 res.enableSameOptionalComponentsOf(m);
46
47 // enable the custom component birth element
48 if constexpr (comp::HasCustomComponents<OutElemType>) {
49 if (saveBirthIndicesInCustomComponent) {
50 res.template addPerElementCustomComponent<ELEM_ID, uint>(ccname);
51 }
52 }
53
54 for (const auto& [birthV, filter] :
55 std::views::zip(m.template elements<ELEM_ID>(), elemFilterRng)) {
56 if (filter) {
57 uint v = res.template add<ELEM_ID>();
58 // import all the components from the input mesh
59 res.template element<ELEM_ID>(v).importFrom(birthV, false);
60 // set the birth element
61 if constexpr (comp::HasCustomComponents<OutElemType>) {
62 if (saveBirthIndicesInCustomComponent) {
63 res.template element<ELEM_ID>(v)
64 .template customComponent<uint>(ccname) =
65 m.index(birthV);
66 }
67 }
68 }
69 }
70
71 return res;
72}
73
74template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
75OutMeshType perElementMeshFilter(
76 const InMeshType& m,
77 const std::function<bool(
78 const typename InMeshType::template ElementType<ELEM_ID>&)>& elemFilter,
79 bool saveBirthIndicesInCustomComponent = true)
80{
81 auto view =
82 m.template elements<ELEM_ID>() | std::views::transform(elemFilter);
83
84 return perElementMeshFilter<OutMeshType, ELEM_ID, InMeshType>(
85 m, view, saveBirthIndicesInCustomComponent);
86}
87
88template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
89OutMeshType perElementMeshFilterWithVRefs(
90 const InMeshType& m,
91 Range auto&& elemFilterRng,
92 bool saveBirthIndicesInCustomComponent = true)
93{
94 using InVertexType = InMeshType::VertexType;
95 using OutElemType = OutMeshType::template ElementType<ELEM_ID>;
96
97 std::string ccname = "birth" + elementEnumString<ELEM_ID>();
98
99 OutMeshType res;
100 res.enableSameOptionalComponentsOf(m);
101
102 // enable the custom component birthVertex
103 if constexpr (HasPerVertexCustomComponents<OutMeshType>) {
104 if (saveBirthIndicesInCustomComponent) {
105 res.template addPerVertexCustomComponent<uint>("birthVertex");
106 }
107 }
108
109 // enable the custom component birth element
110 if constexpr (comp::HasCustomComponents<OutElemType>) {
111 if (saveBirthIndicesInCustomComponent) {
112 res.template addPerElementCustomComponent<ELEM_ID, uint>(ccname);
113 }
114 }
115
116 std::vector<uint> vertexMapping(m.vertexContainerSize(), UINT_NULL);
117
118 for (const auto& [birthF, filter] :
119 std::views::zip(m.template elements<ELEM_ID>(), elemFilterRng)) {
120 if (filter) {
121 std::vector<uint> verts(birthF.vertexNumber(), UINT_NULL);
122 uint vi = 0; // incremented with vertices of the element
123 // set all the vertex indices in the verts vector
124 // two cases here:
125 // - the ith vertex of the face has been already added, we need just
126 // to take its id in the out mesh from the vertexMapping vector
127 // - the ith vertex of the face has not been added: we need to add
128 // it and import all its components, and update the
129 // vertexMappingVector
130 for (const InVertexType* v : birthF.vertices()) {
131 // the vertex has not already added
132 if (vertexMapping[m.index(v)] == UINT_NULL) {
133 // add the vertex to the out mesh
134 uint ov = res.addVertex();
135 // import all the components from the input mesh
136 res.vertex(ov).importFrom(*v, false);
137 if constexpr (HasPerVertexCustomComponents<OutMeshType>) {
138 // set the birth vertex
139 if (saveBirthIndicesInCustomComponent) {
140 res.vertex(ov).template customComponent<uint>(
141 "birthVertex") = m.index(v);
142 }
143 }
144 vertexMapping[m.index(v)] = ov;
145 verts[vi] = ov;
146 }
147 else {
148 verts[vi] = vertexMapping[m.index(v)];
149 }
150 ++vi;
151 }
152
153 // now all the vertices of the elements are in the out mesh, we can
154 // add the actual element
155 uint f = res.template add<ELEM_ID>();
156 // import all the components from the input mesh
157 res.template element<ELEM_ID>(f).importFrom(birthF, false);
158
159 if constexpr (OutElemType::VERTEX_NUMBER < 0) {
160 res.template element<ELEM_ID>(f).resizeVertices(verts.size());
161 }
162
163 res.template element<ELEM_ID>(f).setVertices(verts);
164
165 if constexpr (comp::HasCustomComponents<OutElemType>) {
166 // set the birth elements
167 if (saveBirthIndicesInCustomComponent) {
168 res.template element<ELEM_ID>(f)
169 .template customComponent<uint>(ccname) =
170 m.index(birthF);
171 }
172 }
173 }
174 }
175 return res;
176}
177
178template<MeshConcept OutMeshType, uint ELEM_ID, MeshConcept InMeshType>
179OutMeshType perElementMeshFilterWithVRefs(
180 const InMeshType& m,
181 const std::function<bool(
182 const typename InMeshType::template ElementType<ELEM_ID>&)>& elemFilter,
183 bool saveBirthIndicesInCustomComponent = true)
184{
185 auto view =
186 m.template elements<ELEM_ID>() | std::views::transform(elemFilter);
187
188 return perElementMeshFilterWithVRefs<OutMeshType, ELEM_ID, InMeshType>(
189 m, view, saveBirthIndicesInCustomComponent);
190}
191
192} // namespace detail
193
221template<MeshConcept InMeshType, MeshConcept OutMeshType = InMeshType>
222OutMeshType perVertexMeshFilter(
223 const InMeshType& m,
224 const std::function<bool(const typename InMeshType::VertexType&)>&
225 vertexFilter,
226 bool saveBirthIndicesInCustomComponent = true)
227{
228 return detail::
229 perElementMeshFilter<OutMeshType, ElemId::VERTEX, InMeshType>(
230 m, vertexFilter, saveBirthIndicesInCustomComponent);
231}
232
261template<MeshConcept InMeshType, MeshConcept OutMeshType = InMeshType>
262OutMeshType perVertexMeshFilter(
263 const InMeshType& m,
264 Range auto&& vertexFilterRng,
265 bool saveBirthIndicesInCustomComponent = true)
266{
267 return detail::
268 perElementMeshFilter<OutMeshType, ElemId::VERTEX, InMeshType>(
269 m, vertexFilterRng, saveBirthIndicesInCustomComponent);
270}
271
297template<MeshConcept InMeshType, MeshConcept OutMeshType = InMeshType>
298OutMeshType perVertexSelectionMeshFilter(
299 const InMeshType& m,
300 bool saveBirthIndicesInCustomComponent = true)
301{
302 auto selView = m.vertices() | views::selection;
303
304 return detail::
305 perElementMeshFilter<OutMeshType, ElemId::VERTEX, InMeshType>(
306 m, selView, saveBirthIndicesInCustomComponent);
307}
308
339template<FaceMeshConcept InMeshType, FaceMeshConcept OutMeshType = InMeshType>
340OutMeshType perFaceMeshFilter(
341 const InMeshType& m,
342 const std::function<bool(const typename InMeshType::FaceType&)>& faceFilter,
343 bool saveBirthIndicesInCustomComponent = true)
344{
345 return detail::
346 perElementMeshFilterWithVRefs<OutMeshType, ElemId::FACE, InMeshType>(
347 m, faceFilter, saveBirthIndicesInCustomComponent);
348}
349
380template<FaceMeshConcept InMeshType, FaceMeshConcept OutMeshType = InMeshType>
381OutMeshType perFaceMeshFilter(
382 const InMeshType& m,
383 Range auto&& faceFilterRng,
384 bool saveBirthIndicesInCustomComponent = true)
385{
386 return detail::
387 perElementMeshFilterWithVRefs<OutMeshType, ElemId::FACE, InMeshType>(
388 m, faceFilterRng, saveBirthIndicesInCustomComponent);
389}
390
418template<FaceMeshConcept InMeshType, FaceMeshConcept OutMeshType = InMeshType>
419OutMeshType perFaceSelectionMeshFilter(
420 const InMeshType& m,
421 bool saveBirthIndicesInCustomComponent = true)
422{
423 auto selView = m.faces() | views::selection;
424
425 return detail::
426 perElementMeshFilterWithVRefs<OutMeshType, ElemId::FACE, InMeshType>(
427 m, selView, saveBirthIndicesInCustomComponent);
428}
429
460template<EdgeMeshConcept InMeshType, EdgeMeshConcept OutMeshType = InMeshType>
461OutMeshType perEdgeMeshFilter(
462 const InMeshType& m,
463 const std::function<bool(const typename InMeshType::EdgeType&)>& edgeFilter,
464 bool saveBirthIndicesInCustomComponent = true)
465{
466 return detail::
467 perElementMeshFilterWithVRefs<OutMeshType, ElemId::EDGE, InMeshType>(
468 m, edgeFilter, saveBirthIndicesInCustomComponent);
469}
470
501template<EdgeMeshConcept InMeshType, EdgeMeshConcept OutMeshType = InMeshType>
502OutMeshType perEdgeMeshFilter(
503 const InMeshType& m,
504 Range auto&& edgeFilterRng,
505 bool saveBirthIndicesInCustomComponent = true)
506{
507 return detail::
508 perElementMeshFilterWithVRefs<OutMeshType, ElemId::EDGE, InMeshType>(
509 m, edgeFilterRng, saveBirthIndicesInCustomComponent);
510}
511
539template<EdgeMeshConcept InMeshType, EdgeMeshConcept OutMeshType = InMeshType>
540OutMeshType perEdgeSelectionMeshFilter(
541 const InMeshType& m,
542 bool saveBirthIndicesInCustomComponent = true)
543{
544 auto selView = m.edges() | views::selection;
545
546 return detail::
547 perElementMeshFilterWithVRefs<OutMeshType, ElemId::EDGE, InMeshType>(
548 m, selView, saveBirthIndicesInCustomComponent);
549}
550
579template<EdgeMeshConcept OutMeshType, FaceMeshConcept InMeshType>
580OutMeshType perFaceEdgeMeshFilter(
581 const InMeshType& m,
582 const std::function<bool(const typename InMeshType::FaceType&, uint)>&
583 faceEdgeFilter,
584 bool dontDuplicateEdges = true,
585 bool saveBirthIndicesInCustomComponent = true)
586{
587 using InVertexType = InMeshType::VertexType;
588 using OutEdgeType = OutMeshType::EdgeType;
589
590 OutMeshType res;
591 // todo: enable only per vertex same optional components of m
592 res.enableSameOptionalComponentsOf(m);
593
594 // enable the custom component birthVertex
595 if constexpr (HasPerVertexCustomComponents<OutMeshType>) {
596 if (saveBirthIndicesInCustomComponent) {
597 res.template addPerVertexCustomComponent<uint>("birthVertex");
598 }
599 }
600
601 std::vector<uint> vertexMapping(m.vertexContainerSize(), UINT_NULL);
602
603 std::set<std::pair<uint, uint>, UnorderedPairComparator<uint>>
604 unorderedEdges;
605
606 for (const auto& f : m.faces()) {
607 for (uint ei = 0; ei < f.vertexNumber(); ++ei) {
608 if (faceEdgeFilter(f, ei)) {
609 std::array<uint, 2> verts = {UINT_NULL, UINT_NULL};
610 for (uint i = 0; i < 2; ++i) {
611 const InVertexType* v = f.vertexMod(ei + i);
612 if (vertexMapping[m.index(v)] == UINT_NULL) {
613 uint ov = res.addVertex();
614 res.vertex(ov).importFrom(*v, false);
615 if constexpr (HasPerVertexCustomComponents<
616 OutMeshType>) {
617 if (saveBirthIndicesInCustomComponent) {
618 res.vertex(ov).template customComponent<uint>(
619 "birthVertex") = m.index(v);
620 }
621 }
622 vertexMapping[m.index(v)] = ov;
623 verts[i] = ov;
624 }
625 else {
626 verts[i] = vertexMapping[m.index(v)];
627 }
628 }
629
630 std::pair<uint, uint> ep {verts[0], verts[1]};
631 if (!dontDuplicateEdges || !unorderedEdges.contains(ep)) {
632 uint e = res.addEdge(verts[0], verts[1]);
633 unorderedEdges.insert(ep);
634 }
635 }
636 }
637 }
638
639 return res;
640}
641
670template<EdgeMeshConcept OutMeshType, FaceMeshConcept InMeshType>
671OutMeshType perFaceEdgeMeshFilter(
672 const InMeshType& m,
673 const std::function<bool(uint, uint)>& faceEdgeFilter,
674 bool dontDuplicateEdges = true,
675 bool saveBirthIndicesInCustomComponent = true)
676{
677 auto filter = [&](const typename InMeshType::FaceType& f, uint ei) {
678 return faceEdgeFilter(m.index(f), ei);
679 };
680
681 return perFaceEdgeMeshFilter<OutMeshType, InMeshType>(
682 m, filter, dontDuplicateEdges, saveBirthIndicesInCustomComponent);
683}
684
709template<EdgeMeshConcept OutMeshType, FaceMeshConcept InMeshType>
710OutMeshType perFaceEdgeSelectionMeshFilter(
711 const InMeshType& m,
712 bool dontDuplicateEdges = true,
713 bool saveBirthIndicesInCustomComponent = true)
714{
715 auto filter = [&](const typename InMeshType::FaceType& f, uint ei) {
716 return f.edgeSelected(ei);
717 };
718
719 return perFaceEdgeMeshFilter<OutMeshType, InMeshType>(
720 m, filter, dontDuplicateEdges, saveBirthIndicesInCustomComponent);
721}
722
723} // namespace vcl
724
725#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:84
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92