Visual Computing Library
Loading...
Searching...
No Matches
element_container.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_MESH_CONTAINERS_ELEMENT_CONTAINER_H
24#define VCL_MESH_CONTAINERS_ELEMENT_CONTAINER_H
25
26#include "custom_component_vector_handle.h"
27#include "custom_components_vector_map.h"
28#include "vertical_components_vector_tuple.h"
29
30#include <vclib/concepts/mesh/components.h>
31#include <vclib/concepts/mesh/containers.h>
32#include <vclib/concepts/mesh/elements/element.h>
33#include <vclib/io/serialization.h>
34#include <vclib/mesh/components/bases/component.h>
35#include <vclib/mesh/iterators/element_container_iterator.h>
36#include <vclib/types/view.h>
37
38#include <vector>
39
40namespace vcl::mesh {
41
43template<ElementConcept T>
44class ElementContainer : public ElementContainerTriggerer
45{
46 template<ElementConcept U>
47 friend class ElementContainer;
48
49 using ElementContainerType = ElementContainer<T>;
50
51 // filter components of elements, taking only vertical ones
52 using vComps = FilterTypesByCondition<
53 comp::IsVerticalComponentPred,
54 typename T::Components>::type;
55
56public:
57 using ElementType = T;
58 using ParentMeshType = T::ParentMeshType;
59
60protected:
61 ParentMeshType* mParentMesh = nullptr;
62
68 uint mElemNumber = 0;
69
75 std::vector<T> mElemVec;
76
82 VerticalComponentsVectorTuple<vComps> mVerticalCompVecTuple;
83
88 CustomComponentsVectorMap<comp::HasCustomComponents<T>> mCustomCompVecMap;
89
90public:
91 static const uint ELEMENT_ID = T::ELEMENT_ID;
92
96 ElementContainer() = default;
97
98protected:
99 /* Members that are directly inherited by Containers (just renaming them) */
100 using ElementIterator = ElementContainerIterator<std::vector, T>;
101 using ConstElementIterator = ConstElementContainerIterator<std::vector, T>;
102
114 const T& element(uint i) const
115 {
116 assert(i < mElemVec.size());
117 return mElemVec[i];
118 }
119
131 T& element(uint i)
132 {
133 assert(i < mElemVec.size());
134 return mElemVec[i];
135 }
136
146 uint elementNumber() const { return mElemNumber; }
147
157 uint elementContainerSize() const { return mElemVec.size(); }
158
165 uint deletedElementNumber() const
166 {
167 return elementContainerSize() - elementNumber();
168 }
169
170 uint addElement()
171 {
172 mVerticalCompVecTuple.resize(mElemVec.size() + 1);
173 if constexpr (comp::HasCustomComponents<T>)
174 mCustomCompVecMap.resize(mElemVec.size() + 1);
175
176 T* oldB = mElemVec.data();
177 mElemVec.emplace_back();
178 T* newB = mElemVec.data();
179 mElemNumber++;
180
181 mElemVec.back().setParentMesh(mParentMesh);
182 mElemVec.back().initVerticalComponents();
183
184 if (oldB != newB) {
185 setParentMeshPointers(mParentMesh);
186 mParentMesh->updateAllReferences(oldB);
187 }
188
189 return mElemVec.size() - 1;
190 }
191
200 uint addElements(uint size)
201 {
202 mVerticalCompVecTuple.resize(mElemVec.size() + size);
203 if constexpr (comp::HasCustomComponents<T>)
204 mCustomCompVecMap.resize(mElemVec.size() + size);
205
206 uint baseId = mElemVec.size();
207 T* oldB = mElemVec.data();
208 mElemVec.resize(mElemVec.size() + size);
209 T* newB = mElemVec.data();
210 mElemNumber += size;
211
212 for (uint i = baseId; i < mElemVec.size(); ++i) {
213 mElemVec[i].setParentMesh(mParentMesh);
214 mElemVec[i].initVerticalComponents();
215 }
216
217 if (oldB != newB) {
218 setParentMeshPointers(mParentMesh);
219 mParentMesh->updateAllReferences(oldB);
220 }
221
222 return baseId;
223 }
224
225 void clearElements()
226 {
227 mElemVec.clear();
228 mElemNumber = 0;
229
230 // clear vertical and custom components
231
232 mVerticalCompVecTuple.clear();
233 if constexpr (comp::HasCustomComponents<T>)
234 mCustomCompVecMap.clear();
235 }
236
265 void resizeElements(uint size)
266 {
267 if (size > mElemNumber) {
268 addElements(size - mElemNumber);
269 }
270 else if (size < mElemNumber) {
271 uint nToDelete = mElemNumber - size;
272 for (uint i = mElemVec.size() - 1; nToDelete > 0; --i) {
273 if (!mElemVec[i].deleted()) {
274 deleteElement(i);
275 }
276 }
277 }
278 }
279
280 void reserveElements(uint size)
281 {
282 T* oldB = mElemVec.data();
283 mElemVec.reserve(size);
284 T* newB = mElemVec.data();
285
286 mVerticalCompVecTuple.reserve(size);
287 if constexpr (comp::HasCustomComponents<T>)
288 mCustomCompVecMap.reserve(size);
289
290 if (oldB != newB) {
291 setParentMeshPointers(mParentMesh);
292 mParentMesh->updateAllReferences(oldB);
293 }
294 }
295
303 std::vector<uint> compactElements()
304 {
305 std::vector<uint> newIndices = elementCompactIndices();
306 if (elementNumber() != elementContainerSize()) {
307 compactVector(mElemVec, newIndices);
308
309 mVerticalCompVecTuple.compact(newIndices);
310 if constexpr (comp::HasCustomComponents<T>)
311 mCustomCompVecMap.compact(newIndices);
312
313 updateElementIndices(newIndices);
314 }
315 return newIndices;
316 }
317
333 void deleteElement(uint i)
334 {
335 assert(i < mElemVec.size());
336 mElemVec[i].deletedBit() = true;
337 --mElemNumber;
338 }
339
356 void deleteElement(const T* e) { deleteElement(index(e)); }
357
371 uint elementIndexIfCompact(uint i) const
372 {
373 assert(i < mElemVec.size());
374 if (mElemVec.size() == mElemNumber)
375 return i;
376 else {
377 uint cnt = 0;
378 for (uint ii = 0; ii < i; ii++) {
379 if (!mElemVec[ii].deleted())
380 ++cnt;
381 }
382 return cnt;
383 }
384 }
385
397 std::vector<uint> elementCompactIndices() const
398 {
399 std::vector<uint> newIndices(mElemVec.size());
400 uint k = 0;
401 for (uint i = 0; i < mElemVec.size(); ++i) {
402 if (!mElemVec[i].deleted()) {
403 newIndices[i] = k;
404 k++;
405 }
406 else {
407 newIndices[i] = UINT_NULL;
408 }
409 }
410 return newIndices;
411 }
412
427 void append(const ElementContainer<T>& other)
428 {
429 using Comps = T::Components;
430
431 uint on = other.elementNumber();
432 uint n = elementContainerSize();
433 addElements(on);
434 for (uint i = 0; i < on; ++i) {
435 // copy everything from the other elements, also the (not updated)
436 // pointers:
437 element(n + i) = other.element(i);
438 element(n + i).setParentMesh(mParentMesh);
439 }
440 // importing also optional, vertical and custom components:
441 appendVerticalComponents(other, vComps());
442 appendCustomComponents(other);
443 }
444
455 void serializeOptionalComponentsAndElementsNumber(std::ostream& out) const
456 {
457 constexpr uint N_VERT_COMPS = vComps::size();
458 std::array<bool, N_VERT_COMPS> enabledComps;
459 uint i = 0;
460
461 auto forEachVertComp = [&]<typename Comp>() {
462 enabledComps[i] =
463 mVerticalCompVecTuple.template isComponentEnabled<Comp>();
464 ++i;
465 };
466
467 ForEachType<vComps>::apply(forEachVertComp);
468
469 vcl::serialize(out, elementContainerSize());
470 vcl::serialize(out, enabledComps);
471 }
472
481 void serializeElements(std::ostream& out) const
482 {
483 for (const auto& e : mElemVec) {
484 e.serialize(out);
485 }
486 }
487
498 void deserializeOptionalComponentsAndElementsNumber(std::istream& in)
499 {
500 constexpr uint N_VERT_COMPS = vComps::size();
501 std::array<bool, N_VERT_COMPS> enabledComps;
502 uint size = 0;
503
504 vcl::deserialize(in, size);
505 vcl::deserialize(in, enabledComps);
506
507 resizeElements(size);
508
509 uint i = 0;
510 auto forEachVertComp = [&]<typename Comp>() {
511 if (enabledComps[i])
512 mVerticalCompVecTuple.template enableComponent<Comp>();
513 else
514 mVerticalCompVecTuple.template disableComponent<Comp>();
515 ++i;
516 };
517
518 ForEachType<vComps>::apply(forEachVertComp);
519 }
520
529 void deserializeElements(std::istream& in)
530 {
531 for (auto& e : mElemVec) {
532 e.deserialize(in);
533 }
534 }
535
547 ElementIterator elementBegin(bool jumpDeleted = true)
548 {
549 auto it = mElemVec.begin();
550 if (jumpDeleted) {
551 // if the user asked to jump the deleted elements, and the first
552 // element is deleted, we need to move forward until we find the
553 // first non-deleted element
554 while (it != mElemVec.end() && it->deleted()) {
555 ++it;
556 }
557 }
558 return ElementIterator(
559 it, mElemVec, jumpDeleted && mElemVec.size() != mElemNumber);
560 }
561
566 ElementIterator elementEnd()
567 {
568 return ElementIterator(mElemVec.end(), mElemVec);
569 }
570
582 ConstElementIterator elementBegin(bool jumpDeleted = true) const
583 {
584 auto it = mElemVec.begin();
585 if (jumpDeleted) {
586 // if the user asked to jump the deleted elements, and the first
587 // element is deleted, we need to move forward until we find the
588 // first non-deleted element
589 while (it != mElemVec.end() && it->deleted()) {
590 ++it;
591 }
592 }
593 return ConstElementIterator(
594 it, mElemVec, jumpDeleted && mElemVec.size() != mElemNumber);
595 }
596
601 ConstElementIterator elementEnd() const
602 {
603 return ConstElementIterator(mElemVec.end(), mElemVec);
604 }
605
628 View<ElementIterator> elements(bool jumpDeleted = true)
629 {
630 return View(
631 elementBegin(jumpDeleted && mElemVec.size() != mElemNumber),
632 elementEnd());
633 }
634
657 View<ConstElementIterator> elements(bool jumpDeleted = true) const
658 {
659 return View(
660 elementBegin(jumpDeleted && mElemVec.size() != mElemNumber),
661 elementEnd());
662 }
663
664 void enableAllOptionalComponents()
665 {
666 mVerticalCompVecTuple.enableAllOptionalComponents();
667 }
668
669 void disableAllOptionalComponents()
670 {
671 mVerticalCompVecTuple.disableAllOptionalComponents();
672 }
673
674 template<typename C>
675 bool isOptionalComponentEnabled() const
676 {
677 return mVerticalCompVecTuple.template isComponentEnabled<C>();
678 }
679
680 template<uint COMP_ID>
681 bool isOptionalComponentEnabled() const
682 {
683 return mVerticalCompVecTuple.template isComponentEnabled<COMP_ID>();
684 }
685
686 template<typename C>
687 void enableOptionalComponent()
688 {
689 mVerticalCompVecTuple.template enableComponent<C>();
690 // first call init on all the just enabled components
691 if constexpr (comp::HasInitMemberFunction<C>) {
692 for (auto& e : elements()) {
693 e.C::init();
694 }
695 }
696 // then resize the component containers with tied size to vertex number
697 if constexpr (comp::IsTiedToVertexNumber<C>) {
698 static const int N = T::VERTEX_NUMBER;
699 if constexpr (N < 0) {
700 for (auto& e : elements()) {
701 e.C::resize(e.vertexNumber());
702 }
703 }
704 }
705 }
706
707 template<uint COMP_ID>
708 void enableOptionalComponent()
709 {
710 using C = comp::ComponentOfType<COMP_ID, typename T::Components>;
711 enableOptionalComponent<C>();
712 }
713
714 template<typename C>
715 void disableOptionalComponent()
716 {
717 mVerticalCompVecTuple.template disableComponent<C>();
718 }
719
720 template<uint COMP_ID>
721 void disableOptionalComponent()
722 {
723 mVerticalCompVecTuple.template disableComponent<COMP_ID>();
724 }
725
726 // Custom Components
727
728 bool hasElemCustomComponent(const std::string& name) const
729 requires comp::HasCustomComponents<T>
730 {
731 return mCustomCompVecMap.componentExists(name);
732 }
733
734 std::vector<std::string> elemCustomComponentNames() const
735 requires comp::HasCustomComponents<T>
736 {
737 return mCustomCompVecMap.allComponentNames();
738 }
739
740 template<typename K>
741 bool isElemCustomComponentOfType(const std::string& name) const
742 requires comp::HasCustomComponents<T>
743 {
744 return mCustomCompVecMap.template isComponentOfType<K>(name);
745 }
746
747 std::type_index elemComponentType(const std::string& name) const
748 requires comp::HasCustomComponents<T>
749 {
750 return mCustomCompVecMap.componentType(name);
751 }
752
753 template<typename K>
754 std::vector<std::string> elemCustomComponentNamesOfType() const
755 requires comp::HasCustomComponents<T>
756 {
757 return mCustomCompVecMap.template allComponentNamesOfType<K>();
758 }
759
760 template<typename K>
761 void addElemCustomComponent(const std::string& name)
762 requires comp::HasCustomComponents<T>
763 {
764 mCustomCompVecMap.template addNewComponent<K>(
765 name, elementContainerSize());
766 }
767
768 void deleteElemCustomComponent(const std::string& name)
769 requires comp::HasCustomComponents<T>
770 {
771 mCustomCompVecMap.deleteComponent(name);
772 }
773
774 template<typename K>
775 CustomComponentVectorHandle<K> customComponentVectorHandle(
776 const std::string& name) requires comp::HasCustomComponents<T>
777 {
778 std::vector<std::any>& cc =
779 mCustomCompVecMap.template componentVector<K>(name);
780 CustomComponentVectorHandle<K> v(cc);
781 return v;
782 }
783
784 template<typename K>
785 ConstCustomComponentVectorHandle<K> customComponentVectorHandle(
786 const std::string& name) const requires comp::HasCustomComponents<T>
787 {
788 const std::vector<std::any>& cc =
789 mCustomCompVecMap.template componentVector<K>(name);
790 ConstCustomComponentVectorHandle<K> v(cc);
791 return cc;
792 }
793
794 uint index(const T* e) const
795 {
796 assert(
797 !mElemVec.empty() && e >= mElemVec.data() && e <= &mElemVec.back());
798 return e - mElemVec.data();
799 }
800
801 void setParentMeshPointers(void* pm)
802 {
803 mParentMesh = static_cast<ParentMeshType*>(pm);
804 for (auto& e : elements(false)) {
805 e.setParentMesh(pm);
806 }
807 }
808
809 template<typename Element>
810 void updateReferences(
811 const Element* oldBase,
812 uint firstElementToProcess = 0,
813 uint offset = 0)
814 {
815 using Comps = T::Components;
816
817 updateReferencesOnComponents(
818 oldBase, Comps(), firstElementToProcess, offset);
819 }
820
821 template<typename Element>
822 void updateReferences(const std::vector<uint>& newIndices)
823 {
824 using Comps = T::Components;
825
826 updateReferencesOnComponents<Element>(newIndices, Comps());
827 }
828
860 void updateElementIndices(const std::vector<uint>& newIndices)
861 {
862 mParentMesh->template updateAllReferences<T>(newIndices);
863 }
864
865 template<typename OtherMesh>
866 void enableOptionalComponentsOf(const OtherMesh& m)
867 {
868 if constexpr (OtherMesh::template hasContainerOf<T>()) {
869 // get the container type of the other mesh for T - used to upcast
870 // othMesh
871 using OContainer = OtherMesh::template ContainerOf<T>::type;
872
873 const OContainer& c = static_cast<const OContainer&>(m);
874
875 enableSameOptionalComponents(typename T::Components(), c);
876 }
877 }
878
879 template<typename OtherMesh>
880 void importFrom(const OtherMesh& m)
881 {
882 if constexpr (OtherMesh::template hasContainerOf<T>()) {
883 // get the container type of the other mesh for T - used to upcast
884 // othMesh
885 using Container = OtherMesh::template ContainerOf<T>::type;
886
887 const Container& c = (const Container&) m;
888
889 clearElements();
890
891 // recreate a container having the same number of elements as the
892 // other mesh. this call will also update the parentMesh pointers
893 // and sets the vertical components vectors in vcVecTuple
894 addElements(c.elementContainerSize());
895 unsigned int eid = 0;
896 for (const typename Container::ElementType& e : c.elements(false)) {
897 // import the components of the e, when they are available.
898 // note that will set also the deleted flag of e, therefore if e
899 // is deleted, then also element(eid) will be deleted.
900 element(eid).importFrom(e);
901 ++eid;
902 }
903 // set the number of elements (different from the container size)
904 mElemNumber = c.mElemNumber;
905 if constexpr (
906 comp::HasCustomComponents<T> &&
907 comp::HasCustomComponents<typename Container::ElementType>) {
908 mCustomCompVecMap = c.mCustomCompVecMap;
909 }
910 }
911 }
912
913private:
914 template<typename ElPtr, typename... Comps>
915 void updateReferencesOnComponents(
916 const ElPtr* oldBase,
917 TypeWrapper<Comps...>,
918 uint firstElementToProcess = 0,
919 uint offset = 0)
920 {
921 (updateReferencesOnComponent<Comps>(
922 oldBase, firstElementToProcess, offset),
923 ...);
924 }
925
926 template<typename ElPtr, typename... Comps>
927 void updateReferencesOnComponents(
928 const std::vector<uint>& newIndices,
929 TypeWrapper<Comps...>)
930 {
931 (updateReferencesOnComponent<Comps, ElPtr>(newIndices), ...);
932 }
933
934 /*
935 * This function is called for each component of the element.
936 *
937 * Only if a component has references of the type ElPtr, then the
938 * updateReferences on each element will be executed.
939 *
940 * firstElementToProcess and offset are used only when an append operation
941 * has been executed. In this case, the firstElementToProcess is the index
942 * of the first element that has been appended, and offset is the number of
943 * ElPtr elements that have been appended (the offset that must be added
944 * to the newBase w.r.t. the oldBase that was the other container from which
945 * the elements have been copied).
946 */
947 template<typename Comp, typename ElPtr>
948 void updateReferencesOnComponent(
949 const ElPtr* oldBase,
950 uint firstElementToProcess = 0,
951 uint offset = 0)
952 {
953 if constexpr (comp::HasReferencesOfType<Comp, ElPtr>) {
954 // lambda to avoid code duplication
955 auto loop = [&]() {
956 for (uint i = firstElementToProcess; i < elementContainerSize();
957 i++) {
958 T& e = element(i);
959 if (!e.deleted()) {
960 e.Comp::updateReferences(oldBase, offset);
961 }
962 }
963 };
964
965 if constexpr (comp::HasOptionalReferencesOfType<Comp, ElPtr>) {
966 if (isOptionalComponentEnabled<Comp>()) {
967 loop();
968 }
969 }
970 else {
971 loop();
972 }
973 }
974 }
975
976 template<typename Comp, typename ElPtr>
977 void updateReferencesOnComponent(const std::vector<uint>& newIndices)
978 {
979 if constexpr (comp::HasReferencesOfType<Comp, ElPtr>) {
980 if constexpr (comp::HasOptionalReferencesOfType<Comp, ElPtr>) {
981 if (isOptionalComponentEnabled<Comp>()) {
982 for (T& e : elements()) {
983 e.Comp::updateReferences(newIndices);
984 }
985 }
986 }
987 else {
988 for (T& e : elements()) {
989 e.Comp::updateReferences(newIndices);
990 }
991 }
992 }
993 }
994
995 template<typename... Comps>
996 void appendVerticalComponents(
997 const ElementContainer<T>& other,
998 TypeWrapper<Comps...>)
999 {
1000 (appendVerticalComponent<Comps>(other), ...);
1001 }
1002
1003 template<typename Comp>
1004 void appendVerticalComponent(const ElementContainer<T>& other)
1005 {
1006 uint on = other.elementNumber();
1007 uint n = elementContainerSize() - on;
1008
1009 if (mVerticalCompVecTuple.template isComponentEnabled<Comp>() &&
1010 other.mVerticalCompVecTuple.template isComponentEnabled<Comp>()) {
1011 auto& vc = mVerticalCompVecTuple.template vector<Comp>();
1012 const auto& ovc =
1013 other.mVerticalCompVecTuple.template vector<Comp>();
1014
1015 for (uint i = 0; i < on; ++i) {
1016 vc[n + i] = ovc[i];
1017 }
1018 }
1019 }
1020
1021 void appendCustomComponents(const ElementContainer<T>& other)
1022 {
1023 if constexpr (comp::HasCustomComponents<T>) {
1024 uint on = other.elementNumber();
1025 uint n = elementContainerSize() - on;
1026
1027 std::vector<std::string> ccNames =
1028 mCustomCompVecMap.allComponentNames();
1029
1030 for (const std::string& name : ccNames) {
1031 for (uint i = 0; i < on; ++i) {
1032 mCustomCompVecMap.importSameCustomComponentFrom(
1033 n + i, i, name, other.mCustomCompVecMap);
1034 }
1035 }
1036 }
1037 }
1038
1039 template<typename Cont2, typename... Comps>
1040 void enableSameOptionalComponents(TypeWrapper<Comps...>, const Cont2& c2)
1041 {
1042 // for each Component in Comps, will call enableSameOptionalComponent
1043 (enableSameOptionalComponent<Comps>(c2), ...);
1044 }
1045
1050 template<typename Comp, typename Cont2>
1051 void enableSameOptionalComponent(const Cont2& c2)
1052 {
1053 // if Comp is an optional component in This container
1054 if constexpr (comp::IsOptionalComponent<Comp>) {
1055 // if Comp is available in Cont2
1056 if constexpr (comp::HasComponentOfType<
1057 typename Cont2::ElementType,
1058 Comp::COMPONENT_ID>) {
1059 // if Comp is optional in Cont2
1060 if constexpr (comp::HasOptionalComponentOfType<
1061 typename Cont2::ElementType,
1062 Comp::COMPONENT_ID>) {
1063 // if Comp is enabled in Cont2, we enable it in this
1064 // container
1065 if (c2.template isOptionalComponentEnabled<
1066 Comp::COMPONENT_ID>()) {
1067 enableOptionalComponent<Comp::COMPONENT_ID>();
1068 }
1069 }
1070 // if Comp is not optional (but is available), we enable it in
1071 // this container
1072 else {
1073 enableOptionalComponent<Comp::COMPONENT_ID>();
1074 }
1075 }
1076 }
1077 }
1078};
1079
1081
1082} // namespace vcl::mesh
1083
1084#endif // VCL_MESH_CONTAINERS_ELEMENT_CONTAINER_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