MeshLib Documentation
Loading...
Searching...
No Matches
MREdgePathsBuilder.h
Go to the documentation of this file.
1#pragma once
2
3#include "MREdgePaths.h"
4#include "MRBitSet.h"
5#include "MRMesh.h"
6#include "MRRingIterator.h"
7#include "MRphmap.h"
8#include "MRMacros.h"
9#include <queue>
10
11namespace MR
12{
13
16
19{
20 // edge from this vertex to its predecessor in the forest
21 EdgeId back;
22 // best summed metric to reach this vertex
23 float metric = FLT_MAX;
24
25 bool isStart() const { return !back.valid(); }
26};
27
28// ParallelHashMap here was significantly slower (especially in debug version of tunnel detection),
29// probably because of more allocations
31
33template<class MetricToPenalty>
35{
36public:
37 EdgePathsBuilderT( const MeshTopology & topology, const EdgeMetric & metric );
38 // compares proposed metric with best value known for startVert;
39 // if proposed metric is smaller then adds it in the queue and returns true
40 bool addStart( VertId startVert, float startMetric );
41
42 // information about just reached vertex (with final metric value)
44 {
45 VertId v;
46 // edge from this vertex to its predecessor in the forest (if this vertex is not start)
47 EdgeId backward;
48 // the penalty to reach this vertex
49 float penalty = FLT_MAX;
50 // summed metric to reach this vertex
51 float metric = FLT_MAX;
52 };
53
54 // include one more vertex in the final forest, returning vertex-info for the newly reached vertex;
55 // returns invalid VertId in v-field if no more vertices left
56 ReachedVert reachNext();
57 // adds steps for all origin ring edges of the reached vertex;
58 // returns true if at least one step was added
59 bool addOrgRingSteps( const ReachedVert & rv );
60 // the same as reachNext() + addOrgRingSteps()
61 ReachedVert growOneEdge();
62
63public:
64 // returns true if further edge forest growth is impossible
65 bool done() const { return nextSteps_.empty(); }
66 // returns path length till the next candidate vertex or maximum float value if all vertices have been reached
67 float doneDistance() const { return nextSteps_.empty() ? FLT_MAX : nextSteps_.top().penalty; }
68 // gives read access to the map from vertex to path to it
69 const VertPathInfoMap & vertPathInfoMap() const { return vertPathInfoMap_; }
70 // returns one element from the map (or nullptr if the element is missing)
71 const VertPathInfo * getVertInfo( VertId v ) const;
72
73 // returns the path in the forest from given vertex to one of start vertices
74 EdgePath getPathBack( VertId backpathStart ) const;
75
76protected:
78
79private:
80 const MeshTopology & topology_;
81 EdgeMetric metric_;
82 VertPathInfoMap vertPathInfoMap_;
83
84 struct CandidateVert
85 {
86 VertId v;
87 // best penalty to reach this vertex
88 float penalty = FLT_MAX;
89
90 // smaller penalty to be the first
91 friend bool operator <( const CandidateVert & a, const CandidateVert & b )
92 {
93 return a.penalty > b.penalty;
94 }
95 };
96 std::priority_queue<CandidateVert> nextSteps_;
97
98 // compares proposed step with the value known for org( c.back );
99 // if proposed step is smaller then adds it in the queue and returns true;
100 // otherwise if the known metric to org( c.back ) is already not greater than returns false
101 bool addNextStep_( const VertPathInfo & c );
102};
103
106{
107 float operator()( float metric, VertId ) const { return metric; }
108};
109
111
112template<class MetricToPenalty>
114 : topology_( topology )
115 , metric_( metric )
116{
117}
118
119template<class MetricToPenalty>
120bool EdgePathsBuilderT<MetricToPenalty>::addStart( VertId startVert, float startMetric )
121{
122 auto & vi = vertPathInfoMap_[startVert];
123 if ( vi.metric > startMetric )
124 {
125 vi = { EdgeId{}, startMetric };
126 nextSteps_.push( CandidateVert{ startVert, metricToPenalty_( startMetric, startVert ) } );
127 return true;
128 }
129 return false;
130}
131
132template<class MetricToPenalty>
134{
135 auto it = vertPathInfoMap_.find( v );
136 return ( it != vertPathInfoMap_.end() ) ? &it->second : nullptr;
137}
138
139template<class MetricToPenalty>
141{
142 EdgePath res;
143 for (;;)
144 {
145 auto it = vertPathInfoMap_.find( v );
146 if ( it == vertPathInfoMap_.end() )
147 {
148 assert( false );
149 break;
150 }
151 auto & vi = it->second;
152 if ( vi.isStart() )
153 break;
154 res.push_back( vi.back );
155 v = topology_.dest( vi.back );
156 }
157 return res;
158}
159
160template<class MetricToPenalty>
162{
163 if ( !( c.metric < FLT_MAX ) )
164 return false; // maximal or infinity metric means that this path shall be skipped
165 const auto vert = topology_.org( c.back );
166 auto & vi = vertPathInfoMap_[vert];
167 if ( vi.metric > c.metric )
168 {
169 vi = c;
170 nextSteps_.push( CandidateVert{ vert, metricToPenalty_( c.metric, vert ) } );
171 return true;
172 }
173 return false;
174}
175
176template<class MetricToPenalty>
178{
179 bool aNextStepAdded = false;
180 if ( !rv.v )
181 {
182 assert( !rv.backward );
183 return aNextStepAdded;
184 }
185 const float orgMetric = rv.metric;
186 const EdgeId back = rv.backward ? rv.backward : topology_.edgeWithOrg( rv.v );
187 for ( EdgeId e : orgRing( topology_, back ) )
188 {
189 VertPathInfo c;
190 c.back = e.sym();
191 c.metric = orgMetric + metric_( e );
192 aNextStepAdded = addNextStep_( c ) || aNextStepAdded;
193 }
194 return aNextStepAdded;
195}
196
197template<class MetricToPenalty>
199{
200 while ( !nextSteps_.empty() )
201 {
202 const auto c = nextSteps_.top();
203 nextSteps_.pop();
204 auto & vi = vertPathInfoMap_[c.v];
205 if ( metricToPenalty_( vi.metric, c.v ) < c.penalty )
206 {
207 // shorter path to the vertex was found
208 continue;
209 }
210 assert( metricToPenalty_( vi.metric, c.v ) == c.penalty );
211 return { .v = c.v, .backward = vi.back, .penalty = c.penalty, .metric = vi.metric };
212 }
213 return {};
214}
215
216template<class MetricToPenalty>
218{
219 auto res = reachNext();
220 addOrgRingSteps( res );
221 return res;
222}
223
227{
228 const VertCoords * points = nullptr;
229 Vector3f target;
230 float operator()( float metric, VertId v ) const
231 {
232 return metric + ( (*points)[v] - target ).length();
233 }
234};
235
238class EdgePathsAStarBuilder: public EdgePathsBuilderT<MetricToAStarPenalty>
239{
240public:
241 EdgePathsAStarBuilder( const Mesh & mesh, VertId target, VertId start ) :
242 EdgePathsBuilderT( mesh.topology, edgeLengthMetric( mesh ) )
243 {
245 metricToPenalty_.target = mesh.points[target];
246 addStart( start, 0 );
247 }
248 EdgePathsAStarBuilder( const Mesh & mesh, const MeshTriPoint & target, const MeshTriPoint & start ) :
249 EdgePathsBuilderT( mesh.topology, edgeLengthMetric( mesh ) )
250 {
252 metricToPenalty_.target = mesh.triPoint( target );
253 const auto startPt = mesh.triPoint( start );
254 mesh.topology.forEachVertex( start, [&]( VertId v )
255 {
256 addStart( v, ( mesh.points[v] - startPt ).length() );
257 } );
258 }
259};
260
262
263} // namespace MR
#define MR_NO_UNIQUE_ADDRESS
Definition MRMacros.h:37
length
Definition MRObjectDimensionsEnum.h:14
Definition MREdgePathsBuilder.h:239
EdgePathsAStarBuilder(const Mesh &mesh, VertId target, VertId start)
Definition MREdgePathsBuilder.h:241
EdgePathsAStarBuilder(const Mesh &mesh, const MeshTriPoint &target, const MeshTriPoint &start)
Definition MREdgePathsBuilder.h:248
the class is responsible for finding smallest metric edge paths on a mesh
Definition MREdgePathsBuilder.h:35
ReachedVert growOneEdge()
Definition MREdgePathsBuilder.h:217
bool done() const
Definition MREdgePathsBuilder.h:65
bool addStart(VertId startVert, float startMetric)
Definition MREdgePathsBuilder.h:120
ReachedVert reachNext()
Definition MREdgePathsBuilder.h:198
float doneDistance() const
Definition MREdgePathsBuilder.h:67
bool addOrgRingSteps(const ReachedVert &rv)
Definition MREdgePathsBuilder.h:177
MR_NO_UNIQUE_ADDRESS MetricToPenalty metricToPenalty_
Definition MREdgePathsBuilder.h:77
EdgePathsBuilderT(const MeshTopology &topology, const EdgeMetric &metric)
Definition MREdgePathsBuilder.h:113
EdgePath getPathBack(VertId backpathStart) const
Definition MREdgePathsBuilder.h:140
const VertPathInfoMap & vertPathInfoMap() const
Definition MREdgePathsBuilder.h:69
const VertPathInfo * getVertInfo(VertId v) const
Definition MREdgePathsBuilder.h:133
Definition MRMesh/MRMeshTopology.h:18
void forEachVertex(const MeshTriPoint &p, T &&callback) const
Definition MRMesh/MRMeshTopology.h:571
MRMESH_API EdgeMetric edgeLengthMetric(const Mesh &mesh)
Definition MRCameraOrientationPlugin.h:8
std::function< float(EdgeId)> EdgeMetric
Definition MRMesh/MRMeshFwd.h:438
HashMap< VertId, VertPathInfo > VertPathInfoMap
Definition MREdgePathsBuilder.h:30
std::vector< EdgeId > EdgePath
Definition MRMesh/MRMeshFwd.h:98
IteratorRange< OrgRingIterator > orgRing(const MeshTopology &topology, EdgeId edge)
Definition MRRingIterator.h:70
phmap::flat_hash_map< K, V, Hash, Eq > HashMap
Definition MRMesh/MRMeshFwd.h:460
Definition MREdgePathsBuilder.h:44
float penalty
Definition MREdgePathsBuilder.h:49
EdgeId backward
Definition MREdgePathsBuilder.h:47
float metric
Definition MREdgePathsBuilder.h:51
VertId v
Definition MREdgePathsBuilder.h:45
Definition MRMesh/MRMeshTriPoint.h:23
Definition MRMesh/MRMesh.h:23
MRMESH_API Vector3f triPoint(const MeshTriPoint &p) const
computes coordinates of point given as face and barycentric representation
MeshTopology topology
Definition MRMesh/MRMesh.h:24
VertCoords points
Definition MRMesh/MRMesh.h:25
Definition MREdgePathsBuilder.h:227
Vector3f target
Definition MREdgePathsBuilder.h:229
float operator()(float metric, VertId v) const
Definition MREdgePathsBuilder.h:230
const VertCoords * points
Definition MREdgePathsBuilder.h:228
the vertices in the queue are ordered by their metric from a start location
Definition MREdgePathsBuilder.h:106
float operator()(float metric, VertId) const
Definition MREdgePathsBuilder.h:107
information associated with each vertex by the paths builder
Definition MREdgePathsBuilder.h:19
float metric
Definition MREdgePathsBuilder.h:23
EdgeId back
Definition MREdgePathsBuilder.h:21
bool isStart() const
Definition MREdgePathsBuilder.h:25