1 /**************************************************************************** 2 * VCGLib o o * 3 * Visual and Computer Graphics Library o o * 4 * _ O _ * 5 * Copyright(C) 2004-2017 \/)\/ * 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 24 #ifndef _VCGLIB_VORONOI_REMESHER_H 25 #define _VCGLIB_VORONOI_REMESHER_H 26 27 #include <vcg/complex/complex.h> 28 #include <vcg/complex/algorithms/update/topology.h> 29 #include <vcg/complex/algorithms/refine.h> 30 #include <vcg/complex/algorithms/clean.h> 31 #include <vcg/complex/algorithms/voronoi_processing.h> 32 #include <vcg/complex/algorithms/point_sampling.h> 33 #include <vcg/complex/algorithms/crease_cut.h> 34 //#include <vcg/complex/algorithms/curve_on_manifold.h> 35 36 #include <memory> 37 #include <string> 38 #include <vector> 39 #include <map> 40 #include <unordered_map> 41 #include <unordered_set> 42 #include <cmath> 43 #include <array> 44 #include <utility> 45 46 47 //#define DEBUG_VORO 1 48 49 #ifdef DEBUG_VORO 50 #include <wrap/io_trimesh/export.h> 51 #include <QString> 52 #include <QElapsedTimer> 53 #endif 54 55 namespace vcg { 56 namespace tri { 57 58 class VoroEdgeMeshAux 59 { 60 class EmEdgeType; 61 class EmVertexType; 62 class EUsedTypes : public vcg::UsedTypes<vcg::Use<EmVertexType>::AsVertexType, 63 vcg::Use<EmEdgeType>::AsEdgeType> {}; 64 class EmVertexType : public vcg::Vertex<EUsedTypes 65 ,vcg::vertex::Normal3d 66 , vcg::vertex::Coord3d 67 , vcg::vertex::BitFlags 68 , vcg::vertex::VEAdj> {}; 69 class EmEdgeType : public vcg::Edge<EUsedTypes 70 , vcg::edge::VertexRef 71 , vcg::edge::BitFlags 72 , vcg::edge::EEAdj 73 , vcg::edge::VEAdj> {}; 74 public: 75 class EdgeMeshType : public vcg::tri::TriMesh<std::vector<EmVertexType>, std::vector<EmEdgeType> > 76 { 77 public: ~EdgeMeshType()78 ~EdgeMeshType() 79 { 80 this->Clear(); 81 this->ClearAttributes(); 82 } 83 }; 84 }; 85 86 template <class MeshType> 87 class Remesher 88 { 89 public: 90 typedef Remesher ThisType; 91 92 typedef MeshType Mesh; 93 typedef typename Mesh::ScalarType ScalarType; 94 typedef typename Mesh::CoordType CoordType; 95 typedef typename Mesh::FaceType FaceType; 96 typedef typename Mesh::FacePointer FacePointer; 97 typedef typename Mesh::VertexType VertexType; 98 typedef typename Mesh::VertexPointer VertexPointer; 99 typedef typename Mesh::FaceIterator FaceIterator; 100 typedef typename Mesh::VertexIterator VertexIterator; 101 102 typedef std::shared_ptr<Mesh> MeshPtr; 103 104 protected: 105 typedef face::Pos<FaceType> PosType; 106 107 typedef typename VoroEdgeMeshAux::EdgeMeshType EdgeMeshType; 108 109 /// \brief splitCC split the provided mesh into connected components. 110 /// \param mesh the inputMesh. 111 /// \return the vector of connected components (meshes) for the input model 112 /// (if the input mesh is a single connected component returns an empty vector). 113 /// splitCC(MeshType & mesh)114 inline static std::vector<MeshPtr> splitCC(MeshType & mesh) 115 { 116 std::vector<MeshPtr> ret; 117 118 // find the connected components 119 std::vector<std::pair<int, typename MeshType::FacePointer> > CCV; 120 Clean<MeshType>::ConnectedComponents(mesh, CCV); 121 122 if (CCV.size() == 1) 123 return ret; 124 for(size_t i=0; i<CCV.size(); ++i) 125 { 126 UpdateSelection<MeshType>::Clear(mesh); 127 CCV[i].second->SetS(); 128 UpdateSelection<MeshType>::FaceConnectedFF(mesh); 129 ret.push_back(std::make_shared<MeshType>()); 130 Append<MeshType, MeshType>::MeshCopy(*(ret.back()), mesh, true); 131 } 132 133 return ret; 134 } 135 136 public: 137 static const int VoroRelaxationStep = 10; 138 139 /// 140 /// \brief Remesh the main function that remeshes a mesh preserving creases. 141 /// \param original the mesh 142 /// \param samplingRadius is the sampling radius for remeshing 143 /// \param borderCreaseAngleDeg is the angle treshold for preserving corner points on the mesh boundary 144 /// \param internalCreaseAngleDeg is the angle treshold for preserving creases on the mesh surface (if this value is < 0 it is set to borderCreaseAngleDeg) 145 /// \return the remeshed mesh 146 /// 147 static inline MeshPtr Remesh(Mesh & original, const ScalarType samplingRadius, const ScalarType borderCreaseAngleDeg = 0.0, const ScalarType internalCreaseAngleDeg = -1.0) 148 { 149 RequireFFAdjacency(original); 150 RequireVFAdjacency(original); 151 152 UpdateTopology<Mesh>::FaceFace(original); 153 UpdateFlags<Mesh>::FaceBorderFromFF(original); 154 UpdateFlags<Mesh>::VertexBorderFromFaceAdj(original); 155 156 if (Clean<Mesh>::CountNonManifoldEdgeFF(original) > 0) 157 { 158 std::cout << "Input mesh has non manifold edges" << std::endl; 159 return nullptr; 160 } 161 162 const ScalarType borderAngleDeg = std::max(ScalarType(0), borderCreaseAngleDeg); 163 const ScalarType creaseAngleDeg = internalCreaseAngleDeg < 0 ? borderAngleDeg : internalCreaseAngleDeg; 164 165 // split on creases 166 if (creaseAngleDeg > 0) 167 { 168 CreaseCut<Mesh>(original, vcg::math::ToRad(creaseAngleDeg)); 169 Allocator<Mesh>::CompactEveryVector(original); 170 UpdateTopology<Mesh>::FaceFace(original); 171 UpdateFlags<Mesh>::FaceBorderFromFF(original); 172 UpdateFlags<Mesh>::VertexBorderFromFaceAdj(original); 173 } 174 175 // Mark the non manifold border vertices as visited on the input mesh 176 // TODO maybe optimize this 177 { 178 // extract border mesh 179 EdgeMeshType em; 180 ThisType::ExtractMeshBorders(original, em); 181 182 // get the border edge mesh and leave the non manifold vertices only 183 tri::Allocator<EdgeMeshType>::CompactEveryVector(em); 184 vcg::tri::Clean<EdgeMeshType>::SelectNonManifoldVertexOnEdgeMesh(em); 185 for (EdgeMeshType::VertexType & v : em.vert) 186 { 187 if (!v.IsS()) 188 { 189 tri::Allocator<EdgeMeshType>::DeleteVertex(em, v); 190 } 191 } 192 tri::Allocator<EdgeMeshType>::CompactVertexVector(em); 193 194 195 // clear visited vertices 196 tri::UpdateFlags<Mesh>::VertexClearV(original); 197 if (em.vn != 0) 198 { 199 // iterate over the mesh and mark as visited all the matching vertices with the non manifold border 200 tri::UpdateBounding<EdgeMeshType>::Box(em); 201 EdgeMeshType::BoxType bbox = em.bbox; 202 bbox.Offset(bbox.Diag()/1000.0); 203 typedef SpatialHashTable<EdgeMeshType::VertexType, EdgeMeshType::ScalarType> HashVertexGrid; 204 HashVertexGrid HG; 205 HG.Set(em.vert.begin(), em.vert.end(), bbox); 206 207 typedef EdgeMeshType::CoordType Coord; 208 EdgeMeshType::ScalarType dist_upper_bound = bbox.Diag()/1000.0; 209 for (VertexType & v : original.vert) 210 { 211 EdgeMeshType::ScalarType dist; 212 EdgeMeshType::VertexType * nonManifoldVertex = GetClosestVertex<EdgeMeshType,HashVertexGrid>(em, HG, Coord::Construct(v.cP()), dist_upper_bound, dist); 213 if (nonManifoldVertex != NULL && dist == 0) 214 { 215 v.SetV(); 216 } 217 } 218 } 219 220 } 221 #ifdef DEBUG_VORO 222 io::Exporter<Mesh>::Save(original, "creaseSplit.ply", io::Mask::IOM_VERTCOLOR); 223 #endif 224 225 // One CC 226 std::vector<MeshPtr> ccs = splitCC(original); 227 if (ccs.empty()) 228 { 229 return RemeshOneCC(original, samplingRadius, borderAngleDeg); 230 } 231 232 // Multiple CCs 233 // std::cout << "Remeshing " << ccs.size() << " components" << std::endl; 234 for (size_t i=0; i<ccs.size(); i++) 235 { 236 // std::cout << "Remeshing component " << (i+1) << "/" << ccs.size() << std::endl; 237 ccs[i] = RemeshOneCC(*ccs[i], samplingRadius, borderAngleDeg, i); 238 } 239 240 MeshPtr ret = std::make_shared<Mesh>(); 241 for (MeshPtr & mesh : ccs) 242 { 243 Append<Mesh,Mesh>::Mesh(*ret, *mesh); 244 } 245 Clean<Mesh>::RemoveDuplicateVertex(*ret, true); 246 return ret; 247 } 248 249 protected: debugCallBack(const int pos,const char * str)250 static bool debugCallBack(const int pos, const char * str) { printf("Processing: %s \n",str); fflush(stdout); return true;} 251 252 /// 253 /// \brief RemeshOneCC the function that remeshes a single connected component mesh preserving its boundary (consistently for eventually adjacent meshes). 254 /// \param original the mesh 255 /// \param samplingRadius is the sampling radius for remeshing 256 /// \param borderCreaseAngleDeg is the angle treshold for preserving corner points on the mesh boundary 257 /// \return the remeshed mesh 258 /// 259 static inline MeshPtr RemeshOneCC(Mesh & original, const ScalarType samplingRadius, const ScalarType borderCreaseAngleDeg = 0.0, int idx = 0) 260 { 261 // double timeBorders = 0; 262 // double timePoisson = 0; 263 // double timeRelax = 0; 264 // double timeSeed = 0; 265 // double timeSources = 0; 266 // double timeDelaunay = 0; 267 // QElapsedTimer timer; 268 // timer.start(); 269 270 (void)idx; 271 272 RequireCompactness(original); 273 RequirePerFaceFlags(original); 274 275 UpdateTopology<Mesh>::FaceFace(original); 276 UpdateFlags<Mesh>::FaceBorderFromFF(original); 277 UpdateFlags<Mesh>::VertexBorderFromFaceAdj(original); 278 279 #ifdef DEBUG_VORO 280 io::ExporterPLY<MeshType>::Save(original, QString("cc_%1.ply").arg(idx).toStdString().c_str(), io::Mask::IOM_VERTCOLOR); 281 #endif 282 283 // Resample border 284 Mesh poissonEdgeMesh; 285 { 286 typedef typename EdgeMeshType::CoordType Coord; 287 288 EdgeMeshType em; 289 ThisType::ExtractMeshBorders(original, em); 290 Allocator<EdgeMeshType>::CompactVertexVector(em); 291 Allocator<EdgeMeshType>::CompactEdgeVector(em); 292 // split on non manifold vertices of edgemesh 293 vcg::tri::Clean<EdgeMeshType>::SelectNonManifoldVertexOnEdgeMesh(em); 294 { 295 // select also the visited vertices (coming from the non manifold vertices of the whole crease-cut mesh) 296 for (auto & v : em.vert) 297 { 298 if (v.IsV()) { v.SetS(); } 299 } 300 } 301 const int manifoldSplits = vcg::tri::Clean<EdgeMeshType>::SplitSelectedVertexOnEdgeMesh(em); 302 (void)manifoldSplits; 303 304 #ifdef DEBUG_VORO 305 std::cout << manifoldSplits << " non-manifold splits" << std::endl; 306 io::ExporterOBJ<EdgeMeshType>::Save(em, QString("edgeMesh_%1.obj").arg(idx).toStdString().c_str(), io::Mask::IOM_EDGEINDEX); 307 #endif 308 309 // eventually split on 'creases' 310 if (borderCreaseAngleDeg > 0.0) 311 { 312 // split creases 313 UpdateFlags<EdgeMeshType>::VertexClearS(em); 314 UpdateFlags<EdgeMeshType>::VertexClearV(em); 315 Clean<EdgeMeshType>::SelectCreaseVertexOnEdgeMesh(em, vcg::math::ToRad(borderCreaseAngleDeg)); 316 const int splits = Clean<EdgeMeshType>::SplitSelectedVertexOnEdgeMesh(em); 317 (void)splits; 318 319 #ifdef DEBUG_VORO 320 std::cout << splits << " splits" << std::endl; 321 io::ExporterOBJ<EdgeMeshType>::Save(em, QString("edgeMesh_split_%1.obj").arg(idx).toStdString().c_str(), io::Mask::IOM_EDGEINDEX); 322 #endif 323 } 324 325 // Samples vector 326 std::vector<Coord> borderSamples; 327 TrivialSampler<EdgeMeshType> ps(borderSamples); 328 329 // uniform edge sampling 330 UpdateTopology<EdgeMeshType>::EdgeEdge(em); 331 SurfaceSampling<EdgeMeshType>::EdgeMeshUniform(em, ps, samplingRadius, SurfaceSampling<EdgeMeshType>::Round); 332 BuildMeshFromCoordVector(poissonEdgeMesh, borderSamples); 333 UpdateBounding<Mesh>::Box(poissonEdgeMesh); 334 335 // remove duplicate vertices 336 Clean<Mesh>::RemoveDuplicateVertex(poissonEdgeMesh, false); 337 Allocator<Mesh>::CompactVertexVector(poissonEdgeMesh); 338 339 // select all vertices (to mark them fixed) 340 UpdateFlags<Mesh>::VertexSetS(poissonEdgeMesh); 341 342 #ifdef DEBUG_VORO 343 io::ExporterPLY<MeshType>::Save(poissonEdgeMesh, QString("borderMesh_%1.ply").arg(idx).toStdString().c_str(), io::Mask::IOM_VERTCOLOR); 344 #endif 345 } 346 347 // timeBorders = timer.restart() / 1000.0; 348 349 typedef VoronoiProcessing<Mesh> Voronoi; 350 typedef TrivialSampler<Mesh> BaseSampler; 351 typedef SurfaceSampling<Mesh, BaseSampler> SurfaceSampler; 352 typedef SurfaceSampling<Mesh, FixSampler> SurfaceFixSampler; 353 354 // copy original mesh 355 Mesh baseMesh; 356 Append<Mesh, Mesh>::MeshCopy(baseMesh, original, false, true); 357 358 // refine to obtain a base mesh 359 VoronoiProcessingParameter vpp; 360 vpp.refinementRatio = 5.0f; 361 vpp.lcb = debugCallBack; 362 363 Voronoi::PreprocessForVoronoi(baseMesh, samplingRadius, vpp); 364 365 // Poisson sampling preserving border 366 std::vector<CoordType> seedPointVec; 367 std::vector<bool> seedFixedVec; 368 FixSampler fix_sampler(seedPointVec, seedFixedVec); 369 370 // montecarlo sampler 371 std::vector<CoordType> sampleVec; 372 BaseSampler mps(sampleVec); 373 374 // NOTE in order to make the results consistent the random sampling generator is initialized with the same value 375 SurfaceSampler::SamplingRandomGenerator().initialize(5489u); 376 377 // Montecarlo oversampling 378 Mesh montecarloMesh; 379 // const int poissonCount = SurfaceSampler::ComputePoissonSampleNum(original, samplingRadius)/* * 0.7*/; 380 int poissonCount = 0; 381 { 382 const ScalarType meshArea = Stat<Mesh>::ComputeMeshArea(original); 383 const ScalarType meshBoundary = Stat<Mesh>::ComputeBorderLength(original); 384 const double factor = math::Sqrt(3)/2; 385 const ScalarType areaPerSample = samplingRadius*samplingRadius * factor; 386 poissonCount = meshArea / areaPerSample - meshBoundary * samplingRadius * factor * 0.5; // totalArea / (r^2 * sqrt(3)/2) - (totalBoundary * r * sqrt(3)/4) 387 } 388 389 // std::cout << "poisson Count: " << poissonCount << std::endl; 390 if (poissonCount <= 0) 391 { 392 // no need for internal sampling 393 for (auto vi = poissonEdgeMesh.vert.begin(); vi != poissonEdgeMesh.vert.end(); vi++) 394 { 395 fix_sampler.AddVert(*vi); 396 } 397 } 398 else 399 { 400 // Montecarlo poisson sampling 401 SurfaceSampler::MontecarloPoisson(original, mps, poissonCount * 50); 402 BuildMeshFromCoordVector(montecarloMesh,sampleVec); 403 404 #ifdef DEBUG_VORO 405 io::ExporterPLY<MeshType>::Save(montecarloMesh, QString("montecarloMesh_%1.ply").arg(idx).toStdString().c_str()); 406 #endif 407 408 // Poisson disk pruning initialized with edges 409 typename SurfaceFixSampler::PoissonDiskParam pp; 410 pp.preGenMesh = &poissonEdgeMesh; 411 pp.preGenFlag = true; 412 pp.bestSampleChoiceFlag = true; 413 pp.bestSamplePoolSize = 10; 414 pp.randomSeed = 7; 415 SurfaceFixSampler::PoissonDiskPruning(fix_sampler, montecarloMesh, samplingRadius, pp); 416 417 } 418 419 #ifdef DEBUG_VORO 420 Mesh poissonMesh; 421 BuildMeshFromCoordVector(poissonMesh,seedPointVec); 422 io::ExporterPLY<MeshType>::Save(poissonMesh, QString("poissonMesh_%1.ply").arg(idx).toStdString().c_str()); 423 #endif 424 425 // timePoisson = timer.restart() / 1000.0; 426 427 // std::cout << "poisson samples " << seedPointVec.size() << std::endl; 428 429 // not enough points 430 if (seedPointVec.size() < 3) 431 { 432 return std::make_shared<Mesh>(); 433 } 434 435 // TODO: rimettere a posto 436 // restricted relaxation with fixed points 437 Voronoi::RandomGenerator().initialize(5489u); 438 vpp.seedPerturbationProbability = 0.2f; 439 vpp.seedPerturbationAmount = 0.005f; 440 Voronoi::RestrictedVoronoiRelaxing(baseMesh, seedPointVec, seedFixedVec, VoroRelaxationStep, vpp); 441 vpp.seedPerturbationProbability = 0.0f; 442 Voronoi::RestrictedVoronoiRelaxing(baseMesh, seedPointVec, seedFixedVec, VoroRelaxationStep/2, vpp); 443 // Voronoi::RestrictedVoronoiRelaxing(baseMesh, seedPointVec, seedFixedVec, VoroRelaxationStep, vpp); 444 445 446 #ifdef DEBUG_VORO 447 BuildMeshFromCoordVector(poissonMesh,seedPointVec); 448 io::ExporterPLY<MeshType>::Save(poissonMesh, QString("relaxedMesh_%1.ply").arg(idx).toStdString().c_str()); 449 #endif 450 451 // timeRelax = timer.restart() / 1000.0; 452 453 // FAIL? 454 MeshPtr finalMeshPtr = std::make_shared<Mesh>(); 455 std::vector<VertexType *> seedVertexVec; 456 // Voronoi::SeedToVertexConversion(baseMesh, seedPointVec, seedVertexVec, false); 457 ThisType::SeedToFixedBorderVertexConversion(baseMesh, samplingRadius, seedPointVec, seedFixedVec, seedVertexVec); 458 EuclideanDistance<Mesh> dd; 459 // timeSeed = timer.restart() / 1000.0; 460 461 // std::cout << "BEGIN compute vertex sources (basemesh vn:" << baseMesh.VN() << " fn:" << baseMesh.FN() << ")" << std::endl; 462 Voronoi::ComputePerVertexSources(baseMesh, seedVertexVec, dd); 463 // std::cout << "END compute vertex sources" << std::endl; 464 // timeSources = timer.restart() / 1000.0; 465 // traditional 466 // Voronoi::ConvertDelaunayTriangulationToMesh(baseMesh, *finalMeshPtr, seedVertexVec, false); 467 // border-preserving 468 Voronoi::ConvertDelaunayTriangulationExtendedToMesh(baseMesh, *finalMeshPtr, seedVertexVec); 469 470 #ifdef DEBUG_VORO 471 io::ExporterPLY<MeshType>::Save(*finalMeshPtr, QString("voroMesh_%1.ply").arg(idx).toStdString().c_str()); 472 io::ExporterPLY<MeshType>::Save(baseMesh, QString("baseMesh_%1.ply").arg(idx).toStdString().c_str(), io::Mask::IOM_VERTCOLOR); 473 #endif 474 475 // timeDelaunay = timer.elapsed() / 1000.0; 476 477 // std::cout << "border: " << timeBorders << std::endl 478 // << "poisson: " << timePoisson << std::endl 479 // << "relax: " << timeRelax << std::endl 480 // << "seed: " << timeSeed << std::endl 481 // << "sources: " << timeSources << std::endl 482 // << "delaunay: " << timeDelaunay << std::endl; 483 484 return finalMeshPtr; 485 } 486 ExtractMeshBorders(Mesh & mesh,EdgeMeshType & sides)487 static inline void ExtractMeshBorders(Mesh & mesh, EdgeMeshType & sides) 488 { 489 RequireFFAdjacency(mesh); 490 491 // clean the edge mesh containing the borders 492 sides.Clear(); 493 494 // gather into separate vertices lists 495 std::vector<std::vector<VertexType *> > edges; 496 497 for (auto fi = mesh.face.begin(); fi != mesh.face.end(); fi++) 498 { 499 for (int e=0; e<fi->VN(); e++) 500 { 501 if (vcg::face::IsBorder(*fi, e)) 502 { 503 std::vector<VertexType *> tmp; 504 tmp.push_back(fi->V(e)); 505 tmp.push_back(fi->V((e+1)%fi->VN())); 506 edges.push_back(tmp); 507 } 508 } 509 } 510 511 // convert to edge mesh 512 for (auto & e : edges) 513 { 514 assert(e.size() >= 2); 515 516 std::vector<typename EdgeMeshType::VertexType *> newVtx; 517 518 // insert new vertices and store their pointer 519 auto vi = Allocator<EdgeMeshType>::AddVertices(sides, e.size()); 520 for (const auto & v : e) 521 { 522 vi->ImportData(*v); 523 newVtx.push_back(&(*vi++)); 524 } 525 526 auto ei = Allocator<EdgeMeshType>::AddEdges(sides, e.size() - 1); 527 for (int i=0; i<static_cast<int>(e.size() - 1); i++) 528 { 529 ei->V(0) = newVtx[i]; 530 ei->V(1) = newVtx[i+1]; 531 ei++; 532 } 533 } 534 535 Clean<EdgeMeshType>::RemoveDuplicateVertex(sides); 536 } 537 SeedToFixedBorderVertexConversion(MeshType & m,const ScalarType samplingRadius,const std::vector<CoordType> & seedPVec,const std::vector<bool> & seedFixed,std::vector<VertexType * > & seedVVec)538 static void SeedToFixedBorderVertexConversion(MeshType & m, 539 const ScalarType samplingRadius, 540 const std::vector<CoordType> & seedPVec, 541 const std::vector<bool> & seedFixed, 542 std::vector<VertexType *> & seedVVec) 543 { 544 typedef typename vcg::SpatialHashTable<VertexType, ScalarType> HashVertexGrid; 545 seedVVec.clear(); 546 547 UpdateTopology<MeshType>::FaceFace(m); 548 UpdateFlags<MeshType>::VertexBorderFromFaceAdj(m); 549 550 typename MeshType::BoxType bbox = m.bbox; 551 bbox.Offset(bbox.Diag()/100.0); 552 553 // internal vertices grid 554 HashVertexGrid HG; 555 HG.Set(m.vert.begin(),m.vert.end(), bbox); 556 557 // boundary vertices grid 558 MeshType borderMesh; 559 HashVertexGrid borderHG; 560 { 561 // get border vertices and build another mesh 562 std::vector<CoordType> borderPts; 563 for (auto vit=m.vert.begin(); vit!=m.vert.end(); vit++) 564 { 565 if (!vit->IsD() && vit->IsB()) 566 borderPts.push_back(vit->cP()); 567 } 568 if (!borderPts.empty()) 569 { 570 BuildMeshFromCoordVector(borderMesh,borderPts); 571 borderMesh.bbox = m.bbox; 572 borderHG.Set(borderMesh.vert.begin(), borderMesh.vert.end(), bbox); 573 } 574 } 575 576 const ScalarType dist_upper_bound=samplingRadius*4; 577 VertexType * vp = NULL; 578 579 for( size_t i = 0; i < seedPVec.size(); i++) 580 { 581 const CoordType & p = seedPVec[i]; 582 const bool fixed = seedFixed[i]; 583 if (!fixed) 584 { 585 ScalarType dist; 586 vp = GetClosestVertex<MeshType,HashVertexGrid>(m, HG, p, dist_upper_bound, dist); 587 if (vp) 588 { 589 seedVVec.push_back(vp); 590 } 591 } 592 else 593 { 594 vp = NULL; 595 596 ScalarType dist; 597 VertexType * borderVp = GetClosestVertex<MeshType,HashVertexGrid>(borderMesh, borderHG, p, dist_upper_bound, dist); 598 599 if (borderVp) 600 { 601 std::vector<ScalarType> dist; 602 std::vector<VertexType *> vps; 603 std::vector<CoordType> pts; 604 605 // vp = GetClosestVertex<MeshType,HashVertexGrid>(m, HG, borderVp->cP(), dist_upper_bound, dist); 606 unsigned int n = GetKClosestVertex<MeshType,HashVertexGrid>(m, HG, 16, borderVp->cP(), dist_upper_bound, vps, dist, pts); 607 if (n>0) 608 { 609 ScalarType d = dist[0]; 610 seedVVec.push_back(vps[0]); 611 assert(dist.size() == size_t(n)); 612 for (size_t j=1; j<dist.size(); j++) 613 { 614 if (dist[j] <= d) 615 { 616 seedVVec.push_back(vps[j]); 617 d = dist[j]; 618 } 619 else 620 { 621 break; 622 } 623 } 624 } 625 } 626 } 627 } 628 } 629 630 631 632 /// 633 /// \brief The FixSampler class is used with poisson disk pruning to preserve selected vertices and 634 /// keep an auxiliary vector indicating wether the sample is fixed or not 635 /// 636 class FixSampler 637 { 638 public: 639 typedef typename MeshType::CoordType CoordType; 640 typedef typename MeshType::VertexType VertexType; 641 FixSampler(std::vector<CoordType> & samples,std::vector<bool> & fixed)642 FixSampler(std::vector<CoordType> & samples, std::vector<bool> & fixed) 643 : sampleVec(samples) 644 , fixedVec (fixed) 645 { 646 reset(); 647 } 648 reset()649 void reset() 650 { 651 sampleVec.clear(); 652 fixedVec .clear(); 653 } 654 AddVert(const VertexType & p)655 void AddVert(const VertexType &p) 656 { 657 sampleVec.push_back(p.cP()); 658 fixedVec .push_back(p.IsS()); 659 } 660 661 private: 662 std::vector<CoordType> & sampleVec; 663 std::vector<bool> & fixedVec; 664 }; 665 666 }; 667 } // end namespace tri 668 } // end namespace vcg 669 670 #endif // _VCGLIB_VORONOI_REMESHER_H 671