VCG Library
Loading...
Searching...
No Matches
append.h
1/****************************************************************************
2* VCGLib o o *
3* Visual and Computer Graphics Library o o *
4* _ O _ *
5* Copyright(C) 2004-2016 \/)\/ *
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 GNU General Public License as published by *
13* the Free Software 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* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20* for more details. *
21* *
22****************************************************************************/
23#ifndef __VCGLIB_APPEND
24#define __VCGLIB_APPEND
25
26#include <vcg/complex/allocate.h>
27#include <vcg/complex/algorithms/update/selection.h>
28
29namespace vcg {
30namespace tri {
38template<class MeshLeft, class ConstMeshRight>
39class Append
40{
41public:
42 typedef typename MeshLeft::ScalarType ScalarLeft;
43 typedef typename MeshLeft::CoordType CoordLeft;
44 typedef typename MeshLeft::VertexType VertexLeft;
45 typedef typename MeshLeft::EdgeType EdgeLeft;
46 typedef typename MeshLeft::FaceType FaceLeft;
47 typedef typename MeshLeft::HEdgeType HEdgeLeft;
48 typedef typename MeshLeft::TetraType TetraLeft;
49 typedef typename MeshLeft::VertexPointer VertexPointerLeft;
50 typedef typename MeshLeft::VertexIterator VertexIteratorLeft;
51 typedef typename MeshLeft::EdgeIterator EdgeIteratorLeft;
52 typedef typename MeshLeft::HEdgeIterator HEdgeIteratorLeft;
53 typedef typename MeshLeft::FaceIterator FaceIteratorLeft;
54 typedef typename MeshLeft::TetraIterator TetraIteratorLeft;
55
56
57 typedef typename ConstMeshRight::ScalarType ScalarRight;
58 typedef typename ConstMeshRight::CoordType CoordRight;
59 typedef typename ConstMeshRight::VertexType VertexRight;
60 typedef typename ConstMeshRight::EdgeType EdgeRight;
61 typedef typename ConstMeshRight::HEdgeType HEdgeRight;
62 typedef typename ConstMeshRight::FaceType FaceRight;
63 typedef typename ConstMeshRight::TetraType TetraRight;
64 typedef typename ConstMeshRight::TetraPointer TetraPointerRight;
65 typedef typename ConstMeshRight::TetraIterator TetraIteratorRight;
66 typedef typename ConstMeshRight::VertexPointer VertexPointerRight;
67 typedef typename ConstMeshRight::VertexIterator VertexIteratorRight;
68 typedef typename ConstMeshRight::EdgeIterator EdgeIteratorRight;
69 typedef typename ConstMeshRight::HEdgeIterator HEdgeIteratorRight;
70 typedef typename ConstMeshRight::FaceIterator FaceIteratorRight;
71 typedef typename ConstMeshRight::FacePointer FacePointerRight;
72
73 struct Remap{
74 static size_t InvalidIndex() { return std::numeric_limits<size_t>::max(); }
75 std::vector<size_t> vert, face, edge, hedge, tetra;
76 };
77
78 static void ImportVertexAdj(MeshLeft &ml, const ConstMeshRight &mr, VertexLeft &vl, const VertexRight &vr, Remap &remap ){
79 // Vertex to Edge Adj
80 if(HasVEAdjacency(ml) && HasVEAdjacency(mr) && vr.cVEp() != 0){
81 size_t i = Index(mr,vr.cVEp());
82 vl.VEp() = (i>ml.edge.size())? 0 : &ml.edge[remap.edge[i]];
83 vl.VEi() = vr.VEi();
84 }
85
86 // Vertex to Face Adj
87 if(HasPerVertexVFAdjacency(ml) && HasPerVertexVFAdjacency(mr) && vr.cVFp() != 0 ){
88 size_t i = Index(mr,vr.cVFp());
89 vl.VFp() = (i>ml.face.size())? 0 :&ml.face[remap.face[i]];
90 vl.VFi() = vr.VFi();
91 }
92
93 // Vertex to HEdge Adj
94 if(HasVHAdjacency(ml) && HasVHAdjacency(mr) && vr.cVHp() != 0){
95 vl.VHp() = &ml.hedge[remap.hedge[Index(mr,vr.cVHp())]];
96 vl.VHi() = vr.VHi();
97 }
98
99 // Vertex to Tetra Adj
100 if(HasVTAdjacency(ml) && HasVTAdjacency(mr) && vr.cVTp() != 0){
101 size_t i = Index(mr, vr.cVTp());
102 vl.VTp() = (i > ml.edge.size()) ? 0 : &ml.tetra[remap.tetra[i]];
103 vl.VTi() = vr.VTi();
104 }
105 }
106
107 static void ImportEdgeAdj(MeshLeft &ml, const ConstMeshRight &mr, EdgeLeft &el, const EdgeRight &er, Remap &remap)
108 {
109 // Edge to Edge Adj
110 if(HasEEAdjacency(ml) && HasEEAdjacency(mr))
111 for(unsigned int vi = 0; vi < 2; ++vi)
112 {
113 size_t idx = Index(mr,er.cEEp(vi));
114 el.EEp(vi) = (idx>ml.edge.size())? 0 : &ml.edge[remap.edge[idx]];
115 el.EEi(vi) = er.cEEi(vi);
116 }
117
118 // Edge to Face Adj
119 if(HasEFAdjacency(ml) && HasEFAdjacency(mr)){
120 size_t idx = Index(mr,er.cEFp());
121 el.EFp() = (idx>ml.face.size())? 0 :&ml.face[remap.face[idx]];
122 el.EFi() = er.cEFi();
123 }
124
125 // Edge to HEdge Adj
126 if(HasEHAdjacency(ml) && HasEHAdjacency(mr))
127 el.EHp() = &ml.hedge[remap.hedge[Index(mr,er.cEHp())]];
128 }
129
130
131 static void ImportFaceAdj(MeshLeft &ml, const ConstMeshRight &mr, FaceLeft &fl, const FaceRight &fr, Remap &remap )
132 {
133 // Face to Edge Adj
134 if(HasFEAdjacency(ml) && HasFEAdjacency(mr)){
135 assert(fl.VN() == fr.VN());
136 for( int vi = 0; vi < fl.VN(); ++vi ){
137 size_t idx = remap.edge[Index(mr,fr.cFEp(vi))];
138 if(idx!=Remap::InvalidIndex())
139 fl.FEp(vi) = &ml.edge[idx];
140 }
141 }
142
143 // Face to Face Adj
144 if(HasFFAdjacency(ml) && HasFFAdjacency(mr)){
145 assert(fl.VN() == fr.VN());
146 for( int vi = 0; vi < fl.VN(); ++vi ){
147 size_t idx = remap.face[Index(mr,fr.cFFp(vi))];
148 if(idx!=Remap::InvalidIndex()){
149 assert(idx >= 0 && idx < ml.face.size());
150 fl.FFp(vi) = &ml.face[idx];
151 fl.FFi(vi) = fr.cFFi(vi);
152 }
153 }
154 }
155
156 // Vertex to Face Adj
157 if(HasPerFaceVFAdjacency(ml) && HasPerFaceVFAdjacency(mr))
158 {
159 assert(fl.VN() == fr.VN());
160 for (int vi = 0; vi < fl.VN(); ++vi)
161 {
162 const auto * fp = fr.cVFp(vi);
163 const auto vfindex = fr.cVFi(vi);
164 size_t fidx = (fp == nullptr) ? Remap::InvalidIndex() : remap.face[Index(mr,fp)];
165
166 if (fidx == Remap::InvalidIndex()) // end of VF chain (or not initialized)
167 {
168 fl.VFClear(vi);
169 assert(fl.cVFi(vi) == -1);
170 }
171 else
172 {
173 assert(fidx >= 0 && fidx < ml.face.size());
174 fl.VFp(vi) = &ml.face[fidx];
175 fl.VFi(vi) = vfindex;
176 }
177 }
178 }
179
180 // Face to HEedge Adj
181 if(HasFHAdjacency(ml) && HasFHAdjacency(mr))
182 fl.FHp() = &ml.hedge[remap.hedge[Index(mr,fr.cFHp())]];
183 }
184
185 static void ImportHEdgeAdj(MeshLeft &ml, const ConstMeshRight &mr, HEdgeLeft &hl, const HEdgeRight &hr, Remap &remap, bool /*sel*/ ){
186 // HEdge to Vertex Adj
187 if(HasHVAdjacency(ml) && HasHVAdjacency(mr))
188 hl.HVp() = &ml.vert[remap.vert[Index(mr,hr.cHVp())]];
189
190 // HEdge to Edge Adj
191 if(HasHEAdjacency(ml) && HasHEAdjacency(mr)){
192 size_t idx = Index(mr,hr.cHEp()) ;
193 hl.HEp() = (idx>ml.edge.size())? 0 : &ml.edge[remap.edge[idx]];
194 }
195
196 // HEdge to Face Adj
197 if(HasHFAdjacency(ml) && HasHFAdjacency(mr)){
198 size_t idx = Index(mr,hr.cHFp());
199 hl.HFp() = (idx>ml.face.size())? 0 :&ml.face[remap.face[idx]];
200 }
201
202
203 // HEdge to Opposite HEdge Adj
204 if(HasHOppAdjacency(ml) && HasHOppAdjacency(mr))
205 hl.HOp() = &ml.hedge[remap.hedge[Index(mr,hr.cHOp())]];
206
207 // HEdge to Next HEdge Adj
208 if(HasHNextAdjacency(ml) && HasHNextAdjacency(mr))
209 hl.HNp() = &ml.hedge[remap.hedge[Index(mr,hr.cHNp())]];
210
211 // HEdge to Next HEdge Adj
212 if(HasHPrevAdjacency(ml) && HasHPrevAdjacency(mr))
213 hl.HPp() = &ml.hedge[remap.hedge[Index(mr,hr.cHPp())]];
214 }
215
216 static void ImportTetraAdj(MeshLeft &ml, const ConstMeshRight &mr, TetraLeft &tl, const TetraRight &tr, Remap &remap )
217 {
218 // Tetra to Tetra Adj
219 if(HasTTAdjacency(ml) && HasTTAdjacency(mr)){
220 for( int vi = 0; vi < 4; ++vi ){
221 size_t idx = remap.tetra[Index(mr,tr.cTTp(vi))];
222 if(idx != Remap::InvalidIndex()){
223 tl.TTp(vi) = &ml.tetra[idx];
224 tl.TTi(vi) = tr.cTTi(vi);
225 }
226 }
227 }
228}
229
230// Append Right Mesh to the Left Mesh
231// Append::Mesh(ml, mr) is equivalent to ml += mr.
232// Note MeshRigth could be costant...
253static void Mesh(MeshLeft& ml, ConstMeshRight& mr, const bool selected = false, const bool adjFlag = false)
254{
255 // Note that if the the selection of the vertexes is not consistent with the face selection
256 // the append could build faces referencing non existent vertices
257 // so it is mandatory that the selection of the vertices reflects the loose selection
258 // from edges and faces (e.g. if a face is selected all its vertices must be selected).
259 // note the use of the parameter for preserving existing vertex selection.
260 if(selected)
261 {
262 assert(adjFlag == false || ml.IsEmpty()); // It is rather meaningless to partially copy adj relations.
265 }
266
267 MeshAppendConst(ml, mr, selected, adjFlag);
268}
269
288static void MeshAppendConst(
289 MeshLeft& ml,
290 const ConstMeshRight& mr,
291 const bool selected = false,
292 const bool adjFlag = false)
293{
294 // phase 1. allocate on ml vert,edge,face, hedge to accomodat those of mr
295 // and build the remapping for all
296
297 Remap remap;
298
299 // vertex
300 remap.vert.resize(mr.vert.size(), Remap::InvalidIndex());
301 VertexIteratorLeft vp;
302 if(selected){
304 vp=Allocator<MeshLeft>::AddVertices(ml,int(svn));
305 }
306 else
308
309 ForEachVertex(mr, [&](const VertexRight& v)
310 {
311 if(!selected || v.IsS())
312 {
313 size_t ind=Index(mr,v);
314 remap.vert[ind]=int(Index(ml,*vp));
315 ++vp;
316 }
317 });
318 // edge
319 remap.edge.resize(mr.edge.size(), Remap::InvalidIndex());
320 EdgeIteratorLeft ep;
321 if(selected) {
324 }
325 else ep=Allocator<MeshLeft>::AddEdges(ml,mr.en);
326
327 ForEachEdge(mr, [&](const EdgeRight& e)
328 {
329 if(!selected || e.IsS()){
330 size_t ind=Index(mr,e);
331 remap.edge[ind]=int(Index(ml,*ep));
332 ++ep;
333 }
334 });
335
336 // face
337 remap.face.resize(mr.face.size(), Remap::InvalidIndex());
338 FaceIteratorLeft fp;
339 if(selected) {
342 }
343 else fp=Allocator<MeshLeft>::AddFaces(ml,mr.fn);
344
345 ForEachFace(mr, [&](const FaceRight& f)
346 {
347 if(!selected || f.IsS()){
348 size_t ind=Index(mr,f);
349 remap.face[ind]=int(Index(ml,*fp));
350 ++fp;
351 }
352 });
353
354 // hedge
355 remap.hedge.resize(mr.hedge.size(),Remap::InvalidIndex());
356
357 ForEachHEdge(mr, [&](const HEdgeRight& he)
358 {
359 if(!selected || he.IsS()){
360 size_t ind=Index(mr,he);
361 assert(remap.hedge[ind]==Remap::InvalidIndex());
362 HEdgeIteratorLeft hp = Allocator<MeshLeft>::AddHEdges(ml,1);
363 (*hp).ImportData(he);
364 remap.hedge[ind]=Index(ml,*hp);
365 }
366 });
367
368 remap.tetra.resize(mr.tetra.size(), Remap::InvalidIndex());
369
370 ForEachTetra(mr, [&](const TetraRight& t)
371 {
372 if (!selected || t.IsS()) {
373 size_t idx = Index(mr, t);
374 assert (remap.tetra[idx] == Remap::InvalidIndex());
375 TetraIteratorLeft tp = Allocator<MeshLeft>::AddTetras(ml, 1);
376 (*tp).ImportData(t);
377 remap.tetra[idx] = Index(ml, *tp);
378 }
379 });
380
381 // phase 1.5
382 // manage textures, creating a new one only when necessary
383 // (not making unuseful duplicates on append) and save a mapping
384
385 // for each texture in the right mesh, it maps it to the texture index in the
386 // left mesh
387 std::vector<unsigned int> mappingTextures(mr.textures.size());
388
389 unsigned int baseMlT = ml.textures.size();
390 for (unsigned int i = 0; i < mr.textures.size(); ++i) {
391 auto it = std::find(ml.textures.begin(), ml.textures.end(), mr.textures[i]);
392 //if the right texture does not exists in the left mesh
393 if (it == ml.textures.end()) {
394 //add the texture in the left mesh and create the mapping
395 mappingTextures[i] = baseMlT++;
396 ml.textures.push_back(mr.textures[i]);
397 }
398 else {
399 //the ith right texture will map in the texture found in the left mesh
400 mappingTextures[i] = it - ml.textures.begin();
401 }
402 }
403 //ml.textures.insert(ml.textures.end(), mr.textures.begin(),mr.textures.end());
404
405 // phase 2.
406 // copy data from mr to its corresponding elements in ml and adjacencies
407
408 //vtexcoords - can copy only if they are enabled both on l and r
409 bool vertTexFlag = HasPerVertexTexCoord(ml) && HasPerVertexTexCoord(mr);
410
411 // vertex
412 ForEachVertex(mr, [&](const VertexRight& v)
413 {
414 if(!selected || v.IsS()){
415 VertexLeft &vl = ml.vert[remap.vert[Index(mr,v)]];
416 vl.ImportData(v);
417 if(adjFlag)
418 ImportVertexAdj(ml,mr,vl,v,remap);
419 if (vertTexFlag){
420 if (size_t(v.T().n()) < mappingTextures.size()) {
421 //standard case: the texture is contained in the mesh
422 vl.T().n() = mappingTextures[v.T().n()];
423 }
424 else {
425 //the mesh has tex coords, but not the texture...
426 vl.T().n() = v.T().n();
427 }
428 }
429 }
430 });
431
432 // edge
433 ForEachEdge(mr, [&](const EdgeRight& e)
434 {
435 if(!selected || e.IsS()){
436 ml.edge[remap.edge[Index(mr,e)]].ImportData(e);
437 // Edge to Vertex Adj
438 EdgeLeft &el = ml.edge[remap.edge[Index(mr,e)]];
439 if(HasEVAdjacency(ml) && HasEVAdjacency(mr)){
440 el.V(0) = &ml.vert[remap.vert[Index(mr,e.cV(0))]];
441 el.V(1) = &ml.vert[remap.vert[Index(mr,e.cV(1))]];
442 }
443 if(adjFlag) ImportEdgeAdj(ml,mr,el,e,remap);
444 }
445 });
446
447 //ftexcoords - can copy only if they are enabled both on l and r
448 bool wedgeTexFlag = HasPerWedgeTexCoord(ml) && HasPerWedgeTexCoord(mr);
449
450 // face
451 ForEachFace(mr, [&](const FaceRight& f)
452 {
453 if(!selected || f.IsS())
454 {
455 FaceLeft &fl = ml.face[remap.face[Index(mr,f)]];
456 fl.Alloc(f.VN());
457 if(HasFVAdjacency(ml) && HasFVAdjacency(mr)){
458 for(int i = 0; i < fl.VN(); ++i)
459 fl.V(i) = &ml.vert[remap.vert[Index(mr,f.cV(i))]];
460 }
461 fl.ImportData(f);
462 if(wedgeTexFlag) {
463 for(int i = 0; i < 3; ++i){
464 if (size_t(f.WT(i).n()) < mappingTextures.size()){
465 //standard case: the texture is contained in the mesh
466 fl.WT(i).n() = mappingTextures[f.WT(i).n()];
467 }
468 else {
469 //the mesh has tex coords, but not the texture...
470 fl.WT(i).n() = f.WT(i).n();
471 }
472 }
473 }
474 if(adjFlag) ImportFaceAdj(ml,mr,ml.face[remap.face[Index(mr,f)]],f,remap);
475
476 }
477 });
478
479 // hedge
480 ForEachHEdge(mr, [&](const HEdgeRight& he)
481 {
482 if(!selected || he.IsS()){
483 ml.hedge[remap.hedge[Index(mr,he)]].ImportData(he);
484 ImportHEdgeAdj(ml,mr,ml.hedge[remap.hedge[Index(mr,he)]],he,remap,selected);
485 }
486 });
487
488 //tetra
489 ForEachTetra(mr, [&](const TetraRight& t)
490 {
491 if(!selected || t.IsS())
492 {
493 TetraLeft &tl = ml.tetra[remap.tetra[Index(mr,t)]];
494
495 if(HasFVAdjacency(ml) && HasFVAdjacency(mr)){
496 for(int i = 0; i < 4; ++i)
497 tl.V(i) = &ml.vert[remap.vert[Index(mr,t.cV(i))]];
498 }
499 tl.ImportData(t);
500 if(adjFlag) ImportTetraAdj(ml, mr, ml.tetra[remap.tetra[Index(mr,t)]], t, remap);
501
502 }
503 });
504
505 // phase 3.
506 // take care of other per mesh data: attributes
507
508 // Attributes. Copy only those attributes that are present in both meshes
509 // Two attributes in different meshes are considered the same if they have the same
510 // name and the same type. This may be deceiving because they could in fact have
511 // different semantic, but this is up to the developer.
512 // If the left mesh has attributes that are not in the right mesh, their values for the elements
513 // of the right mesh will be uninitialized
514
515 unsigned int id_r;
516 typename std::set< PointerToAttribute >::iterator al, ar;
517
518 // per vertex attributes
519 for (al = ml.vert_attr.begin(); al != ml.vert_attr.end(); ++al)
520 if(!(*al)._name.empty())
521 {
522 ar = mr.vert_attr.find(*al);
523 if (ar != mr.vert_attr.end())
524 {
525 id_r = 0;
526 for (const auto & v : mr.vert)
527 {
528 if( !v.IsD() && (!selected || v.IsS()))
529 (*al)._handle->CopyValue(remap.vert[Index(mr,v)], id_r, (*ar)._handle);
530 ++id_r;
531 }
532 }
533 }
534
535 // per edge attributes
536 for (al = ml.edge_attr.begin(); al != ml.edge_attr.end(); ++al)
537 if (!(*al)._name.empty())
538 {
539 ar = mr.edge_attr.find(*al);
540 if (ar!= mr.edge_attr.end())
541 {
542 id_r = 0;
543 for (const auto & e : mr.edge)
544 {
545 if( !e.IsD() && (!selected || e.IsS()))
546 (*al)._handle->CopyValue(remap.edge[Index(mr,e)], id_r, (*ar)._handle);
547 ++id_r;
548 }
549 }
550 }
551
552 // per face attributes
553 for (al = ml.face_attr.begin(); al != ml.face_attr.end(); ++al)
554 if (!(*al)._name.empty())
555 {
556 ar = mr.face_attr.find(*al);
557 if (ar!= mr.face_attr.end())
558 {
559 id_r = 0;
560 for (const auto & f : mr.face)
561 {
562 if( !f.IsD() && (!selected || f.IsS()))
563 (*al)._handle->CopyValue(remap.face[Index(mr,f)], id_r, (*ar)._handle);
564 ++id_r;
565 }
566 }
567 }
568
569 // per tetra attributes
570 for (al = ml.tetra_attr.begin(); al != ml.tetra_attr.end(); ++al)
571 if (!(*al)._name.empty())
572 {
573 ar = mr.tetra_attr.find(*al);
574 if (ar!= mr.tetra_attr.end())
575 {
576 id_r = 0;
577 for (const auto & t: mr.tetra)
578 {
579 if( !t.IsD() && (!selected || t.IsS()))
580 (*al)._handle->CopyValue(remap.tetra[Index(mr, t)], id_r, (*ar)._handle);
581 ++id_r;
582 }
583 }
584 }
585
586 // per mesh attributes
587 // if both ml and mr have an attribute with the same name, no action is done
588 // if mr has an attribute that is NOT present in ml, the attribute is added to ml
589 //for(ar = mr.mesh_attr.begin(); ar != mr.mesh_attr.end(); ++ar)
590 // if(!(*ar)._name.empty()){
591 // al = ml.mesh_attr.find(*ar);
592 // if(al== ml.mesh_attr.end())
593 // //...
594 // }
595}
596
601static void MeshCopy(MeshLeft& ml, ConstMeshRight& mr, bool selected=false, const bool adjFlag = false)
602{
603 ml.Clear();
604 Mesh(ml,mr,selected,adjFlag);
605 ml.bbox.Import(mr.bbox);
606}
607
608static void MeshCopyConst(MeshLeft& ml, const ConstMeshRight& mr, bool selected=false, const bool adjFlag = false)
609{
610 ml.Clear();
611 MeshAppendConst(ml,mr,selected,adjFlag);
612 ml.bbox.Import(mr.bbox);
613}
619static void Selected(MeshLeft& ml, ConstMeshRight& mr)
620{
621 Mesh(ml,mr,true);
622}
623
624}; // end of class Append
625
626
627
628
629
630} // End Namespace tri
631} // End Namespace vcg
632
633
634#endif
635
636
static EdgeIterator AddEdges(MeshType &m, size_t n, PointerUpdater< EdgePointer > &pu)
Add n edges to the mesh. Function to add n edges to the mesh. The elements are added always to the en...
Definition: allocate.h:333
static VertexIterator AddVertices(MeshType &m, size_t n, PointerUpdater< VertexPointer > &pu)
Add n vertices to the mesh. Function to add n vertices to the mesh. The elements are added always to ...
Definition: allocate.h:189
static FaceIterator AddFaces(MeshType &m, size_t n)
Function to add n faces to the mesh. First wrapper, with no parameters.
Definition: allocate.h:615
Class to safely duplicate and append (portion of) meshes.
Definition: append.h:40
static void MeshAppendConst(MeshLeft &ml, const ConstMeshRight &mr, const bool selected=false, const bool adjFlag=false)
MeshAppendConst.
Definition: append.h:288
static void MeshCopy(MeshLeft &ml, ConstMeshRight &mr, bool selected=false, const bool adjFlag=false)
Copy the second mesh over the first one. The first mesh is destroyed. If requested only the selected ...
Definition: append.h:601
static void Mesh(MeshLeft &ml, ConstMeshRight &mr, const bool selected=false, const bool adjFlag=false)
Append the second mesh to the first one.
Definition: append.h:253
static void Selected(MeshLeft &ml, ConstMeshRight &mr)
Append only the selected elements of second mesh to the first one.
Definition: append.h:619
static size_t VertexCount(const MeshType &m)
This function returns the number of selected vertices.
Definition: selection.h:315
static size_t EdgeCount(const MeshType &m)
This function returns the number of selected edges.
Definition: selection.h:290
static size_t FaceCount(const MeshType &m)
This function returns the number of selected faces.
Definition: selection.h:280
static size_t VertexFromEdgeLoose(MeshType &m, bool preserveSelection=false)
Select all the vertices that are touched by at least a single selected edge.
Definition: selection.h:414
static size_t VertexFromFaceLoose(MeshType &m, bool preserveSelection=false)
Select all the vertices that are touched by at least a single selected faces.
Definition: selection.h:401
void ForEachTetra(const MeshType &m, Callable action)
Definition: foreach.h:270
void ForEachEdge(const MeshType &m, Callable action)
Definition: foreach.h:222
void ForEachFace(const MeshType &m, Callable action)
Definition: foreach.h:78
void ForEachVertex(const MeshType &m, Callable action)
Definition: foreach.h:126
void ForEachHEdge(const MeshType &m, Callable action)
Definition: foreach.h:174
Definition: color4.h:30
Definition: append.h:73