68 auto inputVertexIdentifiers =
static_cast<SimplexId *
>(address);
69 for(
size_t i = 0; i < size; i++) {
75 if(triangl !=
nullptr) {
81 template <
typename triangulationType = AbstractTriangulation>
82 int execute(
const triangulationType &triangulation);
103 template <
typename triangulationType>
104 int subdivise(
Quadrangulation &qd,
const triangulationType &triangulation);
117 template <
typename triangulationType>
118 SimplexId findEdgeMiddle(
const std::array<SimplexId, 2> &e,
119 const triangulationType &triangulation)
const;
131 SimplexId findQuadBary(std::vector<float> &sum,
const Quad &quad)
const;
138 template <
typename triangulationType>
139 float getBoundingBoxDiagonal(
const triangulationType &triangulation)
const;
141 template <
typename triangulationType>
142 void computeHausdorff(std::vector<float> &hausdorff,
144 const triangulationType &triangulation)
const;
212template <
typename triangulationType>
214 const std::array<SimplexId, 2> &e,
215 const triangulationType &triangulation)
const {
218 float minValue{std::numeric_limits<float>::infinity()};
234 if(m != std::numeric_limits<float>::infinity()
235 && n != std::numeric_limits<float>::infinity()) {
237 sum += std::abs(m - n);
242 triangulation.getVertexPoint(i, curr[0], curr[1], curr[2]);
256template <
typename triangulationType>
257int ttk::QuadrangulationSubdivision::subdivise(
261 std::vector<Quad> tmp{};
266 outputPoints_.reserve(outputPoints_.size() * 5);
268 vertexDistance_.resize(outputPoints_.size());
271 qd.
setInputPoints(this->outputPoints_.size(), this->outputPoints_.data());
272 qd.
setInputCells(this->outputQuads_.size(), this->outputQuads_.data());
277#ifdef TTK_ENABLE_OPENMP
278#pragma omp parallel for num_threads(threadNumber_)
280 for(
size_t i = 0; i < outputPoints_.size(); ++i) {
283 if(vertexDistance_[i].empty()) {
286 std::set<SimplexId> bounds{};
290 for(
const auto v : this->outputQuads_[cid]) {
294 bounds.emplace(nearestVertexIdentifier_[v]);
300 {bounds.begin(), bounds.end()});
304 std::vector<SimplexId> quadBaryId(this->outputQuads_.size());
305 std::vector<float> sum{};
307#ifdef TTK_ENABLE_OPENMP
308#pragma omp parallel for num_threads(threadNumber_) firstprivate(sum)
310 for(
size_t i = 0; i < this->outputQuads_.size(); ++i) {
311 quadBaryId[i] = this->findQuadBary(sum, this->outputQuads_[i]);
316#ifdef TTK_ENABLE_OPENMP
317#pragma omp parallel for num_threads(threadNumber_)
320 edgeMidId[i] = this->findEdgeMiddle(qd.
getEdge(i), triangulation);
325 for(
size_t a = 0; a < this->outputQuads_.size(); ++a) {
326 const auto &q{this->outputQuads_[a]};
329 if(processedEdges[e] == -1) {
330 const auto midab{edgeMidId[e]};
332 triangulation.getVertexPoint(midab, pt[0], pt[1], pt[2]);
334 this->outputPoints_.emplace_back(pt);
336 this->outputVertType_.emplace_back(1);
338 this->nearestVertexIdentifier_.emplace_back(midab);
340 processedEdges[e] = this->outputPoints_.size() - 1;
342 return processedEdges[e];
351 const auto baryid = quadBaryId[a];
354 triangulation.getVertexPoint(baryid, bary[0], bary[1], bary[2]);
358 outputPoints_.emplace_back(bary);
359 outputVertType_.emplace_back(2);
360 nearestVertexIdentifier_.emplace_back(baryid);
363 tmp.emplace_back(Quad{q[0], ij, baryIdx, li});
364 tmp.emplace_back(Quad{q[1], jk, baryIdx, ij});
365 tmp.emplace_back(Quad{q[2], kl, baryIdx, jk});
366 tmp.emplace_back(Quad{q[3], li, baryIdx, kl});
370 auto currSubd = outputSubdivision_.back() + 1;
371 auto subdBeg = outputSubdivision_.size();
372 outputSubdivision_.resize(outputPoints_.size());
374 outputSubdivision_.begin() + subdBeg, outputSubdivision_.end(), currSubd);
376 this->
printMsg(
"Subdivised " + std::to_string(outputQuads_.size())
377 +
" quads into " + std::to_string(tmp.size())
378 +
" new quads (" + std::to_string(outputPoints_.size())
380 1.0, tm.getElapsedTime(), this->threadNumber_);
382 outputQuads_ = std::move(tmp);
387template <
typename triangulationType>
388float ttk::QuadrangulationSubdivision::getBoundingBoxDiagonal(
389 const triangulationType &triangulation)
const {
391 std::array<float, 3> pmin{std::numeric_limits<float>::max(),
392 std::numeric_limits<float>::max(),
393 std::numeric_limits<float>::max()};
394 std::array<float, 3> pmax{std::numeric_limits<float>::min(),
395 std::numeric_limits<float>::min(),
396 std::numeric_limits<float>::min()};
398 for(
SimplexId i = 0; i < triangulation.getNumberOfVertices(); ++i) {
399 std::array<float, 3> p{};
400 triangulation.getVertexPoint(i, p[0], p[1], p[2]);
401 pmax[0] = std::max(pmax[0], p[0]);
402 pmax[1] = std::max(pmax[1], p[1]);
403 pmax[2] = std::max(pmax[2], p[2]);
404 pmin[0] = std::min(pmin[0], p[0]);
405 pmin[1] = std::min(pmin[1], p[1]);
406 pmin[2] = std::min(pmin[2], p[2]);
412template <
typename triangulationType>
413void ttk::QuadrangulationSubdivision::computeHausdorff(
414 std::vector<float> &hausdorff,
415 const Quadrangulation &qd,
416 const triangulationType &triangulation)
const {
420 hausdorff.resize(qd.getNumberOfVertices());
426 const auto bboxDiag = getBoundingBoxDiagonal(triangulation);
429 std::vector<SimplexId> nearestQuadVert(triangulation.getNumberOfVertices());
431#ifdef TTK_ENABLE_OPENMP
432#pragma omp parallel for num_threads(this->getThreadNumber())
434 for(
size_t i = 0; i < nearestQuadVert.size(); ++i) {
435 float minDist{std::numeric_limits<float>::infinity()};
436 std::array<float, 3> p{};
437 triangulation.getVertexPoint(i, p[0], p[1], p[2]);
439 for(
SimplexId j = 0; j < qd.getNumberOfVertices(); ++j) {
440 std::array<float, 3> q{};
441 qd.getVertexPoint(j, q[0], q[1], q[2]);
445 nearestQuadVert[i] = j;
451 std::vector<std::vector<SimplexId>> nearestTriVerts(qd.getNumberOfVertices());
452 for(
SimplexId i = 0; i < triangulation.getNumberOfVertices(); ++i) {
453 nearestTriVerts[nearestQuadVert[i]].emplace_back(i);
456#ifdef TTK_ENABLE_OPENMP
457#pragma omp parallel for num_threads(this->getThreadNumber())
459 for(
size_t i = 0; i < nearestTriVerts.size(); ++i) {
460 std::array<float, 3> q{};
461 qd.getVertexPoint(i, q[0], q[1], q[2]);
463 for(
const auto v : nearestTriVerts[i]) {
464 std::array<float, 3> p{};
465 triangulation.getVertexPoint(v, p[0], p[1], p[2]);
471 hausdorff[i] = maxDist / bboxDiag / nearestQuadVert.size() * 1e8;
474 this->
printMsg(
"Computed Hausdorff distance", 1.0, tm.getElapsedTime(),
480template <
typename triangulationType>
482 const triangulationType &triangulation) {
484 this->
printMsg(
"Beginning computation...");
491 if(LockAllInputVertices) {
492 LockInputExtrema =
true;
496 for(
size_t i = 0; i < inputVertexNumber_; i++) {
497 outputPoints_.emplace_back(inputVertices_[i]);
501 for(
size_t i = 0; i < inputQuadNumber_; i++) {
502 outputQuads_.emplace_back(inputQuads_[i]);
506 outputVertType_.resize(outputPoints_.size());
507 std::fill(outputVertType_.begin(), outputVertType_.end(), 0);
510 outputSubdivision_.resize(outputPoints_.size());
511 std::fill(outputSubdivision_.begin(), outputSubdivision_.end(), 0);
515 qd.setDebugLevel(this->debugLevel_);
518 for(
size_t i = 0; i < SubdivisionLevel; i++) {
522 subdivise(qd, triangulation);
525 qd.setInputPoints(this->outputPoints_.size(), this->outputPoints_.data());
526 qd.setInputCells(this->outputQuads_.size(), this->outputQuads_.data());
529 qd.preconditionVertexNeighbors();
530 qd.preconditionVertexStars();
532 if(this->RelaxationIterations > 0) {
535 std::vector<char> mask(this->outputPoints_.size(), 1);
536 if(this->LockAllInputVertices) {
538 for(
size_t i = 0; i < this->inputVertexNumber_; ++i) {
541 }
else if(this->LockInputExtrema) {
543 for(
SimplexId i = 0; i < qd.getNumberOfVertices(); ++i) {
544 if(qd.isVertexExtraordinary(i)) {
552 worker.setThreadNumber(this->threadNumber_);
553 worker.execute(
reinterpret_cast<float *
>(this->outputPoints_.data()),
554 reinterpret_cast<float *
>(this->outputPoints_.data()),
555 mask.data(), this->nearestVertexIdentifier_.data(),
556 this->RelaxationIterations, qd, triangulation);
559 qd.computeStatistics(this->outputValences_, this->outputDensity_,
560 this->outputDifformity_, this->quadArea_,
561 this->quadDiagsRatio_, this->quadEdgesRatio_,
562 this->quadAnglesRatio_);
563 this->computeHausdorff(this->hausdorff_, qd, triangulation);
565 bool criterion =
false;
566 for(
size_t i = 0; i < outputPoints_.size(); ++i) {
567 if(outputValences_[i] > 4) {
570 if(hausdorff_[i] > HausdorffLevel) {
578 this->printErr(
"The output quadrangulation exceeds the provided Haussdorff "
579 "distance tolerance");
586 this->
printMsg(
"Produced " + std::to_string(outputQuads_.size())
587 +
" quadrangles with " + std::to_string(outputPoints_.size())
boost::tuple< double, double > Point
AbstractTriangulation is an interface class that defines an interface for efficient traversal methods...
virtual SimplexId getNumberOfVertices() const
virtual int setThreadNumber(const int threadNumber)
Minimalist debugging class.
void setDebugMsgPrefix(const std::string &prefix)
virtual int setDebugLevel(const int &debugLevel)
Replacement for std::vector<std::vector<SimplexId>>
TTK processing package for the topological simplification of scalar data.
std::vector< float > quadAnglesRatio_
FlatJaggedArray quadNeighbors_
std::vector< float > outputDensity_
unsigned int RelaxationIterations
unsigned int inputVertexNumber_
std::vector< Point > outputPoints_
void setInputVertices(void *const address, unsigned int size)
void setLockInputExtrema(const bool value)
std::vector< Quad > outputQuads_
void setSubdivisionLevel(const unsigned int value)
std::vector< float > quadEdgesRatio_
std::vector< float > outputDifformity_
void setLockAllInputVertices(const bool value)
unsigned int SubdivisionLevel
std::vector< float > quadArea_
void setShowResError(const bool value)
std::vector< SimplexId > nearestVertexIdentifier_
std::vector< SimplexId > outputVertType_
std::vector< float > hausdorff_
QuadrangulationSubdivision()
std::vector< float > quadDiagsRatio_
int execute(const triangulationType &triangulation)
void setHausdorffLevel(const float value)
void preconditionTriangulation(AbstractTriangulation *const triangl)
std::vector< SimplexId > outputValences_
void setInputVertexIdentifiers(void *const address, unsigned int size)
std::vector< std::vector< float > > vertexDistance_
unsigned int inputQuadNumber_
std::vector< SimplexId > outputSubdivision_
void setRelaxationIterations(const unsigned int value)
bool LockAllInputVertices
void setInputQuads(void *const address, unsigned int size)
SimplexId getVertexStar(const SimplexId v, const int l) const
const std::array< SimplexId, 2 > & getEdge(const SimplexId e) const
ttk::SurfaceGeometrySmoother::Point Point
Ad-hoc vertex coordinates data structure (3 floats)
int preconditionVertexStars()
std::array< ttk::LongSimplexId, 4 > Quad
Ad-hoc quad data structure (4 vertex ids)
SimplexId getNumberOfEdges() const
void setInputCells(const SimplexId cellNumber, void *const quadCells)
SimplexId getVertexStarNumber(const SimplexId v) const
void setInputPoints(const SimplexId pointNumber, void *const pointCoords)
SimplexId getCellEdge(const SimplexId c, const int l)
TTK VTK-filter for smoothing meshes on surfaces.
void preconditionTriangulationSurface(AbstractTriangulation *const triangulation)
int shortestPath(const SimplexId source, const triangulationType &triangulation, std::vector< T > &outputDists, const std::vector< SimplexId > &bounds=std::vector< SimplexId >(), const std::vector< bool > &mask=std::vector< bool >())
Compute the Dijkstra shortest path from source.
T distance(const T *p0, const T *p1, const int &dimension=3)
long long int LongSimplexId
Identifier type for simplices of any dimension.
int SimplexId
Identifier type for simplices of any dimension.
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)