1 /*
2 This Source Code Form is subject to the terms of the Mozilla Public
3 License, v. 2.0. If a copy of the MPL was not distributed with this
4 file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7 #include "vgMesh.h"
8
9
10 namespace Vitelotte
11 {
12
13
14 template < typename _Scalar, int _Dim, int _Chan >
VGMesh(unsigned attributes)15 VGMesh<_Scalar, _Dim, _Chan>::VGMesh(unsigned attributes)
16 : m_attributes(0),
17 m_deletedNodes(0)
18 {
19 m_ndeleted = addNodeProperty<bool>("n:deleted", false);
20 setAttributes(attributes);
21 }
22
23
24 template < typename _Scalar, int _Dim, int _Chan >
VGMesh(unsigned nDims,unsigned nCoeffs,unsigned attributes)25 VGMesh<_Scalar, _Dim, _Chan>::VGMesh(
26 unsigned nDims, unsigned nCoeffs, unsigned attributes)
27 : m_attributes(0),
28 m_deletedNodes(0)
29 {
30 setNDims(nDims);
31 setNCoeffs(nCoeffs);
32 m_ndeleted = addNodeProperty<bool>("n:deleted", false);
33 setAttributes(attributes);
34 }
35
36
37 template < typename _Scalar, int _Dim, int _Chan >
VGMesh(const Self & other)38 VGMesh<_Scalar, _Dim, _Chan>::VGMesh(const Self& other)
39 : PatateCommon::SurfaceMesh(other)
40 {
41 operator=(other);
42 copyVGMeshMembers(other);
43 }
44
45
46 template < typename _Scalar, int _Dim, int _Chan >
47 VGMesh<_Scalar, _Dim, _Chan>&
operator =(const Self & rhs)48 VGMesh<_Scalar, _Dim, _Chan>::operator=(const Self& rhs)
49 {
50 if(&rhs != this)
51 {
52 // FIXME: SurfaceMesh's operator= wont work with properties of different types.
53 PatateCommon::SurfaceMesh::operator=(rhs);
54 copyVGMeshMembers(rhs);
55 }
56 return *this;
57 }
58
59
60 template < typename _Scalar, int _Dim, int _Chan >
61 VGMesh<_Scalar, _Dim, _Chan>&
assign(const Self & rhs)62 VGMesh<_Scalar, _Dim, _Chan>::assign(const Self& rhs)
63 {
64 // FIXME: Implement this properly, ie. copy VGMesh properties without other
65 // custom properties. Disable it in the meantime.
66 assert(false);
67 if(&rhs != this)
68 {
69 // FIXME: SurfaceMesh's operator= wont work with properties of different types.
70 PatateCommon::SurfaceMesh::assign(rhs);
71 // Note: this function is unsuitable for assing()
72 copyVGMeshMembers(rhs);
73 }
74 return *this;
75 }
76
77
78 template < typename _Scalar, int _Dim, int _Chan >
79 void
setNDims(unsigned nDims)80 VGMesh<_Scalar, _Dim, _Chan>::setNDims(unsigned nDims)
81 {
82 assert(int(DimsAtCompileTime) == int(Dynamic) ||
83 int(nDims) == int(DimsAtCompileTime));
84 resizePositionsMatrix(nDims, positionsCapacity());
85 }
86
87
88 template < typename _Scalar, int _Dim, int _Chan >
89 void
setNCoeffs(unsigned nCoeffs)90 VGMesh<_Scalar, _Dim, _Chan>::setNCoeffs(unsigned nCoeffs)
91 {
92 assert(int(CoeffsAtCompileTime) == int(Dynamic) ||
93 int(nCoeffs) == int(CoeffsAtCompileTime));
94 resizeNodesMatrix(nCoeffs, nodesCapacity());
95 }
96
97
98 template < typename _Scalar, int _Dim, int _Chan >
99 void
reserve(unsigned nvertices,unsigned nedges,unsigned nfaces,unsigned nnodes)100 VGMesh<_Scalar, _Dim, _Chan>::reserve(
101 unsigned nvertices, unsigned nedges, unsigned nfaces, unsigned nnodes)
102 {
103 PatateCommon::SurfaceMesh::reserve(nvertices, nedges, nfaces);
104 if(nnodes > nodesCapacity())
105 {
106 if(nnodes > nodesCapacity()) resizeNodesMatrix(nCoeffs(), nnodes);
107 m_nprops.reserve(nnodes);
108 }
109 }
110
111
112 template < typename _Scalar, int _Dim, int _Chan >
113 void
clear()114 VGMesh<_Scalar, _Dim, _Chan>::clear()
115 {
116 PatateCommon::SurfaceMesh::clear();
117 m_nprops.resize(0);
118 m_nprops.freeMemory();
119 m_deletedNodes = 0;
120 resizePositionsMatrix(nDims(), 0);
121 resizeNodesMatrix(nCoeffs(), 0);
122 }
123
124
125 template < typename _Scalar, int _Dim, int _Chan >
126 void
garbageCollection(unsigned flags)127 VGMesh<_Scalar, _Dim, _Chan>::garbageCollection(unsigned flags)
128 {
129 // FIXME: this operation changes vertex order, so it can break edge
130 // orientation. A solution is to invert gradient nodes of affected edges
131 PatateCommon::SurfaceMesh::garbageCollection(GC_DONT_RELEASE_INDEX_MAPS);
132
133 unsigned nN = nodesSize();
134
135 m_gcNodeMap.resize(nN);
136 for(unsigned i = 0; i < nN; ++i) m_gcNodeMap[i] = Node(i);
137
138
139 // remove deleted nodes
140 if(nN > 0)
141 {
142 int i0 = 0;
143 int i1 = nN - 1;
144
145 while (1)
146 {
147 // find first deleted and last un-deleted
148 while(!m_ndeleted[Node(i0)] && i0 < i1) ++i0;
149 while( m_ndeleted[Node(i1)] && i0 < i1) --i1;
150 if(i0 >= i1) break;
151
152 // swap
153 m_nprops.swap(i0, i1);
154 std::swap(m_gcNodeMap[i0], m_gcNodeMap[i1]);
155 };
156
157 // remember new size
158 nN = m_ndeleted[Node(i0)] ? i0 : i0+1;
159 }
160
161
162
163 // remap vertices
164 for(unsigned vi = 0; vi < nVertices(); ++vi) {
165 Vertex v(vi);
166 if(v != gcMap(v))
167 {
168 m_positions.col(vi) = m_positions.col(gcMap(v).idx());
169 }
170 }
171
172 VertexGradientMap vxGradConstraints;
173 for(typename VertexGradientMap::const_iterator vxGrad = m_vertexGradientConstraints.begin();
174 vxGrad != m_vertexGradientConstraints.end(); ++vxGrad)
175 {
176 vxGradConstraints.insert(std::make_pair(gcMap(vxGrad->first), vxGrad->second));
177 }
178 m_vertexGradientConstraints.swap(vxGradConstraints);
179
180 // remap halfedges
181 for(HalfedgeIterator hit = halfedgesBegin(); hit != halfedgesEnd(); ++hit)
182 {
183 for(unsigned ai = 0; ai < HALFEDGE_ATTRIB_COUNT; ++ai)
184 {
185 HalfedgeAttribute attr = HalfedgeAttribute(ai);
186 if(hasAttribute(attr))
187 {
188 Node& n = halfedgeNode(*hit, attr);
189 if(n.isValid()) n = gcMap(n);
190 }
191 }
192 }
193
194 // remap nodes
195 for(unsigned ni = 0; ni < nN; ++ni)
196 {
197 Node n(ni);
198 if(n != gcMap(n))
199 {
200 m_nodes.col(ni) = m_nodes.col(gcMap(n).idx());
201 }
202 }
203
204 if(!(flags & GC_DONT_RELEASE_INDEX_MAPS))
205 {
206 releaseGCIndexMaps();
207 }
208
209 m_nprops.resize(nN); m_nprops.freeMemory();
210
211 m_deletedNodes = 0;
212 m_garbage = false;
213 }
214
215
216 template < typename _Scalar, int _Dim, int _Chan >
217 void
releaseGCIndexMaps()218 VGMesh<_Scalar, _Dim, _Chan>::releaseGCIndexMaps()
219 {
220 PatateCommon::SurfaceMesh::releaseGCIndexMaps();
221 std::vector<Node> nMap;
222 m_gcNodeMap.swap(nMap);
223 }
224
225
226 template < typename _Scalar, int _Dim, int _Chan >
227 template < typename Derived >
228 PatateCommon::SurfaceMesh::Vertex
addVertex(const Eigen::DenseBase<Derived> & pos)229 VGMesh<_Scalar, _Dim, _Chan>::addVertex(const Eigen::DenseBase<Derived>& pos)
230 {
231 if(positionsCapacity() == verticesSize())
232 {
233 unsigned size = std::max(16u, verticesSize() * 2);
234 resizePositionsMatrix(nDims(), size);
235 }
236 m_positions.col(verticesSize()) = pos;
237 Vertex v = PatateCommon::SurfaceMesh::addVertex();
238 assert(nodesSize() <= positionsCapacity());
239 return v;
240 }
241
242
243 template < typename _Scalar, int _Dim, int _Chan >
244 bool
isValid(Node n) const245 VGMesh<_Scalar, _Dim, _Chan>::isValid(Node n) const
246 {
247 return 0 <= n.idx() && unsigned(n.idx()) < nodesSize();
248 }
249
250
251 template < typename _Scalar, int _Dim, int _Chan >
setAttributes(unsigned attributes)252 void VGMesh<_Scalar, _Dim, _Chan>::setAttributes(unsigned attributes)
253 {
254 for(int ai = 0; ai < HALFEDGE_ATTRIB_COUNT; ++ai) {
255 unsigned flag = PATATE_VG_MESH_HALFEDGE_ATTR_FLAG(ai);
256 if(!(m_attributes & flag) && (attributes & flag)) {
257 m_halfedgeAttributes[ai] =
258 addHalfedgeProperty<Node>(_halfedgeAttrName[ai], Node());
259 } else if((m_attributes & flag) && !(attributes & flag)) {
260 removeHalfedgeProperty(m_halfedgeAttributes[ai]);
261 }
262 }
263
264
265 m_attributes = attributes;
266 }
267
268
269 template < typename _Scalar, int _Dim, int _Chan >
270 typename VGMesh<_Scalar, _Dim, _Chan>::HalfedgeAttribute
271 VGMesh<_Scalar, _Dim, _Chan>::
oppositeAttribute(HalfedgeAttribute attr) const272 oppositeAttribute(HalfedgeAttribute attr) const
273 {
274 switch(attr)
275 {
276 case TO_VERTEX_VALUE:
277 return FROM_VERTEX_VALUE;
278 case FROM_VERTEX_VALUE:
279 return TO_VERTEX_VALUE;
280 case EDGE_VALUE:
281 case EDGE_GRADIENT:
282 return attr;
283 default:
284 break;
285 }
286 abort();
287 }
288
289
290 template < typename _Scalar, int _Dim, int _Chan >
291 typename VGMesh<_Scalar, _Dim, _Chan>::Node
292 VGMesh<_Scalar, _Dim, _Chan>::
halfedgeNode(Halfedge h,HalfedgeAttribute attr) const293 halfedgeNode(Halfedge h, HalfedgeAttribute attr) const
294 {
295 return const_cast<Self*>(this)->halfedgeNode(h, attr);
296 }
297
298
299 template < typename _Scalar, int _Dim, int _Chan >
300 typename VGMesh<_Scalar, _Dim, _Chan>::Node&
301 VGMesh<_Scalar, _Dim, _Chan>::
halfedgeNode(Halfedge h,HalfedgeAttribute attr)302 halfedgeNode(Halfedge h, HalfedgeAttribute attr)
303 {
304 if(attr == FROM_VERTEX_VALUE && !hasFromVertexValue())
305 attr = TO_VERTEX_VALUE;
306
307 assert(hasAttribute(attr));
308 return m_halfedgeAttributes[attr][h];
309 }
310
311
312 template < typename _Scalar, int _Dim, int _Chan >
313 typename VGMesh<_Scalar, _Dim, _Chan>::Node
314 VGMesh<_Scalar, _Dim, _Chan>::
halfedgeOppositeNode(Halfedge h,HalfedgeAttribute attr) const315 halfedgeOppositeNode(Halfedge h, HalfedgeAttribute attr) const
316 {
317 return const_cast<Self*>(this)->halfedgeOppositeNode(h, attr);
318 }
319
320
321 template < typename _Scalar, int _Dim, int _Chan >
322 typename VGMesh<_Scalar, _Dim, _Chan>::Node&
323 VGMesh<_Scalar, _Dim, _Chan>::
halfedgeOppositeNode(Halfedge h,HalfedgeAttribute attr)324 halfedgeOppositeNode(Halfedge h, HalfedgeAttribute attr)
325 {
326 return halfedgeNode(oppositeHalfedge(h), oppositeAttribute(attr));
327 }
328
329
330 template < typename _Scalar, int _Dim, int _Chan >
331 void VGMesh<_Scalar, _Dim, _Chan>::
setGradientConstraint(Vertex v,const Gradient & grad)332 setGradientConstraint(Vertex v, const Gradient& grad)
333 {
334 assert(hasVertexGradientConstraint());
335
336 m_vertexGradientConstraints[v] = grad;
337 }
338
339
340 template < typename _Scalar, int _Dim, int _Chan >
removeGradientConstraint(Vertex v)341 void VGMesh<_Scalar, _Dim, _Chan>::removeGradientConstraint(Vertex v)
342 {
343 assert(hasVertexGradientConstraint());
344
345 m_vertexGradientConstraints.erase(v);
346 }
347
348
349 template < typename _Scalar, int _Dim, int _Chan >
nVertexGradientConstraints(Halfedge h) const350 unsigned VGMesh<_Scalar, _Dim, _Chan>::nVertexGradientConstraints(Halfedge h) const
351 {
352 assert(hasVertexGradientConstraint());
353
354 return isGradientConstraint(fromVertex(h)) + isGradientConstraint(toVertex(h));
355 }
356
357
358 template < typename _Scalar, int _Dim, int _Chan >
nVertexGradientConstraints(Face f) const359 unsigned VGMesh<_Scalar, _Dim, _Chan>::nVertexGradientConstraints(Face f) const
360 {
361 assert(hasVertexGradientConstraint());
362
363 VertexAroundFaceCirculator vit = vertices(f);
364 VertexAroundFaceCirculator vend = vit;
365 unsigned count = 0;
366
367 do
368 {
369 if(isGradientConstraint(*vit)) ++count;
370 ++vit;
371 } while(vit != vend);
372
373 return count;
374 }
375
376
377 template < typename _Scalar, int _Dim, int _Chan >
378 void
deleteUnusedNodes()379 VGMesh<_Scalar, _Dim, _Chan>::deleteUnusedNodes()
380 {
381 for(unsigned i = 0; i < nodesSize(); ++i)
382 {
383 m_ndeleted[Node(i)] = true;
384 }
385
386 HalfedgeIterator hBegin = halfedgesBegin(),
387 hEnd = halfedgesEnd();
388 for(HalfedgeIterator hit = hBegin; hit != hEnd; ++hit)
389 {
390 if(!isBoundary(*hit))
391 {
392 if(hasToVertexValue() && toVertexValueNode(*hit).isValid())
393 m_ndeleted[toVertexValueNode(*hit)] = false;
394 if(hasFromVertexValue() && fromVertexValueNode(*hit).isValid())
395 m_ndeleted[fromVertexValueNode(*hit)] = false;
396 if(hasEdgeValue() && edgeValueNode(*hit).isValid())
397 m_ndeleted[edgeValueNode(*hit)] = false;
398 if(hasEdgeGradient() && edgeGradientNode(*hit).isValid())
399 m_ndeleted[edgeGradientNode(*hit)] = false;
400 }
401 }
402 m_deletedNodes = 0;
403 for(unsigned ni = 0; ni < nodesSize(); ++ni)
404 {
405 if(m_ndeleted[Node(ni)]) ++m_deletedNodes;
406 }
407 if(m_deletedNodes) m_garbage = true;
408 }
409
410
411 template < typename _Scalar, int _Dim, int _Chan >
412 template <typename Derived>
413 typename VGMesh<_Scalar, _Dim, _Chan>::Node
addNode(const Eigen::DenseBase<Derived> & value)414 VGMesh<_Scalar, _Dim, _Chan>::addNode(const Eigen::DenseBase<Derived>& value)
415 {
416 if(nodesCapacity() == nodesSize())
417 {
418 unsigned size = std::max(16u, nodesSize() * 2);
419 resizeNodesMatrix(nCoeffs(), size);
420 }
421 m_nodes.col(nodesSize()) = value;
422 m_nprops.pushBack();
423 assert(nodesSize() <= nodesCapacity());
424 return Node(nodesSize() - 1);
425 }
426
427
428 template < typename _Scalar, int _Dim, int _Chan >
429 bool
hasUnknowns() const430 VGMesh<_Scalar, _Dim, _Chan>::hasUnknowns() const
431 {
432 for(NodeIterator nit = nodesBegin();
433 nit != nodesEnd(); ++nit)
434 if(!isConstraint(*nit))
435 return true;
436 return false;
437 }
438
439
440 template < typename _Scalar, int _Dim, int _Chan >
441 unsigned
nUnknowns() const442 VGMesh<_Scalar, _Dim, _Chan>::nUnknowns() const
443 {
444 unsigned nUnk = 0;
445 for(NodeIterator nit = nodesBegin();
446 nit != nodesEnd(); ++nit)
447 if(!isConstraint(*nit))
448 ++nUnk;
449 return nUnk;
450 }
451
452
453 template < typename _Scalar, int _Dim, int _Chan >
454 void
455 VGMesh<_Scalar, _Dim, _Chan>::
setVertexNodes(Node node,Halfedge from,Halfedge to)456 setVertexNodes(Node node, Halfedge from, Halfedge to)
457 {
458 assert(fromVertex(from) == fromVertex(to));
459 assert(hasToVertexValue());
460
461 Halfedge h = from;
462 do
463 {
464 if(hasFromVertexValue() && !isBoundary(h))
465 {
466 fromVertexValueNode(h) = node;
467 }
468
469 h = prevHalfedge(h);
470
471 if(!isBoundary(h))
472 {
473 toVertexValueNode(h) = node;
474 }
475
476 h = oppositeHalfedge(h);
477 }
478 while(h != to && h != from);
479 }
480
481
482 template < typename _Scalar, int _Dim, int _Chan >
483 void
484 VGMesh<_Scalar, _Dim, _Chan>::
setSingularity(Node fromNode,Node toNode,Halfedge from,Halfedge to)485 setSingularity(Node fromNode, Node toNode, Halfedge from, Halfedge to)
486 {
487 assert(fromVertex(from) == fromVertex(to));
488 assert(hasToVertexValue() && hasFromVertexValue());
489 assert(isConstraint(fromNode) && isConstraint(toNode));
490
491 // Must be copies, not refs because m_nodes can be reallocated.
492 Value fromValue = value(fromNode);
493 Value toValue = value( toNode);
494
495 const Vector& v = position(fromVertex(from));
496 Vector fromVec = position(toVertex(from)) - v;
497 Vector toVec = position(toVertex( to)) - v;
498
499 Scalar fromAngle = std::atan2(fromVec.y(), fromVec.x());
500 Scalar toAngle = std::atan2( toVec.y(), toVec.x());
501 Scalar totalAngle = toAngle - fromAngle;
502 if(totalAngle < Scalar(1.e-8)) totalAngle += Scalar(2.*M_PI);
503
504 Node n = fromNode;
505 Halfedge h = from;
506 Halfedge last = oppositeHalfedge(to);
507 do
508 {
509 if(!isBoundary(h))
510 fromVertexValueNode(h) = n;
511
512 h = prevHalfedge(h);
513
514 if(h != last)
515 {
516 // Current Halfedge is reversed.
517 Vector vec = position(fromVertex(h)) - v;
518 Scalar angle = std::atan2(vec.y(), vec.x()) - fromAngle;
519 if(angle < Scalar(1.e-8)) angle += Scalar(2.*M_PI);
520 Scalar a = angle / totalAngle;
521 n = addNode((Scalar(1)-a) * fromValue + a * toValue);
522 }
523 else
524 n = toNode;
525
526 if(!isBoundary(h))
527 toVertexValueNode(h) = n;
528
529 h = oppositeHalfedge(h);
530 }
531 while(h != to && h != from);
532 }
533
534
535 template < typename _Scalar, int _Dim, int _Chan >
536 void
simplifyConstraints()537 VGMesh<_Scalar, _Dim, _Chan>::simplifyConstraints()
538 {
539 assert(hasToVertexValue());
540
541 std::vector<Halfedge> consEdges;
542 consEdges.reserve(12);
543
544 for(VertexIterator vit = verticesBegin();
545 vit != verticesEnd(); ++vit)
546 {
547 consEdges.clear();
548 findConstrainedEdgesSimplify(*vit, consEdges);
549
550 Halfedge prev = consEdges.back();
551 std::vector<Halfedge>::iterator cit = consEdges.begin();
552 for(; cit != consEdges.end(); ++cit)
553 {
554 simplifyVertexArcConstraints(prev, *cit);
555 prev = *cit;
556 }
557 }
558
559 if(hasEdgeValue() || hasEdgeGradient())
560 {
561 for(EdgeIterator eit = edgesBegin();
562 eit != edgesEnd(); ++eit)
563 {
564 simplifyEdgeConstraints(*eit);
565 }
566 }
567 }
568
569
570 template < typename _Scalar, int _Dim, int _Chan >
571 void
simplifyVertexArcConstraints(Halfedge from,Halfedge to)572 VGMesh<_Scalar, _Dim, _Chan>::simplifyVertexArcConstraints(
573 Halfedge from, Halfedge to)
574 {
575 assert(hasToVertexValue());
576 assert(fromVertex(from) == fromVertex(to));
577
578 Node& n0 = halfedgeNode(from, FROM_VERTEX_VALUE);
579 Node& n1 = halfedgeOppositeNode(to, FROM_VERTEX_VALUE);
580
581 bool n0c = n0.isValid() && isConstraint(n0);
582 bool n1c = n1.isValid() && isConstraint(n1);
583
584 if((!n0c && !n1c) ||
585 (n0c && !n1c) ||
586 (n0c && n1c && value(n0) == value(n1)))
587 {
588 Node& n1o = halfedgeNode(to, FROM_VERTEX_VALUE);
589 if(n1o == n1)
590 {
591 n1o = n0;
592 }
593 n1 = n0;
594 }
595 else if(!n0c && n1c)
596 {
597 Node toReplace = n0;
598 Halfedge h = from;
599 while(true) {
600 Node& n = halfedgeNode(h, FROM_VERTEX_VALUE);
601 if(n == toReplace)
602 n = n1;
603 else
604 break;
605
606 Node& no = halfedgeOppositeNode(h, FROM_VERTEX_VALUE);
607 if(no == toReplace)
608 n = n1;
609 else
610 break;
611
612 h = nextHalfedge(h);
613 }
614 }
615 }
616
617
618 template < typename _Scalar, int _Dim, int _Chan >
619 void
simplifyEdgeConstraints(Edge e)620 VGMesh<_Scalar, _Dim, _Chan>::simplifyEdgeConstraints(Edge e)
621 {
622 Halfedge h0 = halfedge(e, 0);
623 Halfedge h1 = halfedge(e, 1);
624 if(hasEdgeValue())
625 {
626 Node& n0 = edgeValueNode(h0);
627 Node& n1 = edgeValueNode(h1);
628 simplifyOppositeNodes(n0, n1, isBoundary(h0), isBoundary(h1));
629 }
630 if(hasEdgeGradient())
631 {
632 Node& n0 = edgeGradientNode(h0);
633 Node& n1 = edgeGradientNode(h1);
634 simplifyOppositeNodes(n0, n1, isBoundary(h0), isBoundary(h1));
635 }
636 }
637
638
639 template < typename _Scalar, int _Dim, int _Chan >
640 void
simplifyOppositeNodes(Node & n0,Node & n1,bool b0,bool b1) const641 VGMesh<_Scalar, _Dim, _Chan>::simplifyOppositeNodes(Node& n0, Node& n1,
642 bool b0, bool b1) const
643 {
644 bool n0c = !b0 && n0.isValid() && isConstraint(n0);
645 bool n1c = !b1 && n1.isValid() && isConstraint(n1);
646
647 // if not a discontinuity, merge nodes.
648 if(n0c && n1c && value(n0) == value(n1))
649 {
650 if(!b0) n0 = Node(std::min(n1.idx(), n0.idx()));
651 if(!b1) n1 = Node(std::min(n1.idx(), n0.idx()));
652 }
653 else if(!n0c && !n1c && n0 == n1)
654 {
655 // It is useless to use an unknown node here
656 // FIXME: Assume that these unknown node are only used
657 // around this vertex.
658 if(!b0) n0 = Node();
659 if(!b1) n1 = Node();
660 }
661 else if(n0c && !n1.isValid())
662 {
663 if(!b1) n1 = n0;
664 }
665 else if(n1c && !n0.isValid())
666 {
667 if(!b0) n0 = n1;
668 }
669 }
670
671
672 template < typename _Scalar, int _Dim, int _Chan >
673 void
finalize()674 VGMesh<_Scalar, _Dim, _Chan>::finalize()
675 {
676 assert(hasToVertexValue());
677
678 std::vector<Halfedge> consEdges;
679 consEdges.reserve(12);
680
681 for(VertexIterator vit = verticesBegin();
682 vit != verticesEnd(); ++vit)
683 {
684 consEdges.clear();
685 findConstrainedEdgesSimplify(*vit, consEdges);
686
687 if(consEdges.empty())
688 consEdges.push_back(halfedge(*vit));
689
690 Halfedge prev = consEdges.back();
691 std::vector<Halfedge>::iterator cit = consEdges.begin();
692 for(; cit != consEdges.end(); ++cit)
693 {
694 if(!isBoundary(prev))
695 finalizeVertexArc(prev, *cit);
696
697 prev = *cit;
698 }
699 }
700
701 if(hasEdgeValue() || hasEdgeGradient())
702 {
703 for(EdgeIterator eit = edgesBegin();
704 eit != edgesEnd(); ++eit)
705 {
706 finalizeEdge(*eit);
707 }
708 }
709 }
710
711
712 template < typename _Scalar, int _Dim, int _Chan >
713 void
finalizeVertexArc(Halfedge from,Halfedge to)714 VGMesh<_Scalar, _Dim, _Chan>::finalizeVertexArc(Halfedge from, Halfedge to)
715 {
716 Node n0 = halfedgeNode(from, FROM_VERTEX_VALUE);
717 Node n1 = halfedgeOppositeNode(to, FROM_VERTEX_VALUE);
718
719 bool n0c = n0.isValid() && isConstraint(n0);
720 bool n1c = n1.isValid() && isConstraint(n1);
721
722 Node n = Node();
723 if(!n0c && !n1c)
724 {
725 // Free nodes, choose one valid or create a new one.
726 if (n0.isValid()) n = n0;
727 else if(n1.isValid()) n = n1;
728 else n = addNode();
729 }
730 else if(n0c != n1c)
731 n = n0c? n0: n1; // One constraint, choose it
732 else if(n0 == n1 || value(n0) == value(n1))
733 n = n0; // Same constraints, choose one arbitrarily
734
735 // The remaining option is a singularity, that require special
736 // processing.
737 if(isValid(n))
738 setVertexNodes(n, from, to);
739 else
740 setSingularity(n0, n1, from, to);
741 }
742
743
744 template < typename _Scalar, int _Dim, int _Chan >
745 void
finalizeEdge(Edge e)746 VGMesh<_Scalar, _Dim, _Chan>::finalizeEdge(Edge e)
747 {
748 Halfedge h0 = halfedge(e, 0);
749 Halfedge h1 = halfedge(e, 1);
750 if(hasEdgeValue())
751 {
752 Node& n0 = edgeValueNode(h0);
753 Node& n1 = edgeValueNode(h1);
754 bool n0v = n0.isValid();
755 bool n1v = n1.isValid();
756
757 if(!n0v && !isBoundary(h0)) n0 = n1v? n1: addNode();
758 if(!n1v && !isBoundary(h1)) n1 = n0.isValid()? n0: addNode();
759 }
760 if(hasEdgeGradient())
761 {
762 Node& n0 = edgeGradientNode(h0);
763 Node& n1 = edgeGradientNode(h1);
764 bool n0v = n0.isValid();
765 bool n1v = n1.isValid();
766
767 if(!n0v && !isBoundary(h0)) n0 = n1v? n1: addNode();
768 if(!n1v && !isBoundary(h1)) n1 = n0.isValid()? n0: addNode();
769 }
770 }
771
772
773 template < typename _Scalar, int _Dim, int _Chan >
774 bool
isSingular(Halfedge h) const775 VGMesh<_Scalar, _Dim, _Chan>::isSingular(Halfedge h) const
776 {
777 return hasFromVertexValue() &&
778 toVertexValueNode(h) != fromVertexValueNode(nextHalfedge(h));
779 }
780
781
782 template < typename _Scalar, int _Dim, int _Chan >
783 unsigned
nSingulars(Face f) const784 VGMesh<_Scalar, _Dim, _Chan>::nSingulars(Face f) const
785 {
786 unsigned nSingulars = 0;
787 HalfedgeAroundFaceCirculator
788 hit = halfedges(f),
789 hend = hit;
790 do
791 {
792 nSingulars += isSingular(*hit);
793 }
794 while(++hit != hend);
795
796 return nSingulars;
797 }
798
799
800 template < typename _Scalar, int _Dim, int _Chan >
801 unsigned
nSingularFaces() const802 VGMesh<_Scalar, _Dim, _Chan>::nSingularFaces() const
803 {
804 unsigned n = 0;
805 for(FaceIterator fit = facesBegin();
806 fit != facesEnd(); ++fit)
807 {
808 if(nSingulars(*fit))
809 ++n;
810 }
811 return n;
812 }
813
814
815 template < typename _Scalar, int _Dim, int _Chan >
816 void
copyVGMeshMembers(const Self & rhs)817 VGMesh<_Scalar, _Dim, _Chan>::copyVGMeshMembers(const Self& rhs)
818 {
819 m_attributes = rhs.m_attributes;
820
821 m_nprops = rhs.m_nprops;
822
823 m_positions = rhs.m_positions;
824 m_vertexGradientConstraints = rhs.m_vertexGradientConstraints;
825 m_curvedEdges = rhs.m_curvedEdges;
826
827 for(int ai = 0; ai < HALFEDGE_ATTRIB_COUNT; ++ai) {
828 m_halfedgeAttributes[ai] = getHalfedgeProperty<Node>(_halfedgeAttrName[ai]);
829 }
830
831 m_deletedNodes = rhs.m_deletedNodes;
832 m_nodes = rhs.m_nodes/*.template cast<Scalar>()*/;
833 m_ndeleted = nodeProperty<bool>("n:deleted");
834
835 assert(verticesSize() <= positionsCapacity());
836 assert(nodesSize() <= nodesCapacity());
837 }
838
839
840 template < typename _Scalar, int _Dim, int _Chan >
841 void
842 VGMesh<_Scalar, _Dim, _Chan>::
findConstrainedEdgesSimplify(Vertex vx,std::vector<Halfedge> & consEdges)843 findConstrainedEdgesSimplify(Vertex vx,
844 std::vector<Halfedge>& consEdges)
845 {
846 HalfedgeAroundVertexCirculator hit = halfedges(vx),
847 hEnd = hit;
848 do
849 {
850 Node& np = halfedgeOppositeNode(*hit, FROM_VERTEX_VALUE);
851 Node& n0 = halfedgeNode(*hit, FROM_VERTEX_VALUE);
852 bool boundary = isBoundary(edge(*hit));
853 if(np.isValid() || n0.isValid() || boundary)
854 {
855 simplifyOppositeNodes(np, n0, isBoundary(oppositeHalfedge(*hit)),
856 isBoundary(*hit));
857
858 if(np.isValid() || n0.isValid() || boundary)
859 {
860 consEdges.push_back(*hit);
861 }
862 }
863 ++hit;
864 }
865 while(hit != hEnd);
866 }
867
868
869 template < typename _Scalar, int _Dim, int _Chan >
870 void
resizePositionsMatrix(unsigned rows,unsigned cols)871 VGMesh<_Scalar, _Dim, _Chan>::resizePositionsMatrix(unsigned rows, unsigned cols)
872 {
873 VectorMatrix positions(rows, cols);
874 unsigned minRows = std::min(rows, unsigned(m_positions.rows()));
875 unsigned minCols = std::min(cols, unsigned(m_positions.cols()));
876 positions.block(0, 0, minRows, minCols) = m_positions.block(0, 0, minRows, minCols);
877 m_positions.swap(positions);
878 }
879
880
881 template < typename _Scalar, int _Dim, int _Chan >
882 void
resizeNodesMatrix(unsigned rows,unsigned cols)883 VGMesh<_Scalar, _Dim, _Chan>::resizeNodesMatrix(unsigned rows, unsigned cols)
884 {
885 NodeMatrix nodes(rows, cols);
886 unsigned minRows = std::min(rows, unsigned(m_nodes.rows()));
887 unsigned minCols = std::min(cols, unsigned(m_nodes.cols()));
888 nodes.block(0, 0, minRows, minCols) = m_nodes;
889 m_nodes.swap(nodes);
890 }
891
892
893 template < typename _Scalar, int _Dim, int _Chan >
894 const char*
895 VGMesh<_Scalar, _Dim, _Chan>::_halfedgeAttrName[] = {
896 "h:toVertexValueNode",
897 "h:fromVertexValueNode",
898 "h:edgeValueNode",
899 "h:edgeGradientNode"
900 };
901
902
903
904 } // namespace Vitelotte
905