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