| 564 | } |
| 565 | |
| 566 | int reducePath( const Mesh & mesh, const MeshTriPoint & start, SurfacePath & path, const MeshTriPoint & end, int maxIter ) |
| 567 | { |
| 568 | if ( maxIter <= 0 ) |
| 569 | return 0; |
| 570 | MR_TIMER; |
| 571 | |
| 572 | // consider points on degenerate edges as points in vertices |
| 573 | for ( auto & e : path ) |
| 574 | { |
| 575 | if ( !e.inVertex() && mesh.edgeLengthSq( e.e ) <= 0 ) |
| 576 | { |
| 577 | e.a = 0; |
| 578 | assert( e.inVertex() ); |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | SurfacePath newPath; |
| 583 | newPath.reserve( path.size() ); |
| 584 | SurfacePath cacheOneSideUnfold; |
| 585 | std::vector<Vector2f> tmp; |
| 586 | std::vector<std::pair<int,int>> vertSpans; |
| 587 | SurfacePath rpoints; // to be added next in the new path in reverse order |
| 588 | tbb::enumerable_thread_specific<TriangleStripUnfolder> stripPerThread( std::cref( mesh ) ); |
| 589 | for ( int i = 0; i < maxIter; ++i ) |
| 590 | { |
| 591 | std::atomic<bool> pathTopologyChanged{false}; |
| 592 | |
| 593 | // try to exit from vertices and remove repeating locations |
| 594 | int j = 0; |
| 595 | // there are points to add in newPath |
| 596 | auto hasNext = [&]() |
| 597 | { |
| 598 | return !rpoints.empty() || j < path.size(); |
| 599 | }; |
| 600 | // returns next point to add in newPath, if extract=false then it will be returned again next time |
| 601 | auto takeNext = [&]( bool extract ) |
| 602 | { |
| 603 | MeshEdgePoint res; |
| 604 | if ( !rpoints.empty() ) |
| 605 | { |
| 606 | res = rpoints.back(); |
| 607 | if ( extract ) |
| 608 | rpoints.pop_back(); |
| 609 | } |
| 610 | else |
| 611 | { |
| 612 | res = path[j]; |
| 613 | if ( extract ) |
| 614 | ++j; |
| 615 | } |
| 616 | return res; |
| 617 | }; |
| 618 | // remove last point from newPath and mark topology as changed |
| 619 | auto newPathPopBack = [&]() |
| 620 | { |
| 621 | newPath.pop_back(); |
| 622 | pathTopologyChanged.store( true, std::memory_order_relaxed ); |
| 623 | }; |
no test coverage detected