TTK
Loading...
Searching...
No Matches
SurfaceGeometrySmoother.h
Go to the documentation of this file.
1
24
25#pragma once
26
27// base code includes
28#include <Triangulation.h>
29#include <VisitedMask.h>
30
31#include <numeric>
32#include <stack>
33#include <string>
34
35namespace ttk {
36
37 class SurfaceGeometrySmoother : virtual public Debug {
38
39 public:
41 ~SurfaceGeometrySmoother() override = default;
42
44 AbstractTriangulation *const triangulation) {
45 if(triangulation != nullptr) {
46 triangulation->preconditionVertexNeighbors();
47 if(triangulation->getDimensionality() == 2) {
48 triangulation->preconditionVertexStars();
49 }
50 }
51 }
53 AbstractTriangulation *const triangulation) {
54 if(triangulation != nullptr) {
55 triangulation->preconditionEdges();
56 triangulation->preconditionVertexNeighbors();
57 triangulation->preconditionVertexEdges();
58 triangulation->preconditionTriangles();
59 triangulation->preconditionVertexTriangles();
60 triangulation->preconditionEdgeTriangles();
61 }
62 }
63
64 template <typename triangulationType0, typename triangulationType1>
65 int execute(float *const outputCoords,
66 const float *const inputCoords,
67 const char *const mask,
68 const SimplexId *const vertsId,
69 const int nIter,
70 const triangulationType0 &triangulationToSmooth,
71 const triangulationType1 &triangulationSurface) const;
72
73 struct Point : public std::array<float, 3> {
74 Point operator+(const Point other) const {
75 Point res{};
76 res[0] = (*this)[0] + other[0];
77 res[1] = (*this)[1] + other[1];
78 res[2] = (*this)[2] + other[2];
79 return res;
80 }
81 Point operator*(const float scalar) const {
82 Point res{};
83 res[0] = (*this)[0] * scalar;
84 res[1] = (*this)[1] * scalar;
85 res[2] = (*this)[2] * scalar;
86 return res;
87 }
88 Point operator-(Point other) const {
89 return *this + other * (-1);
90 }
91 Point operator/(const float scalar) const {
92 return (*this * (1.0F / scalar));
93 }
94 friend std::ostream &operator<<(std::ostream &os, const Point &pt) {
95 return os << '(' << pt[0] << " " << pt[1] << " " << pt[2] << ')';
96 }
97 };
98
99 protected:
100 template <typename triangulationType0, typename triangulationType1>
101 int relaxProject(std::vector<Point> &outputPoints,
102 std::vector<Point> &tmpStorage,
103 std::vector<SimplexId> &nearestVertexId,
104 std::vector<bool> &trianglesTested,
105 std::vector<SimplexId> &visitedTriangles,
106 std::vector<float> &dists,
107 const char *const mask,
108 const triangulationType0 &triangulationToSmooth,
109 const triangulationType1 &triangulationSurface) const;
110
125 };
126
132 size_t id;
137 };
138
139 template <typename triangulationType0, typename triangulationType1>
142 VisitedMask &trianglesTested,
143 std::vector<float> &dists,
144 std::stack<SimplexId> &trianglesToTest,
145 const bool reverseProjection,
146 const triangulationType0 &triangulationToSmooth,
147 const triangulationType1 &triangulationSurface) const;
148
157 template <typename triangulationType>
158 inline Point
160 std::vector<ttk::SurfaceGeometrySmoother::Point> &outputPoints,
161 const triangulationType &triangulationToSmooth) const {
162 Point relaxed{outputPoints[a]};
163 const auto nneigh{triangulationToSmooth.getVertexNeighborNumber(a)};
164 for(SimplexId i = 0; i < nneigh; ++i) {
165 SimplexId neigh{};
166 triangulationToSmooth.getVertexNeighbor(a, i, neigh);
167 relaxed = relaxed + outputPoints[neigh];
168 }
169 return relaxed * (1.0F / static_cast<float>(nneigh + 1));
170 }
171
181 const Point &a,
182 const Point &normTri) const {
183 const auto ap{p - a};
184 return p - normTri * Geometry::dotProduct(normTri.data(), ap.data());
185 }
186
195 inline Point
196 projectOnEdge(const Point &p, const Point &a, const Point &b) const {
197 const auto ab{b - a};
198 const auto ap{p - a};
199 return a
200 + ab * Geometry::dotProduct(ap.data(), ab.data())
201 / Geometry::dotProduct(ab.data(), ab.data());
202 }
203
212 template <typename triangulationType>
213 inline SimplexId
215 std::vector<float> &dists,
216 const triangulationType &triangulation) const {
217 for(SimplexId i = 0; i < triangulation.getNumberOfVertices(); ++i) {
218 Point pv{};
219 triangulation.getVertexPoint(i, pv[0], pv[1], pv[2]);
220 dists[i] = Geometry::distance(pa.data(), pv.data());
221 }
222 return std::min_element(dists.begin(), dists.end()) - dists.begin();
223 }
224
233 inline Point
234 computeTriangleNormal(const Point a, const Point b, const Point c) const {
235
236 // triangle normal: cross product of two edges
237 Point crossP{};
238 // ab, ac vectors
239 const Point ab = b - a;
240 const Point ac = c - a;
241 // compute ab ^ ac
242 Geometry::crossProduct(ab.data(), ac.data(), crossP.data());
243 // magnitude
244 const auto mag = Geometry::magnitude(crossP.data());
245
246 if(mag > powf(10, -FLT_DIG)) {
247 // unitary normal vector
248 return crossP / mag;
249 }
250
251 crossP[0] = -1.0F;
252 crossP[1] = -1.0F;
253 crossP[2] = -1.0F;
254 return crossP;
255 }
256
264 template <typename triangulationType>
265 Point
267 const triangulationType &triangulation) const;
268 };
269
270} // namespace ttk
271
272template <typename triangulationType>
275 const SimplexId a, const triangulationType &triangulation) const {
276
277 Point res{};
278
279 // store for each triangle in a's star a's two direct neighbors
280 std::vector<std::array<SimplexId, 2>> edges{};
281
282 const auto nStar{triangulation.getVertexStarNumber(a)};
283
284 if(triangulation.getCellVertexNumber(0) == 3) {
285 // triangle mesh
286 for(SimplexId i = 0; i < nStar; ++i) {
287 SimplexId c{};
288 triangulation.getVertexStar(a, i, c);
289 SimplexId v0{}, v1{};
290 triangulation.getCellVertex(c, 0, v0);
291 if(v0 == a) {
292 triangulation.getCellVertex(c, 1, v0);
293 } else {
294 triangulation.getCellVertex(c, 1, v1);
295 if(v1 == a) {
296 triangulation.getCellVertex(c, 2, v1);
297 }
298 }
299 edges.emplace_back(std::array<SimplexId, 2>{v0, v1});
300 }
301 } else if(triangulation.getCellVertexNumber(0) == 4) {
302 // quad mesh
303 for(SimplexId i = 0; i < nStar; ++i) {
304 SimplexId c{};
305 triangulation.getVertexStar(a, i, c);
306 std::array<SimplexId, 4> q{};
307 triangulation.getCellVertex(c, 0, q[0]);
308 triangulation.getCellVertex(c, 1, q[1]);
309 triangulation.getCellVertex(c, 2, q[2]);
310 triangulation.getCellVertex(c, 3, q[3]);
311 if(q[0] == a) {
312 edges.emplace_back(std::array<SimplexId, 2>{
313 static_cast<SimplexId>(q[3]),
314 static_cast<SimplexId>(q[1]),
315 });
316 } else if(q[1] == a) {
317 edges.emplace_back(std::array<SimplexId, 2>{
318 static_cast<SimplexId>(q[0]),
319 static_cast<SimplexId>(q[2]),
320 });
321 } else if(q[2] == a) {
322 edges.emplace_back(std::array<SimplexId, 2>{
323 static_cast<SimplexId>(q[1]),
324 static_cast<SimplexId>(q[3]),
325 });
326 } else if(q[3] == a) {
327 edges.emplace_back(std::array<SimplexId, 2>{
328 static_cast<SimplexId>(q[2]),
329 static_cast<SimplexId>(q[0]),
330 });
331 }
332 }
333 }
334
335 // current vertex 3d coordinates
336 Point pa{};
337 triangulation.getVertexPoint(a, pa[0], pa[1], pa[2]);
338
339 // triangle normals around current surface vertex
340 std::vector<Point> normals{};
341 normals.reserve(nStar);
342
343 for(auto &e : edges) {
344 Point pb{}, pc{};
345 triangulation.getVertexPoint(e[0], pb[0], pb[1], pb[2]);
346 triangulation.getVertexPoint(e[1], pc[0], pc[1], pc[2]);
347
348 const auto normal{this->computeTriangleNormal(pa, pb, pc)};
349 // ensure normal not null
350 if(normal[0] != -1.0F && normal[1] != -1.0F && normal[2] != -1.0F) {
351 // unitary normal vector
352 normals.emplace_back(normal);
353 }
354 }
355
356 if(!normals.empty()) {
357
358 // ensure normals have same direction
359 for(size_t i = 1; i < normals.size(); ++i) {
360 const auto dotProd
361 = Geometry::dotProduct(normals[0].data(), normals[i].data());
362 if(dotProd < 0.0F) {
363 normals[i] = normals[i] * -1.0F;
364 }
365 }
366
367 // compute mean of normals
368 res = std::accumulate(
369 normals.begin(), normals.end(), Point{}, std::plus<Point>());
370 res = res / static_cast<float>(normals.size());
371
372 } else {
373
374 // set error value directly in output variable...
375 res[0] = NAN;
376 }
377
378 return res;
379}
380
381template <typename triangulationType0, typename triangulationType1>
384 const ProjectionInput &pi,
385 VisitedMask &trianglesTested,
386 std::vector<float> &dists,
387 std::stack<SimplexId> &trianglesToTest,
388 const bool reverseProjection,
389 const triangulationType0 &triangulationToSmooth,
390 const triangulationType1 &triangulation) const {
391
392 ProjectionResult res{pi.pt, pi.nearestVertex, 0, false, false};
393
394 Point surfaceNormal{};
395 if(reverseProjection) {
396 surfaceNormal
397 = this->computeSurfaceNormalAtPoint(pi.id, triangulationToSmooth);
398 res.reverseProjection = !std::isnan(surfaceNormal[0]);
399 }
400
401 // clean trianglesToTest
402 while(!trianglesToTest.empty()) {
403 trianglesToTest.pop();
404 }
405
406 // init pipeline by checking in the first triangle around selected vertex
407 if(triangulation.getVertexTriangleNumber(res.nearestVertex) > 0) {
408 SimplexId next{};
409 triangulation.getVertexTriangle(res.nearestVertex, 0, next);
410 trianglesToTest.push(next);
411 }
412
413 while(!trianglesToTest.empty()) {
414 const auto curr = trianglesToTest.top();
415 trianglesToTest.pop();
416
417 // skip if already tested
418 if(trianglesTested.isVisited_[curr]) {
419 continue;
420 }
421
422 // get triangle vertices
423 std::array<SimplexId, 3> tverts{};
424 triangulation.getTriangleVertex(curr, 0, tverts[0]);
425 triangulation.getTriangleVertex(curr, 1, tverts[1]);
426 triangulation.getTriangleVertex(curr, 2, tverts[2]);
427
428 // get coordinates of triangle vertices (lets name is MNO)
429 std::array<Point, 3> mno{}; // [0] is M, [1] is N and [2] is O
430 triangulation.getVertexPoint(tverts[0], mno[0][0], mno[0][1], mno[0][2]);
431 triangulation.getVertexPoint(tverts[1], mno[1][0], mno[1][1], mno[1][2]);
432 triangulation.getVertexPoint(tverts[2], mno[2][0], mno[2][1], mno[2][2]);
433
434 const auto normTri{this->computeTriangleNormal(mno[0], mno[1], mno[2])};
435
436 static const float PREC_FLT{powf(10, -FLT_DIG)};
437
438 if(res.reverseProjection) {
439
440 const auto denom
441 = Geometry::dotProduct(surfaceNormal.data(), normTri.data());
442
443 // check if triangle plane is parallel to surface to project normal
444 if(std::abs(denom) < PREC_FLT) {
445 // fill pipeline with neighboring triangles
446 for(auto &vert : tverts) {
447 auto ntr = triangulation.getVertexTriangleNumber(vert);
448 for(SimplexId j = 0; j < ntr; ++j) {
449 SimplexId tid;
450 triangulation.getVertexTriangle(vert, j, tid);
451 if(tid != curr) {
452 trianglesToTest.push(tid);
453 }
454 }
455 }
456 continue;
457 }
458
459 // compute intersection between _surface to project normal at
460 // current vertex line_ and _reference surface triangle plane_
461 auto tmp = mno[0] - pi.pt;
462 auto alpha = Geometry::dotProduct(tmp.data(), normTri.data()) / denom;
463 res.pt = pi.pt + surfaceNormal * alpha;
464
465 } else {
466 res.pt = this->projectOnTrianglePlane(pi.pt, mno[0], normTri);
467 }
468
469 // compute barycentric coords of projection
470 Point baryCoords{};
472 mno[0].data(), mno[1].data(), mno[2].data(), res.pt.data(), baryCoords);
473
474 // check if projection in triangle
475 bool inTriangle = true;
476
477 for(auto &coord : baryCoords) {
478 if(coord < -PREC_FLT) {
479 inTriangle = false;
480 }
481 if(coord > 1 + PREC_FLT) {
482 inTriangle = false;
483 }
484 }
485
486 // mark triangle as tested
487 trianglesTested.insert(curr);
488 res.trianglesChecked++;
489
490 if(inTriangle) {
491 res.projSuccess = true;
492 // should we check if we have the nearest triangle?
493 break;
494 }
495
496 // extrema values in baryCoords
497 const auto extrema
498 = std::minmax_element(baryCoords.begin(), baryCoords.end());
499
500 // find the nearest triangle vertices local ids (with the
501 // highest/positive values in baryCoords) from proj
502 std::array<SimplexId, 2> vid{
503 static_cast<SimplexId>(extrema.second - baryCoords.begin()), 0};
504 for(size_t j = 0; j < baryCoords.size(); j++) {
505 if(j != static_cast<size_t>(extrema.first - baryCoords.begin())
506 && j != static_cast<size_t>(extrema.second - baryCoords.begin())) {
507 vid[1] = j;
508 break;
509 }
510 }
511
512 // store vertex with highest barycentric coordinate
513 res.nearestVertex = tverts[vid[0]];
514 const auto secondNearVert{tverts[vid[1]]};
515
516 // get the triangle edge with the two vertices
517 SimplexId edge{};
518 const auto nEdges{triangulation.getVertexEdgeNumber(res.nearestVertex)};
519 for(SimplexId i = 0; i < nEdges; ++i) {
520 triangulation.getVertexEdge(res.nearestVertex, i, edge);
521 SimplexId v{};
522 triangulation.getEdgeVertex(edge, 0, v);
523 if(v == res.nearestVertex) {
524 triangulation.getEdgeVertex(edge, 1, v);
525 }
526 if(v == secondNearVert) {
527 break;
528 }
529 }
530
531 // next triangle to visit
532 SimplexId next{};
533 const auto nTri{triangulation.getEdgeTriangleNumber(edge)};
534 for(SimplexId i = 0; i < nTri; ++i) {
535 triangulation.getEdgeTriangle(edge, i, next);
536 if(next != curr) {
537 break;
538 }
539 }
540
541 const auto nVisited{trianglesTested.visitedIds_.size()};
542 if(nVisited > 1 && next == trianglesTested.visitedIds_[nVisited - 2]) {
543 // the relaxed point is probably over the edge separating the
544 // current and the last visited triangles
545 res.pt = this->projectOnEdge(pi.pt, mno[vid[0]], mno[vid[1]]);
546 // check that projected point is indeed on segment
547 res.projSuccess = Geometry::isPointOnSegment(
548 res.pt.data(), mno[vid[0]].data(), mno[vid[1]].data());
549 if(!res.projSuccess) {
550 // if not, replace with nearest triangle vertex
551 triangulation.getVertexPoint(
552 tverts[vid[0]], res.pt[0], res.pt[1], res.pt[2]);
553 res.projSuccess = true;
554 }
555 break;
556 }
557
558 if(!trianglesTested.isVisited_[next]) {
559 trianglesToTest.push(next);
560 }
561 }
562
563 const size_t maxTrChecked = 100;
564
565 if(res.projSuccess && res.trianglesChecked > maxTrChecked) {
566 res.projSuccess = false;
567 }
568
569 Point nearestCoords{};
570 triangulation.getVertexPoint(
571 pi.nearestVertex, nearestCoords[0], nearestCoords[1], nearestCoords[2]);
572 if(Geometry::distance(res.pt.data(), pi.pt.data())
573 > 5.0 * Geometry::distance(res.pt.data(), nearestCoords.data())) {
574 res.projSuccess = false;
575 if(triangulationToSmooth.getDimensionality() == 2 && !reverseProjection) {
576 // clean trianglesTested
577 for(const auto t : trianglesTested.visitedIds_) {
578 trianglesTested.isVisited_[t] = false;
579 }
580 trianglesTested.visitedIds_.clear();
581 return this->findProjection(pi, trianglesTested, dists, trianglesToTest,
582 true, triangulationToSmooth, triangulation);
583 }
584 }
585
586 if(!res.projSuccess) {
587 // replace proj by the nearest vertex?
588 res.nearestVertex
589 = this->getNearestSurfaceVertex(pi.pt, dists, triangulation);
590 triangulation.getVertexPoint(
591 res.nearestVertex, res.pt[0], res.pt[1], res.pt[2]);
592 }
593
594 return res;
595}
596
597template <typename triangulationType0, typename triangulationType1>
599 std::vector<ttk::SurfaceGeometrySmoother::Point> &outputPoints,
600 std::vector<ttk::SurfaceGeometrySmoother::Point> &tmpStorage,
601 std::vector<SimplexId> &nearestVertexId,
602 std::vector<bool> &trianglesTested,
603 std::vector<SimplexId> &visitedTriangles,
604 std::vector<float> &dists,
605 const char *const mask,
606 const triangulationType0 &triangulationToSmooth,
607 const triangulationType1 &triangulationSurface) const {
608
609 Timer tm;
610 std::stack<SimplexId> trianglesToTest{};
611
612 // main loop
613#ifdef TTK_ENABLE_OPENMP
614#pragma omp parallel for num_threads(threadNumber_) \
615 firstprivate(trianglesTested, visitedTriangles, dists, trianglesToTest)
616#endif // TTK_ENABLE_OPENMP
617 for(size_t i = 0; i < outputPoints.size(); i++) {
618
619 // skip computation if i in filtered
620 if(mask != nullptr && mask[i] == 0) {
621 tmpStorage[i] = outputPoints[i];
622 continue;
623 }
624 tmpStorage[i] = this->relax(i, outputPoints, triangulationToSmooth);
625
626 VisitedMask vm{trianglesTested, visitedTriangles};
627
628 // replace curr in outputPoints_ by its projection
629 const auto res = this->findProjection(
630 ProjectionInput{i, tmpStorage[i], nearestVertexId[i]}, vm, dists,
631 trianglesToTest, false, triangulationToSmooth, triangulationSurface);
632
633 tmpStorage[i] = res.pt;
634 nearestVertexId[i] = res.nearestVertex;
635 }
636
637 std::swap(outputPoints, tmpStorage);
638
639 this->printMsg("Projected " + std::to_string(outputPoints.size()) + " points",
640 1.0, tm.getElapsedTime(), this->threadNumber_,
642
643 return 0;
644}
645
646template <typename triangulationType0, typename triangulationType1>
648 float *const outputCoords,
649 const float *const inputCoords,
650 const char *const mask,
651 const SimplexId *const vertsId,
652 const int nIter,
653 const triangulationType0 &triangulationToSmooth,
654 const triangulationType1 &triangulationSurface) const {
655
656 const auto nPoints{triangulationToSmooth.getNumberOfVertices()};
657 if(triangulationSurface.getDimensionality() != 2) {
658 this->printErr("Can only project onto a surface");
659 return -1;
660 }
661
662 if(triangulationToSmooth.getDimensionality() < 1
663 || triangulationToSmooth.getDimensionality() > 2) {
664 this->printErr("Can only project a 1D or a 2D triangulated object");
665 return -1;
666 }
667
668 Timer tm{};
669 this->printMsg("Smoothing " + std::to_string(nPoints) + " points in "
670 + std::to_string(nIter) + " iterations...");
671
672 // list of triangle IDs already tested
673 // (takes more memory to reduce computation time)
674 std::vector<bool> trianglesTested(
675 triangulationSurface.getNumberOfTriangles(), false);
676 std::vector<SimplexId> visitedTriangles{};
677 // distance between every mesh point and current point
678 std::vector<float> dists(triangulationSurface.getNumberOfVertices());
679
680 // temporary storage
681 std::vector<ttk::SurfaceGeometrySmoother::Point> outputPoints(nPoints),
682 tmpStorage(nPoints);
683 std::vector<SimplexId> nearestVertexId(nPoints);
684
685 // copy input
686#ifdef TTK_ENABLE_OPENMP
687#pragma omp parallel for num_threads(threadNumber_)
688#endif // TTK_ENABLE_OPENMP
689 for(SimplexId i = 0; i < nPoints; ++i) {
690 outputPoints[i][0] = inputCoords[3 * i + 0];
691 outputPoints[i][1] = inputCoords[3 * i + 1];
692 outputPoints[i][2] = inputCoords[3 * i + 2];
693 }
694
695 // ttkVertexScalarField is optional (helps for instance with
696 // MorseSmaleComplex 1-separatrices)
697 if(vertsId != nullptr) {
698#ifdef TTK_ENABLE_OPENMP
699#pragma omp parallel for num_threads(threadNumber_)
700#endif // TTK_ENABLE_OPENMP
701 for(SimplexId i = 0; i < nPoints; ++i) {
702 nearestVertexId[i] = vertsId[i];
703 }
704 } else {
705 // generate a ttkVertexScalarField-like point data array using raw
706 // euclidean distance between the points to smooth and every
707 // vertex of the surface
708 Timer tm_nv{};
709 this->printMsg("Computing nearest vertices...", debug::Priority::INFO,
711#ifdef TTK_ENABLE_OPENMP
712#pragma omp parallel for num_threads(threadNumber_) firstprivate(dists)
713#endif // TTK_ENABLE_OPENMP
714 for(SimplexId i = 0; i < nPoints; ++i) {
715 nearestVertexId[i] = this->getNearestSurfaceVertex(
716 outputPoints[i], dists, triangulationSurface);
717 }
718 this->printMsg("Computed nearest vertices", 1.0, tm_nv.getElapsedTime(),
719 this->threadNumber_);
720 }
721
722 for(int i = 0; i < nIter; ++i) {
723 this->relaxProject(outputPoints, tmpStorage, nearestVertexId,
724 trianglesTested, visitedTriangles, dists, mask,
725 triangulationToSmooth, triangulationSurface);
726 }
727
728 // copy output
729#ifdef TTK_ENABLE_OPENMP
730#pragma omp parallel for num_threads(threadNumber_)
731#endif // TTK_ENABLE_OPENMP
732 for(SimplexId i = 0; i < nPoints; ++i) {
733 outputCoords[3 * i + 0] = outputPoints[i][0];
734 outputCoords[3 * i + 1] = outputPoints[i][1];
735 outputCoords[3 * i + 2] = outputPoints[i][2];
736 }
737
738 this->printMsg("Smoothed " + std::to_string(nPoints) + " points", 1.0,
739 tm.getElapsedTime(), this->threadNumber_);
740
741 return 0;
742}
AbstractTriangulation is an interface class that defines an interface for efficient traversal methods...
virtual int getDimensionality() const
Minimalist debugging class.
Definition: Debug.h:88
TTK VTK-filter for smoothing meshes on surfaces.
ProjectionResult findProjection(const ProjectionInput &pi, VisitedMask &trianglesTested, std::vector< float > &dists, std::stack< SimplexId > &trianglesToTest, const bool reverseProjection, const triangulationType0 &triangulationToSmooth, const triangulationType1 &triangulationSurface) const
Point projectOnEdge(const Point &p, const Point &a, const Point &b) const
Compute euclidean projection on a 3D segment.
~SurfaceGeometrySmoother() override=default
SimplexId getNearestSurfaceVertex(const Point &pa, std::vector< float > &dists, const triangulationType &triangulation) const
Find nearest vertex on the surface.
int relaxProject(std::vector< Point > &outputPoints, std::vector< Point > &tmpStorage, std::vector< SimplexId > &nearestVertexId, std::vector< bool > &trianglesTested, std::vector< SimplexId > &visitedTriangles, std::vector< float > &dists, const char *const mask, const triangulationType0 &triangulationToSmooth, const triangulationType1 &triangulationSurface) const
int execute(float *const outputCoords, const float *const inputCoords, const char *const mask, const SimplexId *const vertsId, const int nIter, const triangulationType0 &triangulationToSmooth, const triangulationType1 &triangulationSurface) const
void preconditionTriangulationSurface(AbstractTriangulation *const triangulation)
void preconditionTriangulationToSmooth(AbstractTriangulation *const triangulation)
Point relax(const SimplexId a, std::vector< ttk::SurfaceGeometrySmoother::Point > &outputPoints, const triangulationType &triangulationToSmooth) const
Computes the barycenter of a given point's neighbors.
Point computeSurfaceNormalAtPoint(const SimplexId a, const triangulationType &triangulation) const
Compute (mean) surface normal at given surface vertex.
Point projectOnTrianglePlane(const Point &p, const Point &a, const Point &normTri) const
Compute euclidean projection in a triangle plane.
Point computeTriangleNormal(const Point a, const Point b, const Point c) const
Compute normal vector to triangle.
double getElapsedTime()
Definition: Timer.h:15
T dotProduct(const T *vA0, const T *vA1, const T *vB0, const T *vB1)
Definition: Geometry.cpp:370
bool isPointOnSegment(const T &x, const T &y, const T &xA, const T &yA, const T &xB, const T &yB)
Definition: Geometry.cpp:425
int computeBarycentricCoordinates(const T *p0, const T *p1, const T *p, std::array< T, 2 > &baryCentrics, const int &dimension=3)
Definition: Geometry.cpp:124
int crossProduct(const T *vA0, const T *vA1, const T *vB0, const T *vB1, std::array< T, 3 > &crossProduct)
Definition: Geometry.cpp:314
T magnitude(const T *v, const int &dimension=3)
Definition: Geometry.cpp:491
T distance(const T *p0, const T *p1, const int &dimension=3)
Definition: Geometry.cpp:344
The Topology ToolKit.
int SimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:22
friend std::ostream & operator<<(std::ostream &os, const Point &pt)
Point operator/(const float scalar) const
Point operator*(const float scalar) const
Point operator+(const Point other) const
Auto-cleaning re-usable graph propagations data structure.
Definition: VisitedMask.h:27
std::vector< bool > & isVisited_
Definition: VisitedMask.h:28
void insert(const SimplexId id)
Definition: VisitedMask.h:45
std::vector< SimplexId > & visitedIds_
Definition: VisitedMask.h:29
printMsg(debug::output::GREEN+"                           "+debug::output::ENDCOLOR+debug::output::GREEN+"▒"+debug::output::ENDCOLOR+debug::output::GREEN+"▒▒▒▒▒▒▒▒▒▒▒▒▒░"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)