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