Skip to content

Commit f1524bb

Browse files
authored
Decimate Polyline3 (#172)
* Decimate Polyline3 * grammar
1 parent fd23368 commit f1524bb

File tree

5 files changed

+121
-36
lines changed

5 files changed

+121
-36
lines changed

source/MREAlgorithms/MREPolylineDecimate.cpp

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,21 @@ EdgeId collapseEdge( PolylineTopology & topology, const EdgeId e )
5050
return eNext != e ? eNext : EdgeId();
5151
}
5252

53+
template<typename V>
5354
class PolylineDecimator
5455
{
5556
public:
56-
PolylineDecimator( Polyline2 & polyline, const DecimatePolylineSettings & settings );
57+
PolylineDecimator( MR::Polyline<V> & polyline, const DecimatePolylineSettings<V> & settings );
5758
DecimatePolylineResult run();
5859

5960
// returns true if the collapse of given edge is permitted by the region and settings
6061
bool isInRegion( EdgeId e ) const;
6162

6263
private:
63-
Polyline2 & polyline_;
64-
const DecimatePolylineSettings & settings_;
64+
MR::Polyline<V> & polyline_;
65+
const DecimatePolylineSettings<V> & settings_;
6566
const float maxErrorSq_;
66-
Vector<QuadraticForm2f, VertId> vertForms_;
67+
Vector<QuadraticForm<V>, VertId> vertForms_;
6768
struct QueueElement
6869
{
6970
float c = 0;
@@ -77,12 +78,13 @@ class PolylineDecimator
7778
class EdgeMetricCalc;
7879

7980
void initializeQueue_();
80-
QueueElement computeQueueElement_( UndirectedEdgeId ue, QuadraticForm2f * outCollapseForm = nullptr, Vector2f * outCollapsePos = nullptr ) const;
81+
QueueElement computeQueueElement_( UndirectedEdgeId ue, QuadraticForm<V> * outCollapseForm = nullptr, V * outCollapsePos = nullptr ) const;
8182
void addInQueueIfMissing_( UndirectedEdgeId ue );
82-
VertId collapse_( EdgeId edgeToCollapse, const Vector2f & collapsePos );
83+
VertId collapse_( EdgeId edgeToCollapse, const V & collapsePos );
8384
};
8485

85-
PolylineDecimator::PolylineDecimator( Polyline2 & polyline, const DecimatePolylineSettings & settings )
86+
template<typename V>
87+
PolylineDecimator<V>::PolylineDecimator( MR::Polyline<V> & polyline, const DecimatePolylineSettings<V> & settings )
8688
: polyline_( polyline )
8789
, settings_( settings )
8890
, maxErrorSq_( sqr( settings.maxError ) )
@@ -96,7 +98,8 @@ static bool isRegionEdge( const PolylineTopology & topology, EdgeId e, const Ver
9698
return region->test( topology.org( e ) ) && region->test( topology.dest( e ) );
9799
}
98100

99-
bool PolylineDecimator::isInRegion( EdgeId e ) const
101+
template<typename V>
102+
bool PolylineDecimator<V>::isInRegion( EdgeId e ) const
100103
{
101104
if ( !isRegionEdge( polyline_.topology, e, settings_.region ) )
102105
return false;
@@ -110,10 +113,11 @@ bool PolylineDecimator::isInRegion( EdgeId e ) const
110113
return true;
111114
}
112115

113-
class PolylineDecimator::EdgeMetricCalc
116+
template<typename V>
117+
class PolylineDecimator<V>::EdgeMetricCalc
114118
{
115119
public:
116-
EdgeMetricCalc( const PolylineDecimator & decimator ) : decimator_( decimator ) { }
120+
EdgeMetricCalc( const PolylineDecimator<V> & decimator ) : decimator_( decimator ) { }
117121
EdgeMetricCalc( EdgeMetricCalc & x, tbb::split ) : decimator_( x.decimator_ ) { }
118122
void join( EdgeMetricCalc & y ) { auto yes = y.takeElements(); elems_.insert( elems_.end(), yes.begin(), yes.end() ); }
119123

@@ -137,13 +141,14 @@ class PolylineDecimator::EdgeMetricCalc
137141
}
138142

139143
public:
140-
const PolylineDecimator & decimator_;
144+
const PolylineDecimator<V> & decimator_;
141145
std::vector<QueueElement> elems_;
142146
};
143147

144-
MR::QuadraticForm2f computeFormAtVertex( const MR::Polyline2 & polyline, MR::VertId v, float stabilizer )
148+
template<typename V>
149+
MR::QuadraticForm<V> computeFormAtVertex( const MR::Polyline<V> & polyline, MR::VertId v, float stabilizer )
145150
{
146-
QuadraticForm2f qf;
151+
QuadraticForm<V> qf;
147152

148153
const auto e = polyline.topology.edgeWithOrg( v );
149154
qf.addDistToLine( polyline.edgeVector( e ).normalized() );
@@ -157,7 +162,8 @@ MR::QuadraticForm2f computeFormAtVertex( const MR::Polyline2 & polyline, MR::Ver
157162
return qf;
158163
}
159164

160-
void PolylineDecimator::initializeQueue_()
165+
template<typename V>
166+
void PolylineDecimator<V>::initializeQueue_()
161167
{
162168
MR_TIMER;
163169

@@ -186,7 +192,8 @@ void PolylineDecimator::initializeQueue_()
186192
queue_ = std::priority_queue<QueueElement>{ std::less<QueueElement>(), calc.takeElements() };
187193
}
188194

189-
auto PolylineDecimator::computeQueueElement_( UndirectedEdgeId ue, QuadraticForm2f * outCollapseForm, Vector2f * outCollapsePos ) const -> QueueElement
195+
template<typename V>
196+
auto PolylineDecimator<V>::computeQueueElement_( UndirectedEdgeId ue, QuadraticForm<V> * outCollapseForm, V * outCollapsePos ) const -> QueueElement
190197
{
191198
QueueElement res;
192199
res.uedgeId = ue;
@@ -203,7 +210,8 @@ auto PolylineDecimator::computeQueueElement_( UndirectedEdgeId ue, QuadraticForm
203210
return res;
204211
}
205212

206-
void PolylineDecimator::addInQueueIfMissing_( UndirectedEdgeId ue )
213+
template<typename V>
214+
void PolylineDecimator<V>::addInQueueIfMissing_( UndirectedEdgeId ue )
207215
{
208216
EdgeId e{ ue };
209217
if ( !isInRegion( e ) )
@@ -215,7 +223,8 @@ void PolylineDecimator::addInQueueIfMissing_( UndirectedEdgeId ue )
215223
queue_.push( qe );
216224
}
217225

218-
VertId PolylineDecimator::collapse_( EdgeId edgeToCollapse, const Vector2f & collapsePos )
226+
template<typename V>
227+
VertId PolylineDecimator<V>::collapse_( EdgeId edgeToCollapse, const V & collapsePos )
219228
{
220229
auto & topology = polyline_.topology;
221230
const auto vo = topology.org( edgeToCollapse );
@@ -236,7 +245,8 @@ VertId PolylineDecimator::collapse_( EdgeId edgeToCollapse, const Vector2f & col
236245
return topology.hasVert( vo ) ? vo : VertId{};
237246
}
238247

239-
DecimatePolylineResult PolylineDecimator::run()
248+
template<typename V>
249+
DecimatePolylineResult PolylineDecimator<V>::run()
240250
{
241251
MR_TIMER;
242252

@@ -261,8 +271,8 @@ DecimatePolylineResult PolylineDecimator::run()
261271
continue;
262272
}
263273

264-
QuadraticForm2f collapseForm;
265-
Vector2f collapsePos;
274+
QuadraticForm<V> collapseForm;
275+
V collapsePos;
266276
auto qe = computeQueueElement_( topQE.uedgeId, &collapseForm, &collapsePos );
267277

268278
if ( qe.c > topQE.c )
@@ -293,18 +303,40 @@ DecimatePolylineResult PolylineDecimator::run()
293303
return res_;
294304
}
295305

296-
DecimatePolylineResult decimatePolyline( Polyline2 & polyline, const DecimatePolylineSettings & settings )
306+
DecimatePolylineResult decimatePolyline( MR::Polyline2 & polyline, const DecimatePolylineSettings2 & settings )
297307
{
298308
MR_TIMER;
299309
//MR_POLYLINE_WRITER( polyline );
300-
PolylineDecimator md( polyline, settings );
310+
PolylineDecimator<Vector2f> md( polyline, settings );
301311
return md.run();
302312
}
303313

304-
DecimatePolylineResult decimateContour( Contour2f& contour, const DecimatePolylineSettings& settings )
314+
DecimatePolylineResult decimatePolyline( MR::Polyline3 & polyline, const DecimatePolylineSettings3 & settings )
305315
{
306316
MR_TIMER;
307-
Polyline2 p( { contour } );
317+
//MR_POLYLINE_WRITER( polyline );
318+
PolylineDecimator<Vector3f> md( polyline, settings );
319+
return md.run();
320+
}
321+
322+
DecimatePolylineResult decimateContour( Contour2f& contour, const DecimatePolylineSettings2& settings )
323+
{
324+
MR_TIMER;
325+
MR::Polyline2 p( { contour } );
326+
auto res = decimatePolyline( p, settings );
327+
auto resContours = p.contours();
328+
assert ( p.contours().size() == 1 );
329+
if ( !p.contours().empty() )
330+
contour = p.contours()[0];
331+
else
332+
contour.clear();
333+
return res;
334+
}
335+
336+
DecimatePolylineResult decimateContour( Contour3f& contour, const DecimatePolylineSettings3& settings )
337+
{
338+
MR_TIMER;
339+
MR::Polyline3 p( { contour } );
308340
auto res = decimatePolyline( p, settings );
309341
auto resContours = p.contours();
310342
assert ( p.contours().size() == 1 );
@@ -362,12 +394,12 @@ TEST( MRMesh, DecimatePolyline )
362394

363395
for( auto& cont : testContours )
364396
{
365-
DecimatePolylineSettings settings;
397+
DecimatePolylineSettings2 settings;
366398
settings.maxDeletedVertices = 3;
367399
settings.maxError = 100.f;
368400
settings.touchBdVertices = false;
369401

370-
Polyline2 pl( { cont } );
402+
MR::Polyline2 pl( { cont } );
371403
auto plBack = pl;
372404
auto decRes = decimatePolyline( pl, settings );
373405

source/MREAlgorithms/MREPolylineDecimate.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace MRE
1414
*
1515
* \sa \ref decimatePolyline
1616
*/
17+
template<typename V>
1718
struct DecimatePolylineSettings
1819
{
1920
/// Limit from above on the maximum distance from moved vertices to original contour
@@ -34,15 +35,18 @@ struct DecimatePolylineSettings
3435
* and its origin vertex will get new position (provided as the second argument) after collapse;
3536
* If the callback returns false, then the collapse is prohibited
3637
*/
37-
std::function<bool( MR::EdgeId edgeToCollapse, const MR::Vector2f& newEdgeOrgPos )> preCollapse;
38+
std::function<bool( MR::EdgeId edgeToCollapse, const V & newEdgeOrgPos )> preCollapse;
3839
/**
3940
* \brief If not null, then
4041
* on input: if the vector is not empty then it is takes for initialization instead of form computation for all vertices;
4142
* on output: quadratic form for each remaining vertex is returned there
4243
*/
43-
MR::Vector<MR::QuadraticForm2f, MR::VertId>* vertForms = nullptr;
44+
MR::Vector<MR::QuadraticForm<V>, MR::VertId>* vertForms = nullptr;
4445
};
4546

47+
using DecimatePolylineSettings2 = DecimatePolylineSettings<MR::Vector2f>;
48+
using DecimatePolylineSettings3 = DecimatePolylineSettings<MR::Vector3f>;
49+
4650
/**
4751
* \struct MRE::DecimatePolylineResult
4852
* \brief Results of MRE::decimateContour
@@ -57,12 +61,14 @@ struct DecimatePolylineResult
5761
* \brief Collapse edges in the polyline according to the settings
5862
* \ingroup DecimateGroup
5963
*/
60-
MREALGORITHMS_API DecimatePolylineResult decimatePolyline( MR::Polyline2& polyline, const DecimatePolylineSettings& settings = {} );
64+
MREALGORITHMS_API DecimatePolylineResult decimatePolyline( MR::Polyline2& polyline, const DecimatePolylineSettings2& settings = {} );
65+
MREALGORITHMS_API DecimatePolylineResult decimatePolyline( MR::Polyline3& polyline, const DecimatePolylineSettings3& settings = {} );
6166

6267
/**
6368
* \brief Collapse edges in the contour according to the settings
6469
* \ingroup DecimateGroup
6570
*/
66-
MREALGORITHMS_API DecimatePolylineResult decimateContour( MR::Contour2f& contour, const DecimatePolylineSettings& settings = {} );
71+
MREALGORITHMS_API DecimatePolylineResult decimateContour( MR::Contour2f& contour, const DecimatePolylineSettings2& settings = {} );
72+
MREALGORITHMS_API DecimatePolylineResult decimateContour( MR::Contour3f& contour, const DecimatePolylineSettings3& settings = {} );
6773

6874
} //namespace MRE

source/MRMesh/MRMeshFwd.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,19 @@ using LineSegm3d = LineSegm3<double>;
160160

161161
template <typename V> using Contour = std::vector<V>;
162162
template <typename T> using Contour2 = Contour<Vector2<T>>;
163+
template <typename T> using Contour3 = Contour<Vector3<T>>;
163164
using Contour2d = Contour2<double>;
164-
using Contours2d = std::vector<Contour2d>;
165165
using Contour2f = Contour2<float>;
166-
using Contours2f = std::vector<Contour2f>;
166+
using Contour3d = Contour3<double>;
167+
using Contour3f = Contour3<float>;
168+
169+
template <typename V> using Contours = std::vector<Contour<V>>;
170+
template <typename T> using Contours2 = Contours<Vector2<T>>;
171+
template <typename T> using Contours3 = Contours<Vector3<T>>;
172+
using Contours2d = Contours2<double>;
173+
using Contours2f = Contours2<float>;
174+
using Contours3d = Contours3<double>;
175+
using Contours3f = Contours3<float>;
167176

168177
template <typename T> using Contour3 = Contour<Vector3<T>>;
169178
using Contour3d = Contour3<double>;

source/MRMesh/MRPolyline.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,27 @@ Polyline<V>::Polyline( const Contours2f& contours )
2727
if constexpr ( V::elements == 2 )
2828
points.emplace_back( p.x, p.y );
2929
else
30-
points.emplace_back( p.x, p.y, 0.0f );
30+
points.emplace_back( p.x, p.y, 0.0f );
31+
return points.backId();
32+
}
33+
);
34+
}
35+
36+
template<typename V>
37+
Polyline<V>::Polyline( const Contours3f& contours )
38+
{
39+
MR_TIMER
40+
topology.buildFromContours( contours,
41+
[&points = this->points]( size_t sz )
42+
{
43+
points.reserve( sz );
44+
},
45+
[&points = this->points]( const Vector3f & p )
46+
{
47+
if constexpr ( V::elements == 2 )
48+
points.emplace_back( p.x, p.y );
49+
else
50+
points.push_back( p );
3151
return points.backId();
3252
}
3353
);
@@ -95,7 +115,19 @@ Box<V> Polyline<V>::computeBoundingBox( const AffineXf<V> * toWorld ) const
95115
}
96116

97117
template<typename V>
98-
Contours2f Polyline<V>::contours() const
118+
Contours<V> Polyline<V>::contours() const
119+
{
120+
MR_TIMER
121+
return topology.convertToContours<V>(
122+
[&points = this->points]( VertId v )
123+
{
124+
return points[v];
125+
}
126+
);
127+
}
128+
129+
template<typename V>
130+
Contours2f Polyline<V>::contours2() const
99131
{
100132
MR_TIMER
101133
return topology.convertToContours<Vector2f>(

source/MRMesh/MRPolyline.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ struct Polyline
1919

2020
Polyline() = default;
2121

22-
/// creates polyline from 2d contours
22+
/// creates polyline from 2D contours, 3D polyline will get zero z-component
2323
MRMESH_API Polyline( const Contours2f& contours );
24+
/// creates polyline from 3D contours, 2D polyline will lose z-component
25+
MRMESH_API Polyline( const Contours3f& contours );
2426

2527
/// adds connected line in this, passing progressively via points *[vs, vs+num)
2628
/// \details if closed argument is true then the last and the first points will be additionally connected
@@ -66,7 +68,11 @@ struct Polyline
6668

6769
/// convert Polyline to simple contour structures with vector of points inside
6870
/// \details if all even edges are consistently oriented, then the output contours will be oriented the same
69-
MRMESH_API Contours2f contours() const;
71+
MRMESH_API Contours<V> contours() const;
72+
73+
/// convert Polyline to simple 2D contour structures with vector of points inside
74+
/// \details if all even edges are consistently oriented, then the output contours will be oriented the same
75+
MRMESH_API Contours2f contours2() const;
7076

7177
/// convert Polyline3 to Polyline2 or vice versa
7278
template<typename U>

0 commit comments

Comments
 (0)