VCG Library
Loading...
Searching...
No Matches
curve_on_manifold.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_CURVE_ON_SURF_H
24#define __VCGLIB_CURVE_ON_SURF_H
25
26#include<cstdio>
27#include<vcg/complex/complex.h>
28#include<vcg/simplex/face/topology.h>
29#include<vcg/complex/algorithms/update/topology.h>
30#include<vcg/complex/algorithms/update/color.h>
31#include<vcg/complex/algorithms/update/normal.h>
32#include<vcg/complex/algorithms/update/quality.h>
33#include<vcg/complex/algorithms/clean.h>
34#include<vcg/complex/append.h>
35#include<vcg/complex/algorithms/mesh_assert.h>
36#include<vcg/complex/algorithms/update/bounding.h>
37#include<vcg/complex/algorithms/vertex_interpolation.h>
38#include<vcg/complex/algorithms/point_sampling.h>
39#include <vcg/space/index/grid_static_ptr.h>
40#include <vcg/math/histogram.h>
41#include<vcg/space/distance3.h>
42#include <wrap/callback.h>
43#include <vcg/space/planar_polygon_tessellation.h>
44#include <array>
45#include <deque>
46#include <map>
47#include <set>
48
49namespace vcg {
50namespace tri {
53
118template <class MeshType> class CoMEmbed;
119
120template <class MeshType>
121class CoM
122{
123public:
124 typedef typename MeshType::ScalarType ScalarType;
125 typedef typename MeshType::CoordType CoordType;
126 typedef typename MeshType::VertexType VertexType;
127 typedef typename MeshType::VertexPointer VertexPointer;
128 typedef typename MeshType::VertexIterator VertexIterator;
129 typedef typename MeshType::EdgeIterator EdgeIterator;
130 typedef typename MeshType::EdgeType EdgeType;
131 typedef typename MeshType::FaceType FaceType;
132 typedef typename MeshType::FacePointer FacePointer;
133 typedef typename MeshType::FaceIterator FaceIterator;
134 typedef Segment3<ScalarType> Segment3Type;
135 typedef typename vcg::GridStaticPtr<FaceType, ScalarType> MeshGrid;
136
144 class Param
145 {
146 public:
147
148 ScalarType surfDistThr;
149 ScalarType minRefEdgeLen;
150 ScalarType maxSimpEdgeLen;
151 ScalarType maxMoveDelta;
152 ScalarType maxSnapThr;
153 ScalarType gridBailout;
155 vcg::CallBackPos *cb = nullptr;
156
158 Param(MeshType &m) { SetDefault(m);}
159
161 void SetDefault(MeshType &m)
162 {
163 surfDistThr = m.bbox.Diag()/1000.0;
164 minRefEdgeLen = m.bbox.Diag()/16000.0;
165 maxSimpEdgeLen = m.bbox.Diag()/100.0;
166 maxMoveDelta = m.bbox.Diag()/100.0;
167 maxSnapThr = m.bbox.Diag()/10000.0;
168 gridBailout = m.bbox.Diag()/20.0;
169 barycentricSnapThr = 0.05;
170 }
171
173 void Dump() const
174 {
175 printf("surfDistThr = %6.4f\n",surfDistThr );
176 printf("minRefEdgeLen = %6.4f\n",minRefEdgeLen );
177 printf("maxSimpEdgeLen = %6.4f\n",maxSimpEdgeLen );
178 printf("maxMoveDelta = %6.4f\n",maxMoveDelta);
179 }
180 };
181
182
183
184 // ============================================================================
185 // Data Members
186 // ============================================================================
187
188 MeshType &base;
189 MeshGrid uniformGrid;
191
195 CoM(MeshType &_m) :base(_m),par(BoxUpdated(_m)){}
196
197private:
198 static MeshType &BoxUpdated(MeshType &m) { tri::UpdateBounding<MeshType>::Box(m); return m; }
199
200 template <class> friend class CoMEmbed;
201
202 int progress = 0;
203
205 template <class... Args>
206 void Progress(int pos, const char *fmt, Args... args)
207 {
208 progress = pos;
209 Log(fmt, args...);
210 }
211
214 template <class... Args>
215 void Log(const char *fmt, Args... args)
216 {
217 if (!par.cb) return;
218 char msg[256];
219 snprintf(msg, sizeof(msg), fmt, args...);
220 par.cb(progress, msg);
221 }
222
226 FaceType *Closest(const CoordType &p, CoordType &closestP, ScalarType &closestDist)
227 {
228 FaceType *f = vcg::tri::GetClosestFaceBase(base, uniformGrid, p, par.gridBailout, closestDist, closestP);
229 if (f == nullptr) {
230 char msg[256];
231 snprintf(msg, sizeof(msg), "CoM: no face of the base mesh within %g (Param::gridBailout) of the point (%g, %g, %g); the curve is too far from the surface.",
232 double(par.gridBailout), double(p[0]), double(p[1]), double(p[2]));
233 throw vcg::MissingPreconditionException(msg);
234 }
235 return f;
236 }
237
238public:
239
240 // ============================================================================
241 // Spatial Query Methods
242 // ============================================================================
243
251 FaceType *GetClosestFace(const CoordType &p)
252 {
253 ScalarType closestDist;
254 CoordType closestP;
255 return Closest(p, closestP, closestDist);
256 }
257
264 FaceType *GetClosestFaceIP(const CoordType &p, CoordType &ip)
265 {
266 ScalarType closestDist;
267 CoordType closestP;
268 FaceType *f = Closest(p, closestP, closestDist);
269 InterpolationParameters(*f, f->N(), closestP, ip);
270 return f;
271 }
272
280 FaceType *GetClosestFaceIP(const CoordType &p, CoordType &ip, CoordType &in)
281 {
282 FaceType *f = GetClosestFaceIP(p, ip);
283 in = f->V(0)->cN()*ip[0] + f->V(1)->cN()*ip[1] + f->V(2)->cN()*ip[2];
284 return f;
285 }
286
293 FaceType *GetClosestFacePoint(const CoordType &p, CoordType &closestP)
294 {
295 ScalarType closestDist;
296 return Closest(p, closestP, closestDist);
297 }
298
299 // ============================================================================
300 // Barycentric Coordinate and Snapping Methods
301 // ============================================================================
302
312 bool IsSnappedEdge(CoordType &ip, int &ei)
313 {
314 for(int i=0;i<3;++i)
315 if(ip[i]>0.0 && ip[(i+1)%3]>0.0 && ip[(i+2)%3]==0.0 ) {
316 ei=i;
317 return true;
318 }
319 ei=-1;
320 return false;
321 }
322
329 bool IsSnappedVertex(CoordType &ip, int &vi)
330 {
331 for(int i=0;i<3;++i)
332 if(ip[i]==1.0 && ip[(i+1)%3]==0.0 && ip[(i+2)%3]==0.0 ) {
333 vi=i;
334 return true;
335 }
336 vi=-1;
337 return false;
338 }
339
346 VertexPointer FindVertexSnap(FacePointer fp, CoordType &ip)
347 {
348 for(int i=0;i<3;++i)
349 if(ip[i]==1.0 && ip[(i+1)%3]==0.0 && ip[(i+2)%3]==0.0 ) return fp->V(i);
350 return 0;
351 }
352
353
354
355 // ============================================================================
356 // Utility Functions
357 // ============================================================================
358
371 bool SnapPolyline(MeshType &poly)
372 {
375 // Where each vertex would snap.
376 std::vector<FaceType *> face(poly.vert.size());
377 std::vector<CoordType> ip(poly.vert.size()), raw(poly.vert.size());
378 std::map<VertexType *, std::vector<size_t>> onVertex; // mesh vertex -> polyline vertices
379 for (size_t i = 0; i < poly.vert.size(); ++i)
380 {
381 face[i] = GetClosestFaceIP(poly.vert[i].cP(), raw[i]);
382 ip[i] = raw[i];
383 // A control point is not snapped; one already on a mesh vertex occupies it.
384 if (poly.vert[i].IsS()) RoundingSnap(ip[i], *face[i]);
385 else BarycentricSnap(ip[i], *face[i]);
386 if (VertexPointer v = FindVertexSnap(face[i], ip[i])) onVertex[v].push_back(i);
387 }
388 // A mesh vertex takes one polyline vertex: the nearest, with the ones joined to it by
389 // polyline edges (they will collapse onto it). The others stay off it, on an edge if
390 // they may snap there, so two strands passing by the same vertex are not merged.
391 int deniedCnt = 0;
392 for (auto &ov : onVertex)
393 {
394 if (ov.second.size() < 2) continue;
395 std::sort(ov.second.begin(), ov.second.end(), [&](size_t a, size_t b) {
396 if (poly.vert[a].IsS() != poly.vert[b].IsS()) return poly.vert[a].IsS(); // a control point first
397 return Distance(poly.vert[a].cP(), ov.first->cP()) < Distance(poly.vert[b].cP(), ov.first->cP()); });
398 std::set<size_t> kept{ov.second[0]};
399 for (bool grew = true; grew; ) // the nearest and what is joined to it along the polyline
400 {
401 grew = false;
402 for (size_t c : ov.second)
403 {
404 if (kept.count(c)) continue;
405 std::vector<VertexPointer> star;
406 edge::VVStarVE(&poly.vert[c], star);
407 for (VertexPointer w : star)
408 if (kept.count(tri::Index(poly, w))) { kept.insert(c); grew = true; break; }
409 }
410 }
411 for (size_t c : ov.second)
412 {
413 if (kept.count(c) || poly.vert[c].IsS()) continue;
414 // Only onto the nearest edge, if that snap alone is allowed.
415 ++deniedCnt;
416 CoordType &q = ip[c];
417 q = raw[c];
418 const int k = (q[0] <= q[1] && q[0] <= q[2]) ? 0 : (q[1] <= q[2] ? 1 : 2);
419 const FaceType &f = *face[c];
420 const ScalarType len = Distance(f.cP((k + 1) % 3), f.cP((k + 2) % 3));
421 if (q[k] <= par.barycentricSnapThr && len > 0 && q[k] * (DoubleArea(f) / len) <= par.maxSnapThr)
422 {
423 q[k] = 0;
424 q[(k + 1) % 3] /= q[(k + 1) % 3] + q[(k + 2) % 3];
425 q[(k + 2) % 3] = 1 - q[(k + 1) % 3];
426 }
427 }
428 }
429 int vertSnapCnt=0, edgeSnapCnt=0;
430 for (size_t i = 0; i < poly.vert.size(); ++i)
431 {
432 if (poly.vert[i].IsS()) continue; // control points stay where they are
433 int zeros = 0;
434 for (int k = 0; k < 3; ++k) zeros += ip[i][k] == 0;
435 if (zeros == 0) continue;
436 const FaceType &f = *face[i];
437 poly.vert[i].P() = f.cP(0)*ip[i][0] + f.cP(1)*ip[i][1] + f.cP(2)*ip[i][2];
438 if (zeros == 2) vertSnapCnt++; else edgeSnapCnt++;
439 }
440 const int dupCnt = CollapseNullEdges(poly);
441 Log("SnapPolyline %i vertices: snapped %i onto vertices and %i onto edges, %i kept off an occupied vertex, %i null edges collapsed",
442 poly.vn, vertSnapCnt, edgeSnapCnt, deniedCnt, dupCnt);
443 return vertSnapCnt==0 && edgeSnapCnt==0 && dupCnt==0;
444 }
445
448 {
451 Selected
452 };
453
462 void SetControlPoints(MeshType &poly, ControlPoints mode = EndsAndNodes)
463 {
464 if (mode == Selected) return;
466 ForEachVertex(poly, [&](VertexType &v) {
467 const int deg = edge::VEDegree<EdgeType>(&v);
468 if (mode == AllVertices || deg != 2) v.SetS(); else v.ClearS();
469 });
470 }
471
482 int ConnectCrossings(MeshType &poly)
483 {
484 std::map<CoordType, int> count;
485 for (const VertexType &v : poly.vert) if (!v.IsD()) ++count[v.cP()];
489 // Where the merged strands now branch it is a junction; where they only ran together
490 // (an overlapping stretch) the vertex is an ordinary one.
492 int junctions = 0;
493 for (VertexType &v : poly.vert)
494 if (count[v.cP()] > 1 && edge::VEDegree<EdgeType>(&v) > 2) { v.SetS(); ++junctions; }
495 return junctions;
496 }
497
498
499 void SelectUniformlyDistributed(MeshType &poly, int k)
500 {
502 ScalarType samplingRadius = tri::Stat<MeshType>::ComputeEdgeLengthSum(poly)/ScalarType(k);
503 tri::SurfaceSampling<MeshType, typename tri::TrivialPointerSampler<MeshType> >::EdgeMeshUniform(poly,tps,samplingRadius);
504 for(int i=0;i<tps.sampleVec.size();++i)
505 tps.sampleVec[i]->SetS();
506 }
507
508
509
510 /*
511 * Make an edge mesh 1-manifold by splitting all the
512 * vertexes that have more than two incident edges
513 *
514 * It performs the split in three steps.
515 * - First it collects and counts the vertices to be splitten.
516 * - Then it adds the vertices to the mesh and
517 * - lastly it updates the poly with the newly added vertices.
518 *
519 * singSplitFlag allows to ubersplit each singularity in a number of vertex of the same order of its degree.
520 * This is not really necessary but helps the management of sharp turns in the poly mesh.
521 * \todo add corner detection and split.
522 */
523
524 void DecomposeNonManifoldPolyline(MeshType &poly, bool singSplitFlag = true)
525 {
527 std::vector<int> degreeVec(poly.vn, 0);
529 int neededVert=0;
530 int delta;
531 if(singSplitFlag) delta = 1;
532 else delta = 2;
533
534 for(VertexIterator vi=poly.vert.begin(); vi!=poly.vert.end();++vi)
535 {
536 std::vector<EdgeType *> starVec;
537 edge::VEStarVE(&*vi,starVec);
538 degreeVec[tri::Index(poly, *vi)] = starVec.size();
539 if(starVec.size()>2)
540 neededVert += starVec.size()-delta;
541 }
542 Log("DecomposeNonManifold Adding %i vert to a polyline of %i vert",neededVert,poly.vn);
543 VertexIterator firstVi = tri::Allocator<MeshType>::AddVertices(poly,neededVert);
544
545 for(size_t i=0;i<degreeVec.size();++i)
546 {
547 if(degreeVec[i]>2)
548 {
549 std::vector<EdgeType *> edgeStarVec;
550 edge::VEStarVE(&(poly.vert[i]),edgeStarVec);
551 assert(edgeStarVec.size() == degreeVec[i]);
552 for(size_t j=delta;j<edgeStarVec.size();++j)
553 {
554 EdgeType *ep = edgeStarVec[j];
555 int ind; // index of the vertex to be changed
556 if(tri::Index(poly,ep->V(0)) == i) ind = 0;
557 else ind = 1;
558
559 ep->V(ind) = &*firstVi;
560 ep->V(ind)->P() = poly.vert[i].P();
561 ep->V(ind)->N() = poly.vert[i].N();
562 ++firstVi;
563 }
564 }
565 }
566 assert(firstVi == poly.vert.end());
567 }
568
569 // ============================================================================
570 // Initialization
571 // ============================================================================
572
585 void Init()
586 {
587 if (base.fn == 0)
588 throw vcg::MissingPreconditionException("CoM: the base mesh has no faces.");
591 MeshAssert<MeshType>::FFTwoManifoldEdge(base);
592 // A zero-area face has no barycentric coordinates: the closest-point query either
593 // misses it or returns uninitialized ones, which the snapping then trusts.
594 MeshAssert<MeshType>::NoZeroAreaFace(base);
595 // Construction of the uniform grid
596 uniformGrid.Set(base.face.begin(), base.face.end());
597 }
598
599 // ============================================================================
600 // Simplification Methods
601 // ============================================================================
602
609 void SimplifyNullEdges(MeshType &poly)
610 {
611 int cnt=CollapseNullEdges(poly);
612 if(cnt)
613 Log("SimplifyNullEdges: Collapsed %i zero-length edges",cnt);
614 }
615
625 int CollapseNullEdges(MeshType &poly)
626 {
628 int cnt = 0;
629 for (bool changed = true; changed; )
630 {
631 changed = false;
632 for (size_t i = 0; i < poly.edge.size(); ++i)
633 {
634 EdgeType &e = poly.edge[i];
635 if (e.IsD() || e.V(0)->cP() != e.V(1)->cP()) continue;
636 if (e.V(0) == e.V(1)) { edge::VEDetach(e); tri::Allocator<MeshType>::DeleteEdge(poly, e); }
637 else edge::VEEdgeCollapseToVertex(poly, &e, e.V(1)->IsS() && !e.V(0)->IsS() ? 1 : 0); // keep a control point
638 ++cnt;
639 changed = true;
640 }
641 }
644 return cnt;
645 }
646 void Simplify(MeshType &poly)
647 {
648 int startEn = poly.en;
649 Distribution<ScalarType> hist;
650 for(int i =0; i<poly.en;++i)
651 hist.Add(edge::Length(poly.edge[i]));
652
654
655 for(int i =0; i<poly.vn;++i)
656 {
657 std::vector<VertexPointer> starVecVp;
658 edge::VVStarVE(&(poly.vert[i]),starVecVp);
659 if ((starVecVp.size()==2) && (!poly.vert[i].IsS()))
660 {
661 ScalarType newSegLen = Distance(starVecVp[0]->P(), starVecVp[1]->P());
662 Segment3Type seg(starVecVp[0]->P(),starVecVp[1]->P());
663 ScalarType segDist;
664 CoordType closestPSeg;
665 SegmentPointDistance(seg,poly.vert[i].cP(),closestPSeg,segDist);
666 CoordType fp,fn;
667 ScalarType maxSurfDist = MaxSegDist(starVecVp[0], starVecVp[1],fp,fn);
668
669 if((maxSurfDist < par.surfDistThr) && (newSegLen < par.maxSimpEdgeLen) )
670 {
671 edge::VEEdgeCollapse(poly,&(poly.vert[i]));
672 }
673 }
674 }
676 tri::Allocator<MeshType>::CompactEveryVector(poly);
678// printf("Simplify %5i -> %5i (total len %5.2f)\n",startEn,poly.en,hist.Sum());
679 }
680
681 void EvaluateHausdorffDistance(MeshType &poly, Distribution<ScalarType> &dist)
682 {
683 dist.Clear();
684 tri::UpdateTopology<MeshType>::VertexEdge(poly);
686 for(int i =0; i<poly.edge.size();++i)
687 {
688 CoordType farthestP, farthestN;
689 ScalarType maxDist = MaxSegDist(poly.edge[i].V(0),poly.edge[i].V(1), farthestP, farthestN, &dist);
690 poly.edge[i].V(0)->Q()+= maxDist;
691 poly.edge[i].V(1)->Q()+= maxDist;
692 }
693 for(int i=0;i<poly.vn;++i)
694 {
695 ScalarType deg = edge::VEDegree<EdgeType>(&poly.vert[i]);
696 poly.vert[i].Q()/=deg;
697 }
699 }
700
701
718 bool BarycentricSnap(CoordType &ip, const FaceType &f)
719 {
721 }
722
724 static bool BarycentricSnap(CoordType &ip, const FaceType &f, ScalarType barThr, ScalarType distThr)
725 {
726 // Setting coordinate i to 0 moves the point onto the opposite edge, by ip[i] times the
727 // height of the triangle over that edge.
728 const ScalarType area2 = DoubleArea(f);
729 bool zero[3];
730 for (int i = 0; i < 3; ++i)
731 {
732 const ScalarType len = Distance(f.cP((i + 1) % 3), f.cP((i + 2) % 3));
733 zero[i] = ip[i] <= barThr && len > 0 && ip[i] * (area2 / len) <= distThr;
734 }
735 if (zero[0] && zero[1] && zero[2]) // cannot leave the triangle: keep the largest
736 zero[ip[0] >= ip[1] && ip[0] >= ip[2] ? 0 : (ip[1] >= ip[2] ? 1 : 2)] = false;
737 ScalarType sum = 0;
738 for (int i = 0; i < 3; ++i) { if (zero[i]) ip[i] = 0; sum += ip[i]; }
739 int last = -1;
740 for (int i = 0; i < 3; ++i) if (!zero[i]) { ip[i] /= sum; last = i; }
741 // Make the sum exactly 1: the last kept coordinate takes what the others leave.
742 ip[last] = 1;
743 for (int i = 0; i < 3; ++i) if (i != last) ip[last] -= ip[i];
744 return zero[0] || zero[1] || zero[2];
745 }
746
747
748 // Given a segment find the maximum distance from it to the original surface.
749 // It is used to evaluate the Haustdorff distance of a Segment from the mesh.
750 ScalarType MaxSegDist(VertexType *v0, VertexType *v1, CoordType &farthestPointOnSurf, CoordType &farthestN, Distribution<ScalarType> *distanceDistribution=0)
751 {
752 ScalarType maxSurfDist = 0;
753 const ScalarType sampleNum = 10;
754 for(ScalarType k = 1;k<sampleNum;++k)
755 {
756 ScalarType surfDist;
757 CoordType closestPSurf;
758 CoordType samplePnt = (v0->P()*k +v1->P()*(sampleNum-k))/sampleNum;
759 FaceType *f = Closest(samplePnt, closestPSurf, surfDist);
760 if(distanceDistribution)
761 distanceDistribution->Add(surfDist);
762 if(surfDist > maxSurfDist)
763 {
764 maxSurfDist = surfDist;
765 farthestPointOnSurf = closestPSurf;
766 farthestN = f->N();
767 }
768 }
769 return maxSurfDist;
770 }
771
772
784 void RefineCurveByDistance(MeshType &poly)
785 {
787 int startEdgeSize = poly.en;
788 for(int i =0; i<startEdgeSize;++i)
789 {
790 EdgeType &ei = poly.edge[i];
791 if(edge::Length(ei)>par.minRefEdgeLen)
792 {
793 CoordType farthestP, farthestN;
794 ScalarType maxDist = MaxSegDist(ei.V(0),ei.V(1),farthestP, farthestN);
795 if(maxDist > par.surfDistThr)
796 {
797 edge::VEEdgeSplit(poly, &ei, farthestP, farthestN);
798 }
799 }
800 }
801// tri::Allocator<MeshType>::CompactEveryVector(poly);
802// printf("Refine %i -> %i\n",startEdgeSize,poly.en);fflush(stdout);
803 }
804
822 void RefineCurveByBaseMesh(MeshType &poly)
823 {
824 SnapPolyline(poly); // compacts poly
825 const int startEn = poly.en;
826 MeshType out;
827 tri::Allocator<MeshType>::AddVertices(out, poly.vert.size());
828 for (size_t i = 0; i < poly.vert.size(); ++i) out.vert[i].ImportData(poly.vert[i]);
829 for (size_t ei = 0; ei < poly.edge.size(); ++ei)
830 {
831 Progress(int(100 * ei / poly.edge.size()), "RefineCurveByBaseMesh: tracing segment %lu of %lu", (unsigned long)ei + 1, (unsigned long)poly.edge.size());
832 const size_t i0 = tri::Index(poly, poly.edge[ei].cV(0)), i1 = tri::Index(poly, poly.edge[ei].cV(1));
833 std::vector<CoordType> crossings;
834 TraceSegment(poly.vert[i0].cP(), poly.vert[i1].cP(), crossings);
835 size_t prev = i0;
836 for (const CoordType &c : crossings)
837 {
838 const size_t vi = tri::Allocator<MeshType>::AddVertices(out, 1) - out.vert.begin();
839 out.vert[vi].ImportData(poly.vert[i0]);
840 out.vert[vi].P() = c;
841 out.vert[vi].ClearS(); // a crossing point is not one of the locked vertices
842 auto e = tri::Allocator<MeshType>::AddEdges(out, 1);
843 e->V(0) = &out.vert[prev]; e->V(1) = &out.vert[vi];
844 prev = vi;
845 }
846 auto e = tri::Allocator<MeshType>::AddEdges(out, 1);
847 e->V(0) = &out.vert[prev]; e->V(1) = &out.vert[i1];
848 }
849 poly.Clear();
851 // A geodesic is straight inside a face and along an edge: drop the free vertices that
852 // only bend a strand there, so it runs straight between its control points and edge
853 // crossings. A vertex is dropped when every face it belongs to also holds both its
854 // neighbours (inside a face: the neighbours are in it; on an edge: on the same edge),
855 // so the shortcut stays where the strand was; strands meeting the same edges in the
856 // same order cannot cross once straight.
858 int droppedCnt = 0;
859 auto faces = [&](const CoordType &p) {
860 std::vector<FaceType *> fs;
861 for (const auto &l : Locate(p)) fs.push_back(l.first);
862 std::sort(fs.begin(), fs.end());
863 return fs;
864 };
865 for (VertexType &v : poly.vert)
866 {
867 if (v.IsD() || v.IsS() || edge::VEDegree<EdgeType>(&v) != 2) continue;
868 std::vector<VertexPointer> nb;
869 edge::VVStarVE(&v, nb);
870 const std::vector<FaceType *> fv = faces(v.cP()), fa = faces(nb[0]->cP()), fb = faces(nb[1]->cP());
871 if (!std::includes(fa.begin(), fa.end(), fv.begin(), fv.end()) ||
872 !std::includes(fb.begin(), fb.end(), fv.begin(), fv.end())) continue;
873 edge::VEEdgeCollapse(poly, &v);
874 ++droppedCnt;
875 }
877 SimplifyNullEdges(poly);
878 Log("RefineCurveByBaseMesh %i en -> %i en, %i vertices inside faces dropped", startEn, poly.en, droppedCnt);
879 }
880
890 bool RoundingSnap(CoordType &ip, const FaceType &f) const
891 {
892 return BarycentricSnap(ip, f, ScalarType(1), base.bbox.Diag() * ScalarType(1e-6));
893 }
894
898 typedef std::vector<std::pair<FaceType *, CoordType>> Location;
899
900 Location Locate(const CoordType &p)
901 {
902 CoordType ip;
903 FaceType *f = GetClosestFaceIP(p, ip);
904 RoundingSnap(ip, *f);
905 return LocationFrom(f, ip);
906 }
907
908 Location LocationFrom(FaceType *f, const CoordType &ip) const
909 {
910 Location loc{{f, ip}};
911 int zeros = 0, one = -1, zero = -1;
912 for (int i = 0; i < 3; ++i) { if (ip[i] == 0) { ++zeros; zero = i; } else one = i; }
913 if (zeros == 1) // on the edge opposite to corner `zero`: add the face across it
914 {
915 const int e = (zero + 1) % 3;
916 FaceType *g = f->FFp(e);
917 if (g != f) {
918 CoordType ig(0, 0, 0);
919 for (int j = 0; j < 3; ++j) {
920 if (g->V(j) == f->V(e)) ig[j] = ip[e];
921 if (g->V(j) == f->V((e + 1) % 3)) ig[j] = ip[(e + 1) % 3];
922 }
923 loc.push_back({g, ig});
924 }
925 }
926 else if (zeros == 2) // on vertex V(one): every face around it, across edges incident to it
927 {
928 VertexPointer v = f->V(one);
929 for (size_t k = 0; k < loc.size(); ++k)
930 for (int i = 0; i < 3; ++i) {
931 FaceType *h = loc[k].first;
932 if (h->V(i) != v && h->V((i + 1) % 3) != v) continue;
933 FaceType *g = h->FFp(i);
934 bool seen = false;
935 for (const auto &l : loc) seen |= l.first == g;
936 if (seen) continue;
937 CoordType ig(0, 0, 0);
938 for (int j = 0; j < 3; ++j) if (g->V(j) == v) ig[j] = 1;
939 loc.push_back({g, ig});
940 }
941 }
942 return loc;
943 }
944
951 bool OnCutSeam(const Location &loc) const
952 {
953 const ScalarType tol2 = math::Sqr(base.bbox.Diag() * ScalarType(1e-6));
954 auto same = [tol2](const CoordType &a, const CoordType &b) { return SquaredDistance(a, b) <= tol2; };
955 for (const auto &c : loc)
956 for (int i = 0; i < 3; ++i)
957 {
958 if (!face::IsBorder(*c.first, i) || c.second[(i + 2) % 3] != 0) continue;
959 const CoordType &a = c.first->cP(i), &b = c.first->cP((i + 1) % 3);
960 for (const FaceType &g : base.face)
961 if (!g.IsD() && &g != c.first)
962 for (int j = 0; j < 3; ++j)
963 if (face::IsBorder(g, j) && ((same(g.cP(j), b) && same(g.cP((j + 1) % 3), a)) || // the usual,
964 (same(g.cP(j), a) && same(g.cP((j + 1) % 3), b)))) // or misoriented
965 return true;
966 }
967 return false;
968 }
969
970 [[noreturn]] static void ThrowCutSeam(const CoordType &p)
971 {
972 char buf[256];
973 std::snprintf(buf, sizeof(buf), "CoM: a curve crosses or touches a cut seam at (%g, %g, %g): the border there "
974 "has a coincident twin, so the surface is cut but not open. Embed all curves before cutting, "
975 "or weld the seam first.", double(p[0]), double(p[1]), double(p[2]));
976 throw vcg::MissingPreconditionException(buf);
977 }
978
986 void TraceSegment(const CoordType &p, const CoordType &q, std::vector<CoordType> &crossings)
987 {
988 const Location target = Locate(q);
989 Location cur = Locate(p);
990 CoordType cutN = (q - p) ^ (cur[0].first->cN() + target[0].first->cN());
991 if (!(cutN.Norm() > 0))
992 throw vcg::MissingPreconditionException("CoM: could not trace a curve segment across the mesh.");
993 cutN.Normalize();
994 for (int step = 0; ; ++step)
995 {
996 for (const auto &c : cur) for (const auto &t : target)
997 if (c.first == t.first) return; // both ends in one face: the rest lies in it
998 // At q's position but in none of its faces: q has a coincident copy and was located
999 // on the other one, the other side of a seam. Going on would only turn back.
1000 const CoordType pc = cur[0].first->cP(0) * cur[0].second[0] + cur[0].first->cP(1) * cur[0].second[1] + cur[0].first->cP(2) * cur[0].second[2];
1001 if (SquaredDistance(pc, q) <= math::Sqr(base.bbox.Diag() * ScalarType(1e-6)))
1002 ThrowCutSeam(pc);
1003 if (step > 4 * int(base.fn) + 16)
1004 throw vcg::MissingPreconditionException("CoM: could not trace a curve segment across the mesh.");
1005 // In each face around the current point, the cut runs along the barycentric direction
1006 // keeping the signed distance from the plane at zero, towards q; take the face it
1007 // heads into most. Along an edge lying in the plane it heads into both faces with
1008 // zero inward component, up to rounding: accept that, flattened to exactly zero, so
1009 // the trace follows the edge to its next vertex. On the border, heading out of every
1010 // face means leaving the surface; elsewhere it means the cut turns back (a segment
1011 // too long for the curvature it spans) and the trace follows the best face's edge.
1012 FaceType *g = nullptr;
1013 CoordType bx, d;
1014 ScalarType bestInward = std::numeric_limits<ScalarType>::lowest();
1015 bool onBorder = false;
1016 for (const auto &c : cur)
1017 {
1018 const FaceType &f = *c.first;
1019 for (int i = 0; i < 3; ++i)
1020 onBorder |= face::IsBorder(f, i) && c.second[(i + 2) % 3] == 0;
1021 ScalarType sd[3];
1022 for (int i = 0; i < 3; ++i) sd[i] = cutN.dot(f.cP(i) - p);
1023 CoordType dir(sd[1] - sd[2], sd[2] - sd[0], sd[0] - sd[1]);
1024 const CoordType disp = f.cP(0) * dir[0] + f.cP(1) * dir[1] + f.cP(2) * dir[2];
1025 if (!(disp.Norm() > 0)) continue;
1026 dir /= (disp.dot(q - pc) < 0 ? -disp.Norm() : disp.Norm()); // per unit length, towards q
1027 const ScalarType tol = ScalarType(1e-6) * (std::abs(dir[0]) + std::abs(dir[1]) + std::abs(dir[2]));
1028 ScalarType inward = std::numeric_limits<ScalarType>::max();
1029 for (int k = 0; k < 3; ++k) if (c.second[k] == 0) inward = std::min(inward, dir[k]);
1030 if (inward > -tol) inward = std::max(inward, ScalarType(0));
1031 if (inward <= bestInward) continue;
1032 for (int k = 0; k < 3; ++k) if (c.second[k] == 0 && dir[k] < 0) dir[k] = 0;
1033 bestInward = inward; g = c.first; bx = c.second; d = dir;
1034 }
1035 if (g == nullptr)
1036 throw vcg::MissingPreconditionException("CoM: could not trace a curve segment across the mesh.");
1037 if (bestInward < 0 && onBorder)
1038 {
1039 if (OnCutSeam(cur)) ThrowCutSeam(pc);
1040 char buf[160];
1041 std::snprintf(buf, sizeof(buf), "CoM: a curve segment leaves the surface across a border at (%g, %g, %g).",
1042 double(pc[0]), double(pc[1]), double(pc[2]));
1043 throw vcg::MissingPreconditionException(buf);
1044 }
1045 // Leave g where the first coordinate reaches zero.
1046 int exitK = -1;
1047 ScalarType sExit = std::numeric_limits<ScalarType>::max();
1048 for (int k = 0; k < 3; ++k)
1049 if (d[k] < 0 && bx[k] > 0 && bx[k] / -d[k] < sExit) { sExit = bx[k] / -d[k]; exitK = k; }
1050 if (exitK < 0)
1051 throw vcg::MissingPreconditionException("CoM: could not trace a curve segment across the mesh.");
1052 CoordType b = bx + d * sExit;
1053 b[exitK] = 0;
1054 const ScalarType rest = b[(exitK + 1) % 3] + b[(exitK + 2) % 3];
1055 b[(exitK + 1) % 3] /= rest;
1056 b[(exitK + 2) % 3] = 1 - b[(exitK + 1) % 3];
1057 RoundingSnap(b, *g); // through a vertex, if it passes that close to one
1058 crossings.push_back(g->cP(0) * b[0] + g->cP(1) * b[1] + g->cP(2) * b[2]);
1059 cur = LocationFrom(g, b);
1060 }
1061 }
1062
1063
1072 std::vector<CoordType> operator()(const MeshType &poly) const {
1073 std::vector<CoordType> posVec(poly.vn, CoordType(0,0,0));
1074 std::vector<int> cntVec(poly.vn, 0);
1075 for(int i=0; i<poly.en; ++i)
1076 for(int j=0; j<2; ++j) {
1077 int vi = tri::Index(poly, poly.edge[i].V0(j));
1078 posVec[vi] += poly.edge[i].V1(j)->P();
1079 cntVec[vi] += 1;
1080 }
1081 for(int i=0; i<poly.vn; ++i)
1082 posVec[i] = (poly.vert[i].P() + posVec[i]) / ScalarType(cntVec[i]+1);
1083 return posVec;
1084 }
1085 };
1086
1105 {
1106
1107 CoM<MeshType> &com;
1108 ScalarType scale;
1109 ScalarType smoothBlend = 0.5;
1110 QualityDistanceFieldFunctor(CoM<MeshType> &_com, ScalarType _scale=0, ScalarType _smoothBlend = 0.5) : com(_com), scale(_scale), smoothBlend(_smoothBlend) {};
1111
1112 std::vector<CoordType> operator()(const MeshType &poly) const
1113 {
1114 // Step 1: Compute smoothed position using Laplacian smoothing
1115 std::vector<CoordType> smoothPosVec(poly.vn, CoordType(0, 0, 0));
1116 std::vector<int> cntVec(poly.vn, 0);
1117 for (int i = 0; i < poly.en; ++i)
1118 for (int j = 0; j < 2; ++j)
1119 {
1120 int vi = tri::Index(poly, poly.edge[i].V0(j));
1121 smoothPosVec[vi] += poly.edge[i].V1(j)->P();
1122 cntVec[vi] += 1;
1123 }
1124 for (int i = 0; i < poly.vn; ++i)
1125 smoothPosVec[i] = (poly.vert[i].P() + smoothPosVec[i]) / ScalarType(cntVec[i] + 1);
1126
1127 // Step 2: Compute field-based position using the gradient of the quality field and moving toward zero
1128 std::vector<CoordType> fieldPosVec(poly.vn, CoordType(0, 0, 0));
1129 for (const VertexType &v : poly.vert)
1130 {
1131 CoordType ip;
1132 FacePointer f = com.GetClosestFaceIP(v.P(),ip); // throws rather than return null
1133 ScalarType q = f->V(0)->Q() * ip[0] + f->V(1)->Q() * ip[1] + f->V(2)->Q() * ip[2];
1134 CoordType fieldDir = GradientScalarField(*f, f->V(0)->Q(),f->V(1)->Q(),f->V(2)->Q());
1135
1136 fieldPosVec[tri::Index(poly, v)] = v.P() + fieldDir * scale * q; // Move towards higher quality (lower distance)
1137 }
1138 std::vector<CoordType> PosVec(poly.vn, CoordType(0, 0, 0));
1139 for (int i = 0; i < poly.vn; ++i)
1140 PosVec[i] = (smoothPosVec[i] * smoothBlend + fieldPosVec[i] * (1.0 - smoothBlend));
1141
1142 return PosVec;
1143 }
1144 };
1145
1157 template<typename PositionFunctor>
1158 void MoveAndProject(MeshType &poly, int iterNum, ScalarType moveWeight, ScalarType projectWeight,
1159 PositionFunctor &desiredPos)
1160 {
1161 tri::RequireCompactness(poly);
1163 if (poly.en == 0 || base.fn == 0)
1164 throw vcg::MissingPreconditionException("CoM: the curve and the base mesh must both be non-empty.");
1165 for(int k=0;k<iterNum;++k)
1166 {
1167 Progress(100*k/iterNum, "MoveAndProject iteration %i of %i, %i vertices", k+1, iterNum, poly.vn);
1168 if(k==iterNum-1) projectWeight=1;
1169 std::vector<CoordType> desired = desiredPos(poly);
1170
1171 for(int i=0; i<poly.vn; ++i)
1172 if(!poly.vert[i].IsS())
1173 {
1174 // Clamp the movement towards the desired position by maxMoveDist
1175 CoordType delta = desired[i] - poly.vert[i].P();
1176 ScalarType deltaLen = delta.Norm();
1177 if(deltaLen > par.maxMoveDelta) {
1178 delta *= (par.maxMoveDelta / deltaLen);
1179 desired[i] = poly.vert[i].P() + delta;
1180 }
1181
1182 CoordType newP = poly.vert[i].P()*(1.0-moveWeight) + desired[i]*moveWeight;
1183
1184 CoordType closestP;
1185 FaceType *f = GetClosestFacePoint(newP, closestP);
1186 poly.vert[i].P() = newP*(1.0-projectWeight) +closestP*projectWeight;
1187 poly.vert[i].N() = f->N();
1188 }
1189 else // a control point is only projected
1190 {
1191 CoordType closestP;
1192 FaceType *f = GetClosestFacePoint(poly.vert[i].P(), closestP);
1193 poly.vert[i].P() = closestP;
1194 poly.vert[i].N() = f->N();
1195 }
1196
1198 RefineCurveByDistance(poly);
1200 Simplify(poly);
1202 CollapseNullEdges(poly);
1203 }
1204 }
1205
1206 void SmoothProject(MeshType &poly, int iterNum, ScalarType smoothWeight, ScalarType projectWeight)
1207 {
1208 LaplacianFunctor lapFunct;
1209 MoveAndProject(poly, iterNum, smoothWeight, projectWeight, lapFunct);
1210 }
1211
1212
1213};
1214
1236template <class MeshType>
1238{
1239public:
1240 typedef CoM<MeshType> CoMType;
1241 typedef typename MeshType::ScalarType ScalarType;
1242 typedef typename MeshType::CoordType CoordType;
1243 typedef typename MeshType::VertexType VertexType;
1244 typedef typename MeshType::VertexPointer VertexPointer;
1245 typedef typename MeshType::VertexIterator VertexIterator;
1246 typedef typename MeshType::EdgeIterator EdgeIterator;
1247 typedef typename MeshType::FaceType FaceType;
1248 typedef typename MeshType::FacePointer FacePointer;
1249 typedef typename MeshType::FaceIterator FaceIterator;
1250
1251
1274static bool TagFaceEdgeSelWithPolyLine(CoMType &com, MeshType &poly,bool markFlag=true)
1275{
1276 if (markFlag)
1278
1281
1282 for(EdgeIterator ei=poly.edge.begin(); ei!=poly.edge.end();++ei)
1283 {
1284 CoordType ip0,ip1;
1285 FaceType *f0 = com.GetClosestFaceIP(ei->cP(0),ip0);
1286 FaceType *f1 = com.GetClosestFaceIP(ei->cP(1),ip1);
1287
1288 if(com.BarycentricSnap(ip0, *f0) && com.BarycentricSnap(ip1, *f1))
1289 {
1290 VertexPointer v0 = com.FindVertexSnap(f0,ip0);
1291 VertexPointer v1 = com.FindVertexSnap(f1,ip1);
1292
1293 if(v0==0 || v1==0)
1294 return false;
1295 if(v0==v1)
1296 return false;
1297
1298 FacePointer ff0,ff1;
1299 int e0,e1;
1300 bool ret=face::FindSharedFaces<FaceType>(v0,v1,ff0,ff1,e0,e1);
1301 if(ret)
1302 {
1303 assert(ret);
1304 assert(ff0->V(e0)==v0 || ff0->V(e0)==v1);
1305 ff0->SetFaceEdgeS(e0);
1306 ff1->SetFaceEdgeS(e1);
1307 } else {
1308 return false;
1309 }
1310 }
1311 else {
1312 return false;
1313 }
1314 }
1315 return true;
1316}
1317
1318
1355 static void SplitMeshWithPolyline(CoMType &com, MeshType &poly)
1356 {
1357 MeshType &m = com.base;
1359 if (poly.vn == 0) return;
1360 typedef std::pair<size_t, size_t> EdgeKey; // mesh vertex indices, smaller first
1361 auto key = [](size_t a, size_t b) { return a < b ? EdgeKey(a, b) : EdgeKey(b, a); };
1362
1363 // 1. Where each polyline vertex is on the mesh: on a vertex, on an edge, or in a face.
1364 enum { OnVertex, OnEdge, InFace };
1365 struct Loc { int kind; size_t vert; EdgeKey edge; ScalarType t; size_t face[2]; int faceNum; CoordType ip; };
1366 std::vector<Loc> loc(poly.vert.size());
1367 for (size_t ci = 0; ci < poly.vert.size(); ++ci)
1368 {
1369 Loc &l = loc[ci];
1370 FaceType *f = com.GetClosestFaceIP(poly.vert[ci].cP(), l.ip);
1371 // Only rounding-level snapping here: SnapPolyline already put the vertices that may
1372 // be snapped exactly on their vertex or edge, and kept the others off on purpose.
1373 com.RoundingSnap(l.ip, *f);
1374 int z = -1, one = -1;
1375 for (int i = 0; i < 3; ++i) { if (l.ip[i] == 0) z = i; if (l.ip[i] == 1) one = i; }
1376 l.face[0] = tri::Index(m, f); l.faceNum = 1;
1377 if (one >= 0) { l.kind = OnVertex; l.vert = tri::Index(m, f->V(one)); }
1378 else if (z >= 0) {
1379 // On the edge opposite to corner z: from V(z+1), at parameter ip[z+2].
1380 l.kind = OnEdge;
1381 const size_t a = tri::Index(m, f->V((z + 1) % 3)), b = tri::Index(m, f->V((z + 2) % 3));
1382 l.edge = key(a, b);
1383 l.t = (a < b) ? l.ip[(z + 2) % 3] : l.ip[(z + 1) % 3];
1384 const int e = (z + 1) % 3; // index of that edge in f
1385 if (f->FFp(e) != f) { l.face[1] = tri::Index(m, f->FFp(e)); l.faceNum = 2; }
1386 }
1387 else l.kind = InFace;
1388 }
1389
1390 // 2. A mesh vertex for each of them: the existing one, or a new one shared by every
1391 // polyline vertex within rounding distance (the mesh realizes the union of the
1392 // curves: two strands meeting at a point meet at one mesh vertex).
1393 const ScalarType tol = m.bbox.Diag() * ScalarType(1e-6);
1394 std::vector<size_t> meshV(poly.vert.size());
1395 std::map<EdgeKey, std::vector<std::pair<ScalarType, size_t>>> edgePoints; // (t from first, vertex)
1396 std::map<size_t, std::vector<std::pair<size_t, CoordType>>> facePoints; // (vertex, barycentric)
1397 size_t newVertNum = 0;
1398 const size_t firstNewVert = m.vert.size();
1399 for (size_t ci = 0; ci < poly.vert.size(); ++ci)
1400 {
1401 const Loc &l = loc[ci];
1402 if (l.kind == OnVertex) { meshV[ci] = l.vert; continue; }
1403 if (l.kind == OnEdge) {
1404 auto &pts = edgePoints[l.edge];
1405 const ScalarType len = Distance(m.vert[l.edge.first].cP(), m.vert[l.edge.second].cP());
1406 auto it = std::find_if(pts.begin(), pts.end(), [&](const std::pair<ScalarType, size_t> &p) { return std::abs(p.first - l.t) * len <= tol; });
1407 if (it != pts.end()) { meshV[ci] = it->second; continue; }
1408 meshV[ci] = firstNewVert + newVertNum++;
1409 pts.push_back({l.t, meshV[ci]});
1410 } else {
1411 auto &pts = facePoints[l.face[0]];
1412 const FaceType &f = m.face[l.face[0]];
1413 const CoordType p = f.cP(0) * l.ip[0] + f.cP(1) * l.ip[1] + f.cP(2) * l.ip[2];
1414 auto it = std::find_if(pts.begin(), pts.end(), [&](const std::pair<size_t, CoordType> &q) {
1415 return Distance(p, f.cP(0) * q.second[0] + f.cP(1) * q.second[1] + f.cP(2) * q.second[2]) <= tol; });
1416 if (it != pts.end()) { meshV[ci] = it->first; continue; }
1417 meshV[ci] = firstNewVert + newVertNum++;
1418 pts.push_back({meshV[ci], l.ip});
1419 }
1420 }
1422 for (size_t ci = 0; ci < poly.vert.size(); ++ci)
1423 {
1424 const Loc &l = loc[ci];
1425 VertexType &nv = m.vert[meshV[ci]];
1426 if (l.kind == OnEdge && meshV[ci] >= firstNewVert) {
1427 const VertexType &va = m.vert[l.edge.first], &vb = m.vert[l.edge.second];
1428 nv.P() = va.cP() * (1 - l.t) + vb.cP() * l.t;
1429 VertexInterpolator<MeshType>::Lerp(m, nv, va, vb, l.t);
1430 } else if (l.kind == InFace && meshV[ci] >= firstNewVert) {
1431 const FaceType &f = m.face[l.face[0]];
1432 nv.P() = f.cP(0) * l.ip[0] + f.cP(1) * l.ip[1] + f.cP(2) * l.ip[2];
1433 VertexInterpolator<MeshType>::Barycentric(m, nv, *f.cV(0), *f.cV(1), *f.cV(2), l.ip);
1434 }
1435 }
1436 for (size_t ci = 0; ci < poly.vert.size(); ++ci) poly.vert[ci].P() = m.vert[meshV[ci]].cP();
1437
1438 // 3. The segments: across one face, or along one edge.
1439 struct Segment { size_t polyEdge, a, b; }; // mesh vertices, in the polyline edge's direction
1440 std::map<size_t, std::vector<Segment>> faceSegments;
1441 std::vector<std::pair<Segment, EdgeKey>> edgeSegments;
1442 std::map<size_t, std::vector<size_t>> vertFaces; // faces around the polyline vertices on mesh vertices
1443 for (size_t ci = 0; ci < poly.vert.size(); ++ci)
1444 if (loc[ci].kind == OnVertex) vertFaces[loc[ci].vert];
1445 if (!vertFaces.empty())
1446 for (size_t fi = 0; fi < m.face.size(); ++fi) if (!m.face[fi].IsD())
1447 for (int i = 0; i < 3; ++i) {
1448 auto it = vertFaces.find(tri::Index(m, m.face[fi].V(i)));
1449 if (it != vertFaces.end()) it->second.push_back(fi);
1450 }
1451 auto candidateFaces = [&](size_t ci) {
1452 if (loc[ci].kind == OnVertex) return vertFaces[loc[ci].vert];
1453 return std::vector<size_t>(loc[ci].face, loc[ci].face + loc[ci].faceNum);
1454 };
1455 for (size_t ei = 0; ei < poly.edge.size(); ++ei)
1456 {
1457 const auto &e = poly.edge[ei];
1458 const size_t c0 = tri::Index(poly, e.cV(0)), c1 = tri::Index(poly, e.cV(1));
1459 if (meshV[c0] == meshV[c1]) continue; // a zero-length segment
1460 // The segment lies in the faces both its ends belong to: one face for a segment
1461 // across it, the two faces of an edge for a segment along it.
1462 std::vector<size_t> f0 = candidateFaces(c0), f1 = candidateFaces(c1), common;
1463 std::sort(f0.begin(), f0.end()); std::sort(f1.begin(), f1.end());
1464 std::set_intersection(f0.begin(), f0.end(), f1.begin(), f1.end(), std::back_inserter(common));
1465 if (common.empty())
1466 throw vcg::MissingPreconditionException("CoMEmbed: a curve segment does not lie in one face; call RefineCurveByBaseMesh first.");
1467 const Segment s{ei, meshV[c0], meshV[c1]};
1468 if (common.size() == 1) faceSegments[common[0]].push_back(s);
1469 else {
1470 const FaceType &f = m.face[common[0]]; // the edge both faces share
1471 EdgeKey ek(0, 0);
1472 for (int i = 0; i < 3; ++i)
1473 if (f.cFFp(i) == &m.face[common[1]]) ek = key(tri::Index(m, f.cV(i)), tri::Index(m, f.cV1(i)));
1474 edgeSegments.push_back({s, ek});
1475 }
1476 }
1477
1478 std::set<size_t> touched;
1479 for (const auto &fp : facePoints) touched.insert(fp.first);
1480 for (const auto &fs : faceSegments) touched.insert(fs.first);
1481 for (size_t fi = 0; fi < m.face.size(); ++fi) if (!m.face[fi].IsD())
1482 for (int i = 0; i < 3; ++i)
1483 if (edgePoints.count(key(tri::Index(m, m.face[fi].V(i)), tri::Index(m, m.face[fi].V1(i))))) touched.insert(fi);
1484
1485 // 4. Rebuild every touched face on its own. Where segments cross, the crossing point
1486 // becomes a mesh vertex; every segment is cut at the curve points lying on it
1487 // (crossings, other curves touching or overlapping it), and the pieces recovered.
1488 std::map<size_t, std::vector<size_t>> chains; // polyline edge -> mesh vertices inside it, in order
1489 std::vector<std::pair<size_t, CoordType>> crossingVerts; // (face, barycentric) of the new vertices
1490 const size_t firstCrossingVert = m.vert.size();
1491 std::vector<std::pair<size_t, LocalTriangulation>> rebuilt;
1492 size_t newFaceNum = 0, done = 0;
1493 for (size_t fi : touched)
1494 {
1495 com.Progress(int(100 * done / touched.size()), "SplitMeshWithPolyline: rebuilding face %lu of %lu", (unsigned long)done + 1, (unsigned long)touched.size());
1496 ++done;
1497 LocalTriangulation lt;
1498 const FaceType &f = m.face[fi];
1499 lt.SetMetric(f.cP(1) - f.cP(0), f.cP(2) - f.cP(0));
1500 size_t corner[3];
1501 for (int k = 0; k < 3; ++k) { corner[k] = tri::Index(m, f.cV(k)); lt.AddPoint(corner[k], k == 1, k == 2, (1 << k) | (1 << ((k + 2) % 3))); }
1502 lt.tris.push_back({{0, 1, 2}});
1503 for (int k = 0; k < 3; ++k)
1504 {
1505 auto it = edgePoints.find(key(corner[k], corner[(k + 1) % 3]));
1506 if (it == edgePoints.end()) continue;
1507 std::vector<std::pair<ScalarType, size_t>> pts; // parameter from corner k
1508 for (const auto &p : it->second) pts.push_back({corner[k] < corner[(k + 1) % 3] ? p.first : 1 - p.first, p.second});
1509 std::sort(pts.begin(), pts.end());
1510 int prev = k;
1511 for (const auto &p : pts)
1512 {
1513 const ScalarType s = p.first;
1514 const ScalarType u = lt.pts[k].u * (1 - s) + lt.pts[(k + 1) % 3].u * s;
1515 const ScalarType v = lt.pts[k].v * (1 - s) + lt.pts[(k + 1) % 3].v * s;
1516 const int pi = lt.AddPoint(p.second, u, v, 1 << k);
1517 lt.SplitEdge(prev, (k + 1) % 3, pi);
1518 prev = pi;
1519 }
1520 }
1521 for (const auto &p : facePoints[fi]) lt.InsertInterior(lt.AddPoint(p.first, p.second[1], p.second[2], 0));
1522
1523 const std::vector<Segment> &segs = faceSegments[fi];
1524 auto pos3 = [&](int i) { return f.cP(0) * (1 - lt.pts[i].u - lt.pts[i].v) + f.cP(1) * lt.pts[i].u + f.cP(2) * lt.pts[i].v; };
1525 auto nearPoint = [&](const CoordType &p) {
1526 for (size_t i = 0; i < lt.pts.size(); ++i) if (Distance(pos3(int(i)), p) <= tol) return int(i);
1527 return -1;
1528 };
1529 // Crossings: a new mesh vertex where two segments cross, unless a point is already there.
1530 for (size_t i = 0; i < segs.size(); ++i)
1531 for (size_t j = i + 1; j < segs.size(); ++j)
1532 {
1533 const int p = lt.Local(segs[i].a), q = lt.Local(segs[i].b), a = lt.Local(segs[j].a), b = lt.Local(segs[j].b);
1534 if (!lt.Crosses(p, q, a, b)) continue;
1535 const long double op = lt.Orient(a, b, p), oq = lt.Orient(a, b, q);
1536 const ScalarType s = ScalarType(op / (op - oq));
1537 const ScalarType u = lt.pts[p].u + (lt.pts[q].u - lt.pts[p].u) * s, v = lt.pts[p].v + (lt.pts[q].v - lt.pts[p].v) * s;
1538 const CoordType x = f.cP(0) * (1 - u - v) + f.cP(1) * u + f.cP(2) * v;
1539 if (nearPoint(x) >= 0) continue;
1540 crossingVerts.push_back({fi, CoordType(1 - u - v, u, v)});
1541 lt.InsertInterior(lt.AddPoint(firstCrossingVert + crossingVerts.size() - 1, u, v, 0));
1542 }
1543 // Each segment cut at the curve points on it, then its pieces made edges.
1544 for (const Segment &sg : segs)
1545 {
1546 const int p = lt.Local(sg.a), q = lt.Local(sg.b);
1547 const Segment3<ScalarType> seg(pos3(p), pos3(q));
1548 std::vector<std::pair<ScalarType, int>> on; // (parameter along the segment, point)
1549 for (size_t r = 0; r < lt.pts.size(); ++r)
1550 {
1551 if (int(r) == p || int(r) == q) continue;
1552 CoordType closest; ScalarType dist;
1553 SegmentPointDistance(seg, pos3(int(r)), closest, dist);
1554 const ScalarType t = (pos3(int(r)) - seg.P0()) * (seg.P1() - seg.P0()) / seg.SquaredLength();
1555 if (dist <= tol && t > 0 && t < 1 && Distance(pos3(int(r)), seg.P0()) > tol && Distance(pos3(int(r)), seg.P1()) > tol)
1556 on.push_back({t, int(r)});
1557 }
1558 std::sort(on.begin(), on.end());
1559 int prev = p;
1560 for (const auto &o : on) { lt.Recover(prev, o.second); prev = o.second; chains[sg.polyEdge].push_back(lt.pts[o.second].vert); }
1561 lt.Recover(prev, q);
1562 }
1563 lt.MakeDelaunay();
1564 newFaceNum += lt.tris.size() - 1;
1565 rebuilt.push_back({fi, std::move(lt)});
1566 }
1567 // A segment along an edge is cut at the curve points on that edge between its ends.
1568 for (const auto &es : edgeSegments)
1569 {
1570 const Segment &sg = es.first;
1571 auto tOf = [&](size_t v) -> ScalarType {
1572 if (v == es.second.first) return 0;
1573 if (v == es.second.second) return 1;
1574 for (const auto &p : edgePoints[es.second]) if (p.second == v) return p.first;
1575 return -1;
1576 };
1577 const ScalarType ta = tOf(sg.a), tb = tOf(sg.b);
1578 std::vector<std::pair<ScalarType, size_t>> between;
1579 for (const auto &p : edgePoints[es.second])
1580 if (p.second != sg.a && p.second != sg.b && (p.first - ta) * (p.first - tb) < 0)
1581 between.push_back({std::abs(p.first - ta), p.second});
1582 std::sort(between.begin(), between.end());
1583 for (const auto &b : between) chains[sg.polyEdge].push_back(b.second);
1584 }
1585 tri::Allocator<MeshType>::AddVertices(m, crossingVerts.size());
1586 for (size_t k = 0; k < crossingVerts.size(); ++k)
1587 {
1588 const FaceType &f = m.face[crossingVerts[k].first];
1589 const CoordType &b = crossingVerts[k].second;
1590 VertexType &nv = m.vert[firstCrossingVert + k];
1591 nv.P() = f.cP(0) * b[0] + f.cP(1) * b[1] + f.cP(2) * b[2];
1592 VertexInterpolator<MeshType>::Barycentric(m, nv, *f.cV(0), *f.cV(1), *f.cV(2), b);
1593 }
1594
1595 // 5. Write the sub-triangles back: the first in place of the face, the others new.
1596 const bool wedgeTex = tri::HasPerWedgeTexCoord(m);
1597 size_t nextFace = m.face.size();
1599 for (auto &r : rebuilt)
1600 {
1601 FaceType &f = m.face[r.first];
1602 typename FaceType::TexCoordType wt[3];
1603 bool faux[3], border[3], edgeSel[3];
1604 for (int k = 0; k < 3; ++k) {
1605 if (wedgeTex) wt[k] = f.WT(k);
1606 faux[k] = f.IsF(k); border[k] = f.IsB(k); edgeSel[k] = f.IsFaceEdgeS(k);
1607 }
1608 const LocalTriangulation &lt = r.second;
1609 for (size_t ti = 0; ti < lt.tris.size(); ++ti)
1610 {
1611 FaceType &g = (ti == 0) ? f : m.face[nextFace++];
1612 if (ti > 0) g.ImportData(f);
1613 for (int i = 0; i < 3; ++i)
1614 {
1615 const auto &a = lt.pts[lt.tris[ti][i]], &b = lt.pts[lt.tris[ti][(i + 1) % 3]];
1616 g.V(i) = &m.vert[a.vert];
1617 if (wedgeTex) {
1618 g.WT(i) = wt[0];
1619 g.WT(i).P() = wt[0].P() * (1 - a.u - a.v) + wt[1].P() * a.u + wt[2].P() * a.v;
1620 }
1621 // An edge along an edge of the original face keeps that edge's bits; the
1622 // others are inside it.
1623 const int shared = a.edges & b.edges;
1624 const int k = shared ? (shared & 1 ? 0 : (shared & 2 ? 1 : 2)) : -1;
1625 if (k >= 0 && faux[k]) g.SetF(i); else g.ClearF(i);
1626 if (k >= 0 && border[k]) g.SetB(i); else g.ClearB(i);
1627 if (k >= 0 && edgeSel[k]) g.SetFaceEdgeS(i); else g.ClearFaceEdgeS(i);
1628 }
1629 }
1630 }
1631 com.Init();
1632
1633 // 6. The polyline follows: a segment cut at some points gets its own vertices there, so
1634 // two strands crossing or touching stay two strands, each with a vertex at the
1635 // shared mesh vertex (CoM::ConnectCrossings merges them, if junctions are wanted).
1636 // Every polyline edge is now a mesh edge: select it on both sides.
1637 std::set<EdgeKey> curveEdges;
1638 const size_t oldEdgeNum = poly.edge.size();
1639 for (size_t ei = 0; ei < oldEdgeNum; ++ei)
1640 {
1641 if (poly.edge[ei].IsD()) continue;
1642 const size_t c0 = tri::Index(poly, poly.edge[ei].cV(0)), c1 = tri::Index(poly, poly.edge[ei].cV(1));
1643 size_t prev = c0, prevMV = meshV[c0];
1644 auto ch = chains.find(ei);
1645 if (ch != chains.end())
1646 for (size_t mv : ch->second)
1647 {
1648 const size_t vi = tri::Allocator<MeshType>::AddVertices(poly, 1) - poly.vert.begin();
1649 poly.vert[vi].ImportData(poly.vert[c0]);
1650 poly.vert[vi].ClearS(); // a cut point is not a control point
1651 poly.vert[vi].P() = m.vert[mv].cP();
1652 auto ne = tri::Allocator<MeshType>::AddEdges(poly, 1);
1653 ne->V(0) = &poly.vert[prev]; ne->V(1) = &poly.vert[vi];
1654 curveEdges.insert(key(prevMV, mv));
1655 prev = vi; prevMV = mv;
1656 }
1657 poly.edge[ei].V(0) = &poly.vert[prev]; // the original edge is the last piece
1658 if (prevMV != meshV[c1]) curveEdges.insert(key(prevMV, meshV[c1]));
1659 }
1660 for (FaceType &f : m.face) if (!f.IsD())
1661 for (int i = 0; i < 3; ++i)
1662 if (curveEdges.count(key(tri::Index(m, f.V0(i)), tri::Index(m, f.V1(i))))) f.SetFaceEdgeS(i);
1663 }
1664
1665private:
1669 struct LocalTriangulation
1670 {
1671 struct Point { size_t vert; ScalarType u, v; int edges; }; // edges: bit k if on face edge k
1672 std::vector<Point> pts;
1673 std::vector<std::array<int, 3>> tris;
1674 std::set<std::pair<int, int>> recovered; // segments already made edges, smaller index first
1675 double g11 = 1, g12 = 0, g22 = 1; // the face's metric in the frame: |(du, dv)|^2 = du^2 g11 + 2 du dv g12 + dv^2 g22
1676
1678 void SetMetric(const CoordType &e1, const CoordType &e2)
1679 {
1680 g11 = e1.dot(e1); g12 = e1.dot(e2); g22 = e2.dot(e2);
1681 }
1682 double Len2(int a, int b) const
1683 {
1684 const double du = double(pts[b].u) - pts[a].u, dv = double(pts[b].v) - pts[a].v;
1685 return du * du * g11 + 2 * du * dv * g12 + dv * dv * g22;
1686 }
1687
1688 int AddPoint(size_t vert, ScalarType u, ScalarType v, int edges)
1689 {
1690 pts.push_back({vert, u, v, edges});
1691 return int(pts.size()) - 1;
1692 }
1693 int Local(size_t vert) const
1694 {
1695 for (size_t i = 0; i < pts.size(); ++i) if (pts[i].vert == vert) return int(i);
1696 throw vcg::MissingPreconditionException("CoMEmbed: a curve segment ends outside the face it was assigned to.");
1697 }
1703 long double Orient(int a, int b, int c) const
1704 {
1705 if (pts[a].edges & pts[b].edges & pts[c].edges) return 0;
1706 return planar_polygon_detail::Orient2D(Point2d(pts[a].u, pts[a].v), Point2d(pts[b].u, pts[b].v), Point2d(pts[c].u, pts[c].v));
1707 }
1709 bool FindEdge(int a, int b, size_t &ti, int &i) const
1710 {
1711 for (ti = 0; ti < tris.size(); ++ti)
1712 for (i = 0; i < 3; ++i)
1713 if (tris[ti][i] == a && tris[ti][(i + 1) % 3] == b) return true;
1714 return false;
1715 }
1717 void SplitEdge(int a, int b, int p)
1718 {
1719 for (int side = 0; side < 2; ++side)
1720 {
1721 size_t ti; int i;
1722 if (!FindEdge(side ? b : a, side ? a : b, ti, i)) continue;
1723 const std::array<int, 3> t = tris[ti];
1724 tris[ti] = {{t[i], p, t[(i + 2) % 3]}};
1725 tris.push_back({{p, t[(i + 1) % 3], t[(i + 2) % 3]}});
1726 }
1727 }
1729 void InsertInterior(int p)
1730 {
1731 for (size_t ti = 0; ti < tris.size(); ++ti)
1732 {
1733 const std::array<int, 3> t = tris[ti];
1734 long double o[3];
1735 for (int i = 0; i < 3; ++i) o[i] = Orient(t[i], t[(i + 1) % 3], p);
1736 if (o[0] < 0 || o[1] < 0 || o[2] < 0) continue;
1737 int onEdge = -1, onCount = 0;
1738 for (int i = 0; i < 3; ++i) if (o[i] == 0) { onEdge = i; ++onCount; }
1739 if (onCount > 1)
1740 throw vcg::MissingPreconditionException("CoMEmbed: two curve points coincide inside a face.");
1741 if (onEdge >= 0) { SplitEdge(t[onEdge], t[(onEdge + 1) % 3], p); return; }
1742 tris[ti] = {{t[0], t[1], p}};
1743 tris.push_back({{t[1], t[2], p}});
1744 tris.push_back({{t[2], t[0], p}});
1745 return;
1746 }
1747 throw vcg::MissingPreconditionException("CoMEmbed: a curve point is outside the face it was assigned to.");
1748 }
1749 static int Sign(long double o) { return o > 0 ? 1 : (o < 0 ? -1 : 0); }
1751 bool Crosses(int p, int q, int a, int b) const
1752 {
1753 return Sign(Orient(p, q, a)) * Sign(Orient(p, q, b)) < 0 && Sign(Orient(a, b, p)) * Sign(Orient(a, b, q)) < 0;
1754 }
1759 void Recover(int p, int q)
1760 {
1761 std::deque<std::pair<int, int>> queue;
1762 for (const auto &t : tris)
1763 for (int i = 0; i < 3; ++i)
1764 {
1765 const int a = t[i], b = t[(i + 1) % 3];
1766 if (a < b && Crosses(p, q, a, b)) {
1767 if (recovered.count({a, b}))
1768 throw vcg::MissingPreconditionException("CoMEmbed: two curve segments cross inside a face.");
1769 queue.push_back({a, b});
1770 }
1771 }
1772 size_t guard = 0;
1773 while (!queue.empty())
1774 {
1775 if (++guard > 100 * (tris.size() + 10) * (tris.size() + 10))
1776 throw vcg::MissingPreconditionException("CoMEmbed: could not recover a curve segment; curves may touch or cross.");
1777 const int a = queue.front().first, b = queue.front().second;
1778 queue.pop_front();
1779 size_t t1, t2; int i1, i2;
1780 if (!FindEdge(a, b, t1, i1) || !FindEdge(b, a, t2, i2))
1781 throw vcg::MissingPreconditionException("CoMEmbed: a curve segment crosses the boundary of its face.");
1782 const int c = tris[t1][(i1 + 2) % 3], d = tris[t2][(i2 + 2) % 3];
1783 if (Orient(c, a, d) > 0 && Orient(d, b, c) > 0)
1784 {
1785 tris[t1] = {{c, a, d}};
1786 tris[t2] = {{d, b, c}};
1787 if (Crosses(p, q, c, d)) queue.push_back({c, d});
1788 }
1789 else queue.push_back({a, b});
1790 }
1791 size_t ti; int i;
1792 if (!FindEdge(p, q, ti, i) && !FindEdge(q, p, ti, i))
1793 throw vcg::MissingPreconditionException("CoMEmbed: could not recover a curve segment; it passes through another curve point.");
1794 recovered.insert({std::min(p, q), std::max(p, q)});
1795 }
1798 void MakeDelaunay()
1799 {
1800 std::vector<int> flat;
1801 for (const auto &t : tris) flat.insert(flat.end(), t.begin(), t.end());
1802 FlipToConstrainedDelaunay(flat, recovered,
1803 [this](int a, int b, int c) { return Orient(a, b, c); },
1804 [this](int a, int b) { return Len2(a, b); });
1805 for (size_t i = 0; i < tris.size(); ++i) tris[i] = {{flat[3 * i], flat[3 * i + 1], flat[3 * i + 2]}};
1806 }
1807 };
1808};
1809
1810} // end namespace tri
1811} // end namespace vcg
1812
1813#endif // __VCGLIB_CURVE_ON_SURF_H
Class to safely add and delete elements in a mesh.
Definition: allocate.h:97
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:339
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:195
static FaceIterator AddFaces(MeshType &m, size_t n)
Function to add n faces to the mesh. First wrapper, with no parameters.
Definition: allocate.h:621
static void DeleteEdge(MeshType &m, EdgeType &e)
Definition: allocate.h:952
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 int RemoveDuplicateVertex(MeshType &m, bool RemoveDegenerateFlag=true)
Definition: clean.h:206
static int RemoveDuplicateEdge(MeshType &m)
Definition: clean.h:361
A class for managing curves on a 2-manifold (Curve on Manifold - CoM).
Definition: curve_on_manifold.h:1238
static bool TagFaceEdgeSelWithPolyLine(CoMType &com, MeshType &poly, bool markFlag=true)
Tag face edges of the base mesh that coincide with polyline edges.
Definition: curve_on_manifold.h:1274
static void SplitMeshWithPolyline(CoMType &com, MeshType &poly)
Make the base mesh conform to the polyline: afterwards every polyline edge is an edge of the base mes...
Definition: curve_on_manifold.h:1355
Parameter class controlling the behavior of CoM algorithms.
Definition: curve_on_manifold.h:145
vcg::CallBackPos * cb
Receives progress and diagnostic messages (see wrap/callback.h)
Definition: curve_on_manifold.h:155
ScalarType surfDistThr
Max distance between surface and curve; used in simplify and refine.
Definition: curve_on_manifold.h:148
ScalarType maxMoveDelta
The maximum movement admitted during MoveAndProject (before projection)
Definition: curve_on_manifold.h:151
ScalarType barycentricSnapThr
Threshold for snapping barycentric coords to 0 or 1 (controls vertex/edge snapping)
Definition: curve_on_manifold.h:154
ScalarType gridBailout
The maximum distance bailout used in grid-based spatial queries.
Definition: curve_on_manifold.h:153
ScalarType maxSimpEdgeLen
Maximal admitted edge length (used in simplify: never make edges longer than this)
Definition: curve_on_manifold.h:150
void SetDefault(MeshType &m)
Set all parameters to reasonable defaults based on the mesh bounding box.
Definition: curve_on_manifold.h:161
ScalarType minRefEdgeLen
Minimal admitted edge length (used in refine: never make edges shorter than this)
Definition: curve_on_manifold.h:149
ScalarType maxSnapThr
The maximum distance a snap may move a polyline vertex (onto a mesh vertex or edge)
Definition: curve_on_manifold.h:152
void Dump() const
Print current parameter values to stdout.
Definition: curve_on_manifold.h:173
Param(MeshType &m)
Constructor with default parameter initialization based on mesh size.
Definition: curve_on_manifold.h:158
Definition: curve_on_manifold.h:122
std::vector< std::pair< FaceType *, CoordType > > Location
Definition: curve_on_manifold.h:898
ControlPoints
Which polyline vertices SetControlPoints() makes control points.
Definition: curve_on_manifold.h:448
@ EndsAndNodes
the ends (degree 1) and the junctions (degree > 2): each strand is free
Definition: curve_on_manifold.h:450
@ Selected
the vertices already selected, left as they are
Definition: curve_on_manifold.h:451
@ AllVertices
every vertex: the polyline is taken as it is, only projected and refined
Definition: curve_on_manifold.h:449
MeshType & base
Reference to the base triangulated surface mesh.
Definition: curve_on_manifold.h:188
void SimplifyNullEdges(MeshType &poly)
Remove duplicate/zero-length edges from a polyline.
Definition: curve_on_manifold.h:609
VertexPointer FindVertexSnap(FacePointer fp, CoordType &ip)
Find the vertex pointer for a vertex-snapped barycentric coordinate.
Definition: curve_on_manifold.h:346
FaceType * GetClosestFace(const CoordType &p)
Get the closest face to a query point.
Definition: curve_on_manifold.h:251
MeshGrid uniformGrid
Spatial acceleration structure for closest point queries.
Definition: curve_on_manifold.h:189
FaceType * GetClosestFaceIP(const CoordType &p, CoordType &ip)
Get the closest face and its barycentric coordinates.
Definition: curve_on_manifold.h:264
bool BarycentricSnap(CoordType &ip, const FaceType &f)
Snap the barycentric coordinates of a point of face f onto a vertex or an edge.
Definition: curve_on_manifold.h:718
void SetControlPoints(MeshType &poly, ControlPoints mode=EndsAndNodes)
Choose the control points of a polyline (stored as its vertex selection).
Definition: curve_on_manifold.h:462
void RefineCurveByBaseMesh(MeshType &poly)
Make every polyline segment lie inside one face or along one edge of the base mesh,...
Definition: curve_on_manifold.h:822
Param par
Parameters controlling algorithm behavior.
Definition: curve_on_manifold.h:190
CoM(MeshType &_m)
Definition: curve_on_manifold.h:195
FaceType * GetClosestFacePoint(const CoordType &p, CoordType &closestP)
Get the closest face and the closest point on it.
Definition: curve_on_manifold.h:293
bool RoundingSnap(CoordType &ip, const FaceType &f) const
Definition: curve_on_manifold.h:890
bool SnapPolyline(MeshType &poly)
SnapPolyline snaps the vertexes of a polyline onto the base mesh.
Definition: curve_on_manifold.h:371
bool OnCutSeam(const Location &loc) const
Definition: curve_on_manifold.h:951
int CollapseNullEdges(MeshType &poly)
Merge the two ends of every zero-length polyline edge.
Definition: curve_on_manifold.h:625
static bool BarycentricSnap(CoordType &ip, const FaceType &f, ScalarType barThr, ScalarType distThr)
BarycentricSnap() with explicit thresholds, e.g. rounding-level ones.
Definition: curve_on_manifold.h:724
void MoveAndProject(MeshType &poly, int iterNum, ScalarType moveWeight, ScalarType projectWeight, PositionFunctor &desiredPos)
MoveAndProject.
Definition: curve_on_manifold.h:1158
FaceType * GetClosestFaceIP(const CoordType &p, CoordType &ip, CoordType &in)
Get the closest face, barycentric coordinates, and normal.
Definition: curve_on_manifold.h:280
void RefineCurveByDistance(MeshType &poly)
RefineCurve.
Definition: curve_on_manifold.h:784
void TraceSegment(const CoordType &p, const CoordType &q, std::vector< CoordType > &crossings)
Definition: curve_on_manifold.h:986
int ConnectCrossings(MeshType &poly)
Make the points where strands meet into junctions (opt-in).
Definition: curve_on_manifold.h:482
void Init()
Initialize the CoM data structures for processing.
Definition: curve_on_manifold.h:585
bool IsSnappedVertex(CoordType &ip, int &vi)
Check if a barycentric coordinate is snapped to a vertex.
Definition: curve_on_manifold.h:329
bool IsSnappedEdge(CoordType &ip, int &ei)
Check if a barycentric coordinate is snapped to an edge.
Definition: curve_on_manifold.h:312
Main Class of the Sampling framework.
Definition: point_sampling.h:476
Definition: point_sampling.h:137
static void Box(ComputeMeshType &m)
Calculates the bounding box of the given mesh m.
Definition: bounding.h:45
static void PerVertexQualityRamp(MeshType &m, ScalarType minq=0., ScalarType maxq=0., vcg::ColorMap cmap=vcg::ColorMap::RGB)
This function colores all the faces of a mesh with a hue color shade dependent on the quality.
Definition: color.h:222
Management, updating and computation of per-vertex and per-face flags (like border flags).
Definition: flag.h:44
static void PerFaceNormalized(ComputeMeshType &m)
Equivalent to PerFace() and NormalizePerFace()
Definition: normal.h:276
static void VertexConstant(MeshType &m, VertexQualityType q)
Definition: quality.h:67
Generation of per-vertex and per-face topological information.
Definition: topology.h:43
static void VertexFace(MeshType &m)
Update the Vertex-Face topological relation.
Definition: topology.h:467
static void FaceFace(MeshType &m)
Update the Face-Face topological relation by allowing to retrieve for each face what other faces shar...
Definition: topology.h:395
static void TestVertexEdge(MeshType &m)
Test correctness of VEtopology.
Definition: topology.h:584
void ForEachVertex(const MeshType &m, Callable action)
Definition: foreach.h:126
bool IsBorder(FaceType const &f, const int j)
Definition: topology.h:55
Definition: color4.h:30
Definition: curve_on_manifold.h:1671
LaplacianFunctor basic Laplacian smoothing functor.
Definition: curve_on_manifold.h:1071
QualityDistanceFieldFunctor quality field based smoothing functor.
Definition: curve_on_manifold.h:1105