Visual Computing Library  devel
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_BASE_ELEMENT_CONTAINER_H
24#define VCL_MESH_CONTAINERS_BASE_ELEMENT_CONTAINER_H
25
26#include "base.h"
27#include "custom_component_vector_handle.h"
28
29#include "../detail/custom_components_vector_map.h"
30#include "../detail/vertical_components_vector_tuple.h"
31
32#include <vclib/mesh/components/base/component.h>
33#include <vclib/mesh/components/custom_components.h>
34#include <vclib/mesh/elements/base/element.h>
35#include <vclib/mesh/iterators/element_container_iterator.h>
36
37#include <vclib/base.h>
38
39#include <vector>
40
41namespace vcl::mesh {
42
44template<ElementConcept T>
45class ElementContainer : public ElementContainerTriggerer
46{
47 template<ElementConcept U>
48 friend class ElementContainer;
49
50 using ElementContainerType = ElementContainer<T>;
51
52 // filter components of elements, taking only vertical ones
53 using VertComps = FilterTypesByCondition<
54 comp::IsVerticalComponentPred,
55 typename T::Components>::type;
56
57public:
58 using ElementType = T;
59 using ParentMeshType = T::ParentMeshType;
60
61protected:
62 ParentMeshType* mParentMesh = nullptr;
63
69 uint mElemNumber = 0;
70
76 std::vector<T> mElemVec;
77
83 detail::VerticalComponentsVectorTuple<VertComps> mVerticalCompVecTuple;
84
89 detail::CustomComponentsVectorMap<comp::HasCustomComponents<T>>
90 mCustomCompVecMap;
91
92public:
93 static const uint ELEMENT_ID = T::ELEMENT_ID;
94
98 ElementContainer() = default;
99
100protected:
101 /* Members that are directly inherited by Containers (just renaming them) */
102 using ElementIterator = ElementContainerIterator<std::vector, T>;
103 using ConstElementIterator = ConstElementContainerIterator<std::vector, T>;
104
116 const T& element(uint i) const
117 {
118 assert(i < mElemVec.size());
119 return mElemVec[i];
120 }
121
133 T& element(uint i)
134 {
135 assert(i < mElemVec.size());
136 return mElemVec[i];
137 }
138
148 uint elementNumber() const { return mElemNumber; }
149
159 uint elementContainerSize() const { return mElemVec.size(); }
160
167 uint deletedElementNumber() const
168 {
169 return elementContainerSize() - elementNumber();
170 }
171
172 uint addElement()
173 {
174 mVerticalCompVecTuple.resize(mElemVec.size() + 1);
175 if constexpr (comp::HasCustomComponents<T>)
176 mCustomCompVecMap.resize(mElemVec.size() + 1);
177
178 T* oldB = mElemVec.data();
179 mElemVec.emplace_back();
180 T* newB = mElemVec.data();
181 mElemNumber++;
182
183 mElemVec.back().setParentMesh(mParentMesh);
184 mElemVec.back().initVerticalComponents();
185
186 if (oldB != newB) {
187 setParentMeshPointers(mParentMesh);
188 mParentMesh->updateAllReferences(oldB);
189 }
190
191 return mElemVec.size() - 1;
192 }
193
202 uint addElements(uint size)
203 {
204 mVerticalCompVecTuple.resize(mElemVec.size() + size);
205 if constexpr (comp::HasCustomComponents<T>)
206 mCustomCompVecMap.resize(mElemVec.size() + size);
207
208 uint baseId = mElemVec.size();
209 T* oldB = mElemVec.data();
210 mElemVec.resize(mElemVec.size() + size);
211 T* newB = mElemVec.data();
212 mElemNumber += size;
213
214 for (uint i = baseId; i < mElemVec.size(); ++i) {
215 mElemVec[i].setParentMesh(mParentMesh);
216 mElemVec[i].initVerticalComponents();
217 }
218
219 if (oldB != newB) {
220 setParentMeshPointers(mParentMesh);
221 mParentMesh->updateAllReferences(oldB);
222 }
223
224 return baseId;
225 }
226
227 void clearElements()
228 {
229 mElemVec.clear();
230 mElemNumber = 0;
231
232 // clear vertical and custom components
233
234 mVerticalCompVecTuple.clear();
235 if constexpr (comp::HasCustomComponents<T>)
236 mCustomCompVecMap.clear();
237 }
238
267 void resizeElements(uint size)
268 {
269 if (size > mElemNumber) {
270 addElements(size - mElemNumber);
271 }
272 else if (size < mElemNumber) {
273 uint nToDelete = mElemNumber - size;
274 for (uint i = mElemVec.size() - 1; nToDelete > 0; --i) {
275 if (!mElemVec[i].deleted()) {
276 deleteElement(i);
277 }
278 }
279 }
280 }
281
282 void reserveElements(uint size)
283 {
284 T* oldB = mElemVec.data();
285 mElemVec.reserve(size);
286 T* newB = mElemVec.data();
287
288 mVerticalCompVecTuple.reserve(size);
289 if constexpr (comp::HasCustomComponents<T>)
290 mCustomCompVecMap.reserve(size);
291
292 if (oldB != newB) {
293 setParentMeshPointers(mParentMesh);
294 mParentMesh->updateAllReferences(oldB);
295 }
296 }
297
305 std::vector<uint> compactElements()
306 {
307 std::vector<uint> newIndices = elementCompactIndices();
308 if (elementNumber() != elementContainerSize()) {
309 compactVector(mElemVec, newIndices);
310
311 mVerticalCompVecTuple.compact(newIndices);
312 if constexpr (comp::HasCustomComponents<T>)
313 mCustomCompVecMap.compact(newIndices);
314
315 updateElementIndices(newIndices);
316 }
317 return newIndices;
318 }
319
335 void deleteElement(uint i)
336 {
337 assert(i < mElemVec.size());
338 mElemVec[i].deletedBit() = true;
339 --mElemNumber;
340 }
341
358 void deleteElement(const T* e) { deleteElement(index(e)); }
359
373 uint elementIndexIfCompact(uint i) const
374 {
375 assert(i < mElemVec.size());
376 if (mElemVec.size() == mElemNumber)
377 return i;
378 else {
379 uint cnt = 0;
380 for (uint ii = 0; ii < i; ii++) {
381 if (!mElemVec[ii].deleted())
382 ++cnt;
383 }
384 return cnt;
385 }
386 }
387
399 std::vector<uint> elementCompactIndices() const
400 {
401 std::vector<uint> newIndices(mElemVec.size());
402 uint k = 0;
403 for (uint i = 0; i < mElemVec.size(); ++i) {
404 if (!mElemVec[i].deleted()) {
405 newIndices[i] = k;
406 k++;
407 }
408 else {
409 newIndices[i] = UINT_NULL;
410 }
411 }
412 return newIndices;
413 }
414
429 void append(const ElementContainer<T>& other)
430 {
431 using Comps = T::Components;
432
433 uint on = other.elementContainerSize();
434 uint n = elementContainerSize();
435 addElements(on);
436 for (uint i = 0; i < on; ++i) {
437 // copy everything from the other elements, also the (not updated)
438 // pointers:
439 if (other.element(i).deleted()) {
440 deleteElement(n + i);
441 }
442 element(n + i) = other.element(i);
443 element(n + i).setParentMesh(mParentMesh);
444 }
445 // importing also optional, vertical and custom components:
446 appendVerticalComponents(other, VertComps());
447 appendCustomComponents(other);
448 }
449
460 void serializeOptionalComponentsAndElementsNumber(std::ostream& out) const
461 {
462 constexpr uint N_VERT_COMPS = VertComps::size();
463 std::array<bool, N_VERT_COMPS> enabledComps;
464 uint i = 0;
465
466 auto forEachVertComp = [&]<typename Comp>() {
467 enabledComps[i] =
468 mVerticalCompVecTuple.template isComponentEnabled<Comp>();
469 ++i;
470 };
471
472 ForEachType<VertComps>::apply(forEachVertComp);
473
474 vcl::serialize(out, elementContainerSize());
475 vcl::serialize(out, enabledComps);
476 }
477
486 void serializeElements(std::ostream& out) const
487 {
488 for (const auto& e : mElemVec) {
489 e.serialize(out);
490 }
491 }
492
503 void deserializeOptionalComponentsAndElementsNumber(std::istream& in)
504 {
505 constexpr uint N_VERT_COMPS = VertComps::size();
506 std::array<bool, N_VERT_COMPS> enabledComps;
507 uint size = 0;
508
509 vcl::deserialize(in, size);
510 vcl::deserialize(in, enabledComps);
511
512 resizeElements(size);
513
514 uint i = 0;
515 auto forEachVertComp = [&]<typename Comp>() {
516 if (enabledComps[i])
517 mVerticalCompVecTuple.template enableComponent<Comp>();
518 else
519 mVerticalCompVecTuple.template disableComponent<Comp>();
520 ++i;
521 };
522
523 ForEachType<VertComps>::apply(forEachVertComp);
524 }
525
534 void deserializeElements(std::istream& in)
535 {
536 for (auto& e : mElemVec) {
537 e.deserialize(in);
538 }
539 }
540
552 ElementIterator elementBegin(bool jumpDeleted = true)
553 {
554 return ElementIterator(
555 mElemVec.begin(),
556 mElemVec,
557 jumpDeleted && mElemVec.size() != mElemNumber);
558 }
559
564 ElementIterator elementEnd()
565 {
566 return ElementIterator(mElemVec.end(), mElemVec);
567 }
568
580 ConstElementIterator elementBegin(bool jumpDeleted = true) const
581 {
582 return ConstElementIterator(
583 mElemVec.begin(),
584 mElemVec,
585 jumpDeleted && mElemVec.size() != mElemNumber);
586 }
587
592 ConstElementIterator elementEnd() const
593 {
594 return ConstElementIterator(mElemVec.end(), mElemVec);
595 }
596
619 View<ElementIterator> elements(bool jumpDeleted = true)
620 {
621 return View(
622 elementBegin(jumpDeleted && mElemVec.size() != mElemNumber),
623 elementEnd());
624 }
625
650 View<ElementIterator> elements(uint begin, uint end = UINT_NULL)
651 {
652 assert(begin <= elementContainerSize());
653 if (end == UINT_NULL || end > elementContainerSize())
654 end = elementContainerSize();
655 assert(begin <= end);
656 return View(elementBegin(false) + begin, elementBegin(false) + end);
657 }
658
681 View<ConstElementIterator> elements(bool jumpDeleted = true) const
682 {
683 return View(
684 elementBegin(jumpDeleted && mElemVec.size() != mElemNumber),
685 elementEnd());
686 }
687
712 View<ConstElementIterator> elements(uint begin, uint end = UINT_NULL) const
713 {
714 assert(begin <= elementContainerSize());
715 if (end == UINT_NULL || end > elementContainerSize())
716 end = elementContainerSize();
717 assert(begin <= end);
718 return View(elementBegin(false) + begin, elementBegin(false) + end);
719 }
720
721 void enableAllOptionalComponents()
722 {
723 mVerticalCompVecTuple.enableAllOptionalComponents();
724 }
725
726 void disableAllOptionalComponents()
727 {
728 mVerticalCompVecTuple.disableAllOptionalComponents();
729 }
730
731 template<typename C>
732 bool isComponentAvailable() const
733 {
734 if constexpr (comp::HasComponentOfType<T, C::COMPONENT_ID>) {
735 if constexpr (comp::
736 HasOptionalComponentOfType<T, C::COMPONENT_ID>) {
737 return mVerticalCompVecTuple.template isComponentEnabled<C>();
738 }
739 else {
740 return true;
741 }
742 }
743 else {
744 return false;
745 }
746 }
747
748 template<uint COMP_ID>
749 bool isComponentAvailable() const
750 {
751 if constexpr (comp::HasComponentOfType<T, COMP_ID>) {
752 if constexpr (comp::HasOptionalComponentOfType<T, COMP_ID>) {
753 return mVerticalCompVecTuple
754 .template isComponentEnabled<COMP_ID>();
755 }
756 else {
757 return true;
758 }
759 }
760 else {
761 return false;
762 }
763 }
764
765 template<typename C>
766 bool isOptionalComponentEnabled() const
767 {
768 return mVerticalCompVecTuple.template isComponentEnabled<C>();
769 }
770
771 template<uint COMP_ID>
772 bool isOptionalComponentEnabled() const
773 {
774 return mVerticalCompVecTuple.template isComponentEnabled<COMP_ID>();
775 }
776
777 template<typename C>
778 void enableOptionalComponent()
779 {
780 mVerticalCompVecTuple.template enableComponent<C>();
781 // first call init on all the just enabled components
782 if constexpr (comp::HasInitMemberFunction<C>) {
783 for (auto& e : elements()) {
784 e.C::init();
785 }
786 }
787 // then resize the component containers with tied size to vertex number
788 if constexpr (comp::IsTiedToVertexNumber<C>) {
789 static const int N = T::VERTEX_NUMBER;
790 if constexpr (N < 0) {
791 for (auto& e : elements()) {
792 e.C::resize(e.vertexNumber());
793 }
794 }
795 }
796 }
797
798 template<uint COMP_ID>
799 void enableOptionalComponent()
800 {
801 using C = comp::ComponentOfType<COMP_ID, typename T::Components>;
802 enableOptionalComponent<C>();
803 }
804
805 template<typename C>
806 void disableOptionalComponent()
807 {
808 mVerticalCompVecTuple.template disableComponent<C>();
809 }
810
811 template<uint COMP_ID>
812 void disableOptionalComponent()
813 {
814 mVerticalCompVecTuple.template disableComponent<COMP_ID>();
815 }
816
817 // Custom Components
818
819 bool hasElemCustomComponent(const std::string& name) const
820 requires comp::HasCustomComponents<T>
821 {
822 return mCustomCompVecMap.componentExists(name);
823 }
824
825 std::vector<std::string> elemCustomComponentNames() const
826 requires comp::HasCustomComponents<T>
827 {
828 return mCustomCompVecMap.allComponentNames();
829 }
830
831 template<typename K>
832 bool isElemCustomComponentOfType(const std::string& name) const
833 requires comp::HasCustomComponents<T>
834 {
835 return mCustomCompVecMap.template isComponentOfType<K>(name);
836 }
837
838 std::type_index elemComponentType(const std::string& name) const
839 requires comp::HasCustomComponents<T>
840 {
841 return mCustomCompVecMap.componentType(name);
842 }
843
844 template<typename K>
845 std::vector<std::string> elemCustomComponentNamesOfType() const
846 requires comp::HasCustomComponents<T>
847 {
848 return mCustomCompVecMap.template allComponentNamesOfType<K>();
849 }
850
851 template<typename K>
852 void addElemCustomComponent(const std::string& name)
853 requires comp::HasCustomComponents<T>
854 {
855 mCustomCompVecMap.template addNewComponent<K>(
856 name, elementContainerSize());
857 }
858
859 void deleteElemCustomComponent(const std::string& name)
860 requires comp::HasCustomComponents<T>
861 {
862 mCustomCompVecMap.deleteComponent(name);
863 }
864
865 template<typename K>
866 CustomComponentVectorHandle<K> customComponentVectorHandle(
867 const std::string& name) requires comp::HasCustomComponents<T>
868 {
869 std::vector<std::any>& cc =
870 mCustomCompVecMap.template componentVector<K>(name);
871 CustomComponentVectorHandle<K> v(cc);
872 return v;
873 }
874
875 template<typename K>
876 ConstCustomComponentVectorHandle<K> customComponentVectorHandle(
877 const std::string& name) const requires comp::HasCustomComponents<T>
878 {
879 const std::vector<std::any>& cc =
880 mCustomCompVecMap.template componentVector<K>(name);
881 ConstCustomComponentVectorHandle<K> v(cc);
882 return cc;
883 }
884
885 template<typename K>
886 void serializePerElementCustomComponentsOfType(std::ostream& os) const
887 requires comp::HasCustomComponents<T>
888 {
889 mCustomCompVecMap.template serializeCustomComponentsOfType<K>(os);
890 }
891
892 template<typename K>
893 void deserializePerElementCustomComponentsOfType(std::istream& is)
894 requires comp::HasCustomComponents<T>
895 {
896 mCustomCompVecMap.template deserializeCustomComponentsOfType<K>(is);
897 }
898
899 uint index(const T* e) const
900 {
901 assert(
902 !mElemVec.empty() && e >= mElemVec.data() && e <= &mElemVec.back());
903 return e - mElemVec.data();
904 }
905
906 void setParentMeshPointers(void* pm)
907 {
908 mParentMesh = static_cast<ParentMeshType*>(pm);
909 for (auto& e : elements(false)) {
910 e.setParentMesh(pm);
911 }
912 }
913
914 template<typename Element>
915 void updateReferences(
916 const Element* oldBase,
917 uint firstElementToProcess = 0,
918 uint offset = 0)
919 {
920 using Comps = T::Components;
921
922 updateReferencesOnComponents(
923 oldBase, Comps(), firstElementToProcess, offset);
924 }
925
926 template<typename Element>
927 void updateReferences(const std::vector<uint>& newIndices)
928 {
929 using Comps = T::Components;
930
931 updateReferencesOnComponents<Element>(newIndices, Comps());
932 }
933
965 void updateElementIndices(const std::vector<uint>& newIndices)
966 {
967 mParentMesh->template updateAllReferences<T>(newIndices);
968 }
969
970 template<typename OtherMesh>
971 void enableOptionalComponentsOf(const OtherMesh& m)
972 {
973 if constexpr (OtherMesh::template hasContainerOf<T>()) {
974 // get the container type of the other mesh for T - used to upcast
975 // othMesh
976 using OContainer = OtherMesh::template ContainerOf<T>::type;
977
978 const OContainer& c = static_cast<const OContainer&>(m);
979
980 enableSameOptionalComponents(typename T::Components(), c);
981 }
982 }
983
984 template<typename OtherMesh>
985 void importFrom(const OtherMesh& m)
986 {
987 if constexpr (OtherMesh::template hasContainerOf<T>()) {
988 // get the container type of the other mesh for T - used to upcast
989 // othMesh
990 using Container = OtherMesh::template ContainerOf<T>::type;
991
992 const Container& c = (const Container&) m;
993
994 clearElements();
995
996 // recreate a container having the same number of elements as the
997 // other mesh. this call will also update the parentMesh pointers
998 // and sets the vertical components vectors in vcVecTuple
999 addElements(c.elementContainerSize());
1000 unsigned int eid = 0;
1001 for (const typename Container::ElementType& e : c.elements(false)) {
1002 // import the components of the e, when they are available.
1003 // note that will set also the deleted flag of e, therefore if e
1004 // is deleted, then also element(eid) will be deleted.
1005 element(eid).importFrom(e);
1006 ++eid;
1007 }
1008 // set the number of elements (different from the container size)
1009 mElemNumber = c.mElemNumber;
1010 if constexpr (
1011 comp::HasCustomComponents<T> &&
1012 comp::HasCustomComponents<typename Container::ElementType>) {
1013 mCustomCompVecMap = c.mCustomCompVecMap;
1014 }
1015 }
1016 }
1017
1018private:
1019 template<typename ElPtr, typename... Comps>
1020 void updateReferencesOnComponents(
1021 const ElPtr* oldBase,
1022 TypeWrapper<Comps...>,
1023 uint firstElementToProcess = 0,
1024 uint offset = 0)
1025 {
1026 (updateReferencesOnComponent<Comps>(
1027 oldBase, firstElementToProcess, offset),
1028 ...);
1029 }
1030
1031 template<typename ElPtr, typename... Comps>
1032 void updateReferencesOnComponents(
1033 const std::vector<uint>& newIndices,
1034 TypeWrapper<Comps...>)
1035 {
1036 (updateReferencesOnComponent<Comps, ElPtr>(newIndices), ...);
1037 }
1038
1039 /*
1040 * This function is called for each component of the element.
1041 *
1042 * Only if a component has references of the type ElPtr, then the
1043 * updateReferences on each element will be executed.
1044 *
1045 * firstElementToProcess and offset are used only when an append operation
1046 * has been executed. In this case, the firstElementToProcess is the index
1047 * of the first element that has been appended, and offset is the number of
1048 * ElPtr elements that have been appended (the offset that must be added
1049 * to the newBase w.r.t. the oldBase that was the other container from which
1050 * the elements have been copied).
1051 */
1052 template<typename Comp, typename ElPtr>
1053 void updateReferencesOnComponent(
1054 const ElPtr* oldBase,
1055 uint firstElementToProcess = 0,
1056 uint offset = 0)
1057 {
1058 if constexpr (comp::HasReferencesOfType<Comp, ElPtr>) {
1059 // lambda to avoid code duplication
1060 auto loop = [&]() {
1061 for (uint i = firstElementToProcess; i < elementContainerSize();
1062 i++) {
1063 T& e = element(i);
1064 if (!e.deleted()) {
1065 e.Comp::updateReferences(oldBase, offset);
1066 }
1067 }
1068 };
1069
1070 if constexpr (comp::HasOptionalReferencesOfType<Comp, ElPtr>) {
1071 if (isOptionalComponentEnabled<Comp>()) {
1072 loop();
1073 }
1074 }
1075 else {
1076 loop();
1077 }
1078 }
1079 }
1080
1081 template<typename Comp, typename ElPtr>
1082 void updateReferencesOnComponent(const std::vector<uint>& newIndices)
1083 {
1084 if constexpr (comp::HasReferencesOfType<Comp, ElPtr>) {
1085 if constexpr (comp::HasOptionalReferencesOfType<Comp, ElPtr>) {
1086 if (isOptionalComponentEnabled<Comp>()) {
1087 for (T& e : elements()) {
1088 e.Comp::updateReferences(newIndices);
1089 }
1090 }
1091 }
1092 else {
1093 for (T& e : elements()) {
1094 e.Comp::updateReferences(newIndices);
1095 }
1096 }
1097 }
1098 }
1099
1100 template<typename... Comps>
1101 void appendVerticalComponents(
1102 const ElementContainer<T>& other,
1103 TypeWrapper<Comps...>)
1104 {
1105 (appendVerticalComponent<Comps>(other), ...);
1106 }
1107
1108 template<typename Comp>
1109 void appendVerticalComponent(const ElementContainer<T>& other)
1110 {
1111 uint on = other.elementContainerSize();
1112 uint n = elementContainerSize() - on;
1113
1114 if (mVerticalCompVecTuple.template isComponentEnabled<Comp>() &&
1115 other.mVerticalCompVecTuple.template isComponentEnabled<Comp>()) {
1116 auto& vc = mVerticalCompVecTuple.template vector<Comp>();
1117 const auto& ovc =
1118 other.mVerticalCompVecTuple.template vector<Comp>();
1119
1120 for (uint i = 0; i < on; ++i) {
1121 vc[n + i] = ovc[i];
1122 }
1123 }
1124 }
1125
1126 void appendCustomComponents(const ElementContainer<T>& other)
1127 {
1128 if constexpr (comp::HasCustomComponents<T>) {
1129 uint on = other.elementContainerSize();
1130 uint n = elementContainerSize() - on;
1131
1132 std::vector<std::string> ccNames =
1133 mCustomCompVecMap.allComponentNames();
1134
1135 for (const std::string& name : ccNames) {
1136 for (uint i = 0; i < on; ++i) {
1137 mCustomCompVecMap.importSameCustomComponentFrom(
1138 n + i, i, name, other.mCustomCompVecMap);
1139 }
1140 }
1141 }
1142 }
1143
1144 template<typename Cont2, typename... Comps>
1145 void enableSameOptionalComponents(TypeWrapper<Comps...>, const Cont2& c2)
1146 {
1147 // for each Component in Comps, will call enableSameOptionalComponent
1148 (enableSameOptionalComponent<Comps>(c2), ...);
1149 }
1150
1155 template<typename Comp, typename Cont2>
1156 void enableSameOptionalComponent(const Cont2& c2)
1157 {
1158 // if Comp is an optional component in This container
1159 if constexpr (comp::IsOptionalComponent<Comp>) {
1160 // if Comp is available in Cont2
1161 if constexpr (comp::HasComponentOfType<
1162 typename Cont2::ElementType,
1163 Comp::COMPONENT_ID>) {
1164 // if Comp is optional in Cont2
1165 if constexpr (comp::HasOptionalComponentOfType<
1166 typename Cont2::ElementType,
1167 Comp::COMPONENT_ID>) {
1168 // if Comp is enabled in Cont2, we enable it in this
1169 // container
1170 if (c2.template isOptionalComponentEnabled<
1171 Comp::COMPONENT_ID>()) {
1172 enableOptionalComponent<Comp::COMPONENT_ID>();
1173 }
1174 }
1175 // if Comp is not optional (but is available), we enable it in
1176 // this container
1177 else {
1178 enableOptionalComponent<Comp::COMPONENT_ID>();
1179 }
1180 }
1181 }
1182 }
1183};
1184
1197template<typename T>
1198concept ElementContainerConcept =
1199 std::derived_from< // same type or derived type
1200 std::remove_cvref_t<T>,
1201 ElementContainer<typename RemoveRef<T>::ElementType>>;
1202
1204
1205} // namespace vcl::mesh
1206
1207#endif // VCL_MESH_CONTAINERS_BASE_ELEMENT_CONTAINER_H
PointT size() const
Computes the size of the box.
Definition box.h:267
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