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 "dcMesh.h"
8 
9 
10 namespace Vitelotte
11 {
12 
13 
14 template <typename _Value>
15 typename PiecewiseLinearFunction<_Value>::Value
operator ()(float x) const16     PiecewiseLinearFunction<_Value>::operator()(float x) const
17 {
18     assert(!empty());
19 
20     if(x <= m_samples.begin()->first)
21         return m_samples.begin()->second;
22     if(x >= m_samples.rbegin()->first)
23         return m_samples.rbegin()->second;
24 
25     ConstIterator next = m_samples.upper_bound(x);
26     ConstIterator prev = next;
27     --next;
28 
29     float alpha = (x - prev->first) / (next->first - prev->first);
30     return (1 - alpha) * prev->second + alpha * next->second;
31 }
32 
33 
34 template < typename _Scalar, int _Dim, int _Chan >
DCMesh()35 DCMesh<_Scalar, _Dim, _Chan>::DCMesh()
36 {
37     m_pointConstraintConn = Base::template addVertexProperty<PointConstraint>(
38                                                 "v:pointConstraintConnectivity");
39     m_halfedgeCurveConn = Base::template addHalfedgeProperty<HalfedgeCurveConnectivity>(
40                                                 "h:curveConnectivity");
41 }
42 
43 
44 template < typename _Scalar, int _Dim, int _Chan >
DCMesh(unsigned nDims,unsigned nCoeffs)45 DCMesh<_Scalar, _Dim, _Chan>::DCMesh(unsigned nDims, unsigned nCoeffs)
46     : Base(nDims, nCoeffs, 0)
47 {
48     m_pointConstraintConn = Base::template addVertexProperty<PointConstraint>(
49                                                 "v:pointConstraintConnectivity");
50     m_halfedgeCurveConn = Base::template addHalfedgeProperty<HalfedgeCurveConnectivity>(
51                                                 "h:curveConnectivity");
52 }
53 
54 
55 template < typename _Scalar, int _Dim, int _Chan >
DCMesh(const DCMesh & other)56 DCMesh<_Scalar, _Dim, _Chan>::DCMesh(const DCMesh& other)
57     : Base(other)
58 {
59     copyVGMeshWithCurvesMembers(other);
60 }
61 
62 
63 template < typename _Scalar, int _Dim, int _Chan >
64 DCMesh<_Scalar, _Dim, _Chan>&
operator =(const DCMesh & other)65 DCMesh<_Scalar, _Dim, _Chan>::operator=(const DCMesh& other)
66 {
67     if(&other == this) return *this;
68 
69     Base::operator=(other);
70     copyVGMeshWithCurvesMembers(other);
71 
72     return *this;
73 }
74 
75 
76 template < typename _Scalar, int _Dim, int _Chan >
77 DCMesh<_Scalar, _Dim, _Chan>&
assign(const DCMesh & other)78 DCMesh<_Scalar, _Dim, _Chan>::assign(const DCMesh& other)
79 {
80     if(&other == this) return *this;
81 
82     Base::assign(other);
83     copyVGMeshWithCurvesMembers(other);
84 
85     return *this;
86 }
87 
88 
89 template < typename _Scalar, int _Dim, int _Chan >
90 typename DCMesh<_Scalar, _Dim, _Chan>::Curve
addCurve(unsigned flags)91 DCMesh<_Scalar, _Dim, _Chan>::addCurve(unsigned flags)
92 {
93     Curve c(nCurves());
94     CurveInfo ci;
95     ci.flags = flags;
96     m_curves.push_back(ci);
97     return c;
98 }
99 
100 
101 template < typename _Scalar, int _Dim, int _Chan >
102 void
addHalfedgeToCurve(Curve c,Halfedge h,float from,float to)103 DCMesh<_Scalar, _Dim, _Chan>::addHalfedgeToCurve(Curve c, Halfedge h, float from, float to)
104 {
105     assert(isValid(c));
106     assert(isValid(h));
107 
108     CurveInfo& ci = m_curves[c.idx()];
109     HalfedgeCurveConnectivity& hcc = m_halfedgeCurveConn[h];
110     HalfedgeCurveConnectivity& ohcc = m_halfedgeCurveConn[oppositeHalfedge(h)];
111 
112     assert(!hcc.curve.isValid());
113     assert(!ohcc.curve.isValid());
114 
115     hcc.curve = c;
116     hcc.pos = to;
117     ohcc.curve = c;
118     ohcc.pos = from;
119     if(ci.firstHalfedge.isValid())
120     {
121         assert(ci.lastHalfedge.isValid());
122         HalfedgeCurveConnectivity& phcc = m_halfedgeCurveConn[ci.lastHalfedge];
123 
124         phcc.next = h;
125         ohcc.next = ci.lastHalfedge;
126         ci.lastHalfedge = h;
127     }
128     else
129     {
130         ci.firstHalfedge = h;
131         ci.lastHalfedge = h;
132     }
133 }
134 
135 
136 template < typename _Scalar, int _Dim, int _Chan >
137 void
setFlags(Curve c,unsigned flags)138 DCMesh<_Scalar, _Dim, _Chan>::setFlags(Curve c, unsigned flags)
139 {
140     assert(isValid(c));
141 
142     CurveInfo& ci = m_curves[c.idx()];
143     if(flags & VALUE_TEAR && !(ci.flags & VALUE_TEAR))
144         ci.gradient[VALUE_RIGHT] = ci.gradient[VALUE_LEFT];
145     if(flags & GRADIENT_TEAR && !(ci.flags & GRADIENT_TEAR))
146         ci.gradient[GRADIENT_RIGHT] = ci.gradient[GRADIENT_LEFT];
147     ci.flags = flags;
148 }
149 
150 
151 template < typename _Scalar, int _Dim, int _Chan >
152 void
setFlagsRaw(Curve c,unsigned flags)153 DCMesh<_Scalar, _Dim, _Chan>::setFlagsRaw(Curve c, unsigned flags)
154 {
155     assert(isValid(c));
156 
157     CurveInfo& ci = m_curves[c.idx()];
158     ci.flags = flags;
159 }
160 
161 
162 template < typename _Scalar, int _Dim, int _Chan >
163 const typename DCMesh<_Scalar, _Dim, _Chan>::ValueFunction&
valueFunction(Curve c,unsigned which) const164 DCMesh<_Scalar, _Dim, _Chan>::valueFunction(Curve c, unsigned which) const
165 {
166     return const_cast<DCMesh*>(this)->valueFunction(c, which);
167 }
168 
169 
170 template < typename _Scalar, int _Dim, int _Chan >
171 typename DCMesh<_Scalar, _Dim, _Chan>::ValueFunction&
valueFunction(Curve c,unsigned which)172 DCMesh<_Scalar, _Dim, _Chan>::valueFunction(Curve c, unsigned which)
173 {
174     assert(isValid(c));
175     assert(which < 4);
176 
177     switch(which)
178     {
179     case VALUE_RIGHT:
180         if(!valueTear(c))
181             which = VALUE_LEFT;
182         break;
183     case GRADIENT_RIGHT:
184         if(!gradientTear(c))
185             which = GRADIENT_LEFT;
186         break;
187     }
188 
189     return m_curves[c.idx()].gradient[which];
190 }
191 
192 
193 template < typename _Scalar, int _Dim, int _Chan >
194 const typename DCMesh<_Scalar, _Dim, _Chan>::ValueFunction&
valueFunctionRaw(Curve c,unsigned which) const195 DCMesh<_Scalar, _Dim, _Chan>::valueFunctionRaw(Curve c, unsigned which) const
196 {
197     return const_cast<DCMesh*>(this)->valueFunctionRaw(c, which);
198 }
199 
200 
201 template < typename _Scalar, int _Dim, int _Chan >
202 typename DCMesh<_Scalar, _Dim, _Chan>::ValueFunction&
valueFunctionRaw(Curve c,unsigned which)203 DCMesh<_Scalar, _Dim, _Chan>::valueFunctionRaw(Curve c, unsigned which)
204 {
205     assert(isValid(c));
206     assert(which < 4);
207 
208     return m_curves[c.idx()].gradient[which];
209 }
210 
211 
212 template < typename _Scalar, int _Dim, int _Chan >
213 void
setVertex(PointConstraint pc,Vertex vx)214 DCMesh<_Scalar, _Dim, _Chan>::setVertex(PointConstraint pc, Vertex vx) {
215     assert(!m_pointConstraintConn[vx].isValid());
216     if(vertex(pc).isValid()) {
217         m_pointConstraintConn[vertex(pc)] = PointConstraint();
218     }
219     m_pointConstraints[pc.idx()].vertex = vx;
220     m_pointConstraintConn[vx] = pc;
221 }
222 
223 
224 template < typename _Scalar, int _Dim, int _Chan >
225 typename DCMesh<_Scalar, _Dim, _Chan>::PointConstraint
addPointConstraint(Vertex vx)226 DCMesh<_Scalar, _Dim, _Chan>::addPointConstraint(Vertex vx)
227 {
228     PointConstraint pc(nPointConstraints());
229     PointConstraintInfo pci;
230     pci.value = unconstrainedValue();
231     pci.gradient = unconstrainedGradientValue();
232     m_pointConstraints.push_back(pci);
233     setVertex(pc, vx);
234     return pc;
235 }
236 
237 
238 template < typename _Scalar, int _Dim, int _Chan >
239 void
clear()240 DCMesh<_Scalar, _Dim, _Chan>::clear()
241 {
242     Base::clear();
243     m_pointConstraints.clear();
244     m_curves.clear();
245 }
246 
247 
248 template < typename _Scalar, int _Dim, int _Chan >
249 void
setNodesFromCurves()250 DCMesh<_Scalar, _Dim, _Chan>::setNodesFromCurves()
251 {
252     m_nprops.resize(0);
253     for(HalfedgeIterator hit = halfedgesBegin();
254         hit != halfedgesEnd(); ++hit)
255     {
256         if(hasFromVertexValue())    fromVertexValueNode(*hit)   = Node();
257         if(hasToVertexValue())      toVertexValueNode(*hit)     = Node();
258         if(hasEdgeValue())          edgeValueNode(*hit)         = Node();
259         if(hasEdgeGradient())       edgeGradientNode(*hit)      = Node();
260     }
261     if(hasVertexGradientConstraint()) {
262         for(VertexIterator vit = verticesBegin();
263             vit != verticesEnd(); ++vit)
264         {
265             if(isGradientConstraint(*vit))
266             {
267                 removeGradientConstraint(*vit);
268             }
269         }
270     }
271 
272     for(unsigned pci = 0; pci < nPointConstraints(); ++pci)
273     {
274         PointConstraint pc(pci);
275         Vertex vx = vertex(pc);
276         assert(isValid(vx));
277 
278         Node vn;
279         if(isValueConstraint(pc))
280             vn = addNode(value(pc));
281 
282         HalfedgeAroundVertexCirculator hit = halfedges(vx);
283         HalfedgeAroundVertexCirculator hend = hit;
284         do {
285             Halfedge opp = oppositeHalfedge(*hit);
286             if(isValueConstraint(pc))
287             {
288                 if(!isBoundary(*hit))
289                     halfedgeNode(*hit, Base::FROM_VERTEX_VALUE) = vn;
290                 if(!isBoundary(opp))
291                     halfedgeOppositeNode(*hit, Base::FROM_VERTEX_VALUE) = vn;
292             }
293             ++hit;
294         } while(hit != hend);
295 
296         if(hasVertexGradientConstraint() && isGradientConstraint(pc))
297         {
298             setGradientConstraint(vertex(pc), gradient(pc));
299         }
300     }
301 
302     for(unsigned ci = 0; ci < nCurves(); ++ci)
303     {
304         Curve c(ci);
305 
306         Halfedge lh = firstHalfedge(c);
307         if(!lh.isValid())
308             continue;
309 
310         const BezierPath& path = bezierPath(c);
311         unsigned si = 0;
312         Scalar splitPos = 0;
313         CurvedEdge head;
314         CurvedEdge tail = path.nSegments()? path.getSegment(si): CurvedEdge();
315 
316         Node fromNode[2];
317         addGradientNodes(fromNode, c, VALUE, fromCurvePos(lh));
318         do {
319             Node toNode[2];
320             addGradientNodes(toNode, c, VALUE, toCurvePos(lh));
321 
322             Halfedge rh = oppositeHalfedge(lh);
323             float midPos = (fromCurvePos(lh) + toCurvePos(lh)) / 2.f;
324 
325             bool lhnb = !isBoundary(lh);
326             bool rhnb = !isBoundary(rh);
327 
328             if(hasFromVertexValue())
329             {
330                 if(lhnb) fromVertexValueNode(lh) = fromNode[LEFT];
331                 if(rhnb) fromVertexValueNode(rh) =   toNode[RIGHT];
332             }
333             if(hasToVertexValue())
334             {
335                 if(lhnb) toVertexValueNode(lh) =   toNode[LEFT];
336                 if(rhnb) toVertexValueNode(rh) = fromNode[RIGHT];
337             }
338 
339             if(hasEdgeValue())
340             {
341                 Node midNode[2];
342                 addGradientNodes(midNode, c, VALUE, midPos);
343                 if(lhnb) edgeValueNode(lh) = midNode[LEFT];
344                 if(rhnb) edgeValueNode(rh) = midNode[RIGHT];
345             }
346 
347             if(hasEdgeGradient())
348             {
349                 Node gNode[2];
350                 addGradientNodes(gNode, c, GRADIENT, midPos);
351                 if(lhnb) edgeGradientNode(lh) = gNode[LEFT];
352                 if(rhnb) edgeGradientNode(rh) = gNode[RIGHT];
353 
354                 if(halfedgeOrientation(lh) && lhnb)
355                     value(gNode[LEFT]) *= -1;
356                 if(gNode[LEFT] != gNode[RIGHT] && halfedgeOrientation(lh) && rhnb)
357                     value(gNode[RIGHT]) *= -1;
358 
359             }
360 
361             if(tail.type() != BEZIER_EMPTY) {
362                 Scalar csi;
363                 Scalar curvePos = std::modf(toCurvePos(lh) * path.nSegments() + 1.e-5, &csi);
364 
365                 if(unsigned(csi) == si) {
366                     Scalar pos = (curvePos - splitPos) / (1 - splitPos);
367                     tail.split(pos, head, tail);
368                     setEdgeCurve(lh, head);
369                     splitPos = curvePos;
370                 } else {
371                     setEdgeCurve(lh, tail);
372                     ++si;
373                     tail = (si < path.nSegments())?
374                                 path.getSegment(si):
375                                 CurvedEdge();
376                     splitPos = 0;
377                 }
378             }
379 
380 
381             fromNode[0] = toNode[0];
382             fromNode[1] = toNode[1];
383             lh = nextCurveHalfedge(lh);
384         } while(lh.isValid());
385     }
386 }
387 
388 
389 template < typename _Scalar, int _Dim, int _Chan >
390 typename DCMesh<_Scalar, _Dim, _Chan>::Value
evalValueFunction(Curve c,unsigned which,float pos) const391 DCMesh<_Scalar, _Dim, _Chan>::evalValueFunction(
392         Curve c, unsigned which, float pos) const
393 {
394     return valueFunction(c, which)(pos);
395 }
396 
397 
398 template < typename _Scalar, int _Dim, int _Chan >
399 void
copyVGMeshWithCurvesMembers(const DCMesh & other)400 DCMesh<_Scalar, _Dim, _Chan>::copyVGMeshWithCurvesMembers(const DCMesh& other)
401 {
402     m_pointConstraintConn = Base::template vertexProperty<PointConstraint>(
403                                                 "v:pointConstraintConnectivity");
404     m_halfedgeCurveConn   = Base::template halfedgeProperty<HalfedgeCurveConnectivity>(
405                                                 "h:curveConnectivity");
406 
407     m_pointConstraints = other.m_pointConstraints;
408     m_curves = other.m_curves;
409 }
410 
411 
412 template < typename _Scalar, int _Dim, int _Chan >
413 void
addGradientNodes(Node nodes[2],Curve c,unsigned gType,float pos)414 DCMesh<_Scalar, _Dim, _Chan>::addGradientNodes(
415         Node nodes[2], Curve c, unsigned gType, float pos)
416 {
417     bool tear = (gType == VALUE)? valueTear(c): gradientTear(c);
418 
419     nodes[LEFT] = valueFunction(c, gType | LEFT).empty()?
420                 addNode():
421                 addNode(evalValueFunction(c, gType | LEFT, pos));
422     nodes[RIGHT] =
423             (!tear)?
424                 nodes[LEFT]:
425                 valueFunction(c, gType | RIGHT).empty()?
426                             addNode():
427                             addNode(evalValueFunction(c, gType | RIGHT, pos));
428 }
429 
430 
431 }
432