Skip to content

Commit 7cb23ed

Browse files
authored
Introduce curve.totalLength (#5699)
* Introduce `curve.totalLength` - CurveFunc argument is now expected [0,totalLength) - Bend function: curve time now has same "space" for stretched and non-stretched mode - Remove `unitLength` argument from some functions because it is not longer needed * add include * CR Fix
1 parent 7710ae3 commit 7cb23ed

File tree

5 files changed

+51
-38
lines changed

5 files changed

+51
-38
lines changed

source/MRMesh/MRAlignContoursToMesh.cpp

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "MRMeshComponents.h"
1212
#include "MRParallelFor.h"
1313
#include "MRRegionBoundary.h"
14+
#include <cmath>
1415

1516
namespace MR
1617
{
@@ -117,6 +118,12 @@ Expected<Mesh> bendContoursAlongCurve( const Contours2f& contours, const CurveFu
117118
if ( !bbox.valid() )
118119
return unexpected( "Contours mesh is empty" );
119120

121+
if ( curve.totalLength <= 0.0f )
122+
{
123+
assert( !"invalid curve length" );
124+
return unexpected( "Invalid curve length" );
125+
}
126+
120127
const float cStartDepth = bbox.diagonal() * 0.05f; // use relative depth to avoid floating errors
121128
addBaseToPlanarMesh( contoursMesh, -cStartDepth );
122129
contoursMesh.invalidateCaches();
@@ -132,19 +139,21 @@ Expected<Mesh> bendContoursAlongCurve( const Contours2f& contours, const CurveFu
132139
VertId firstBottomVert( contoursMeshPoints.size() / 2 );
133140

134141
const auto components = MeshComponents::getAllComponents( contoursMesh );
142+
const auto stretchMod = curve.totalLength / diagonal.x;
143+
const auto startCurvePos = params.pivotCurveTime * curve.totalLength;
135144
// independently for each component of contoursMesh
136145
ParallelFor( components, [&]( size_t icomp )
137146
{
138147
const auto & compFaces = components[icomp];
139148
const auto compCenter = contoursMesh.computeBoundingBox( &compFaces ).center();
140-
float xInBoxRelPivot = compCenter.x - pivotInBoxX;
149+
float xInBox = compCenter.x - pivotInBoxX;
141150
if ( params.stretch )
142-
xInBoxRelPivot /= diagonal.x;
151+
xInBox *= stretchMod;
143152

144-
float curveTime = params.pivotCurveTime + xInBoxRelPivot;
153+
float curveTime = startCurvePos + xInBox;
145154
if ( params.periodicCurve )
146-
curveTime = curveTime - std::floor( curveTime );
147-
const auto pos = curve( curveTime );
155+
curveTime = curveTime - std::floor( curveTime / curve.totalLength ) * curve.totalLength;
156+
const auto pos = curve.func( curveTime );
148157

149158
const auto vecx = pos.dir;
150159
const auto norm = pos.snorm;
@@ -188,19 +197,19 @@ Expected<Mesh> bendContoursAlongSurfacePath( const Contours2f& contours, const M
188197
const BendContoursAlongCurveParams& params )
189198
{
190199
MR_TIMER;
191-
return curveFromPoints( meshPathCurvePoints( mesh, start, path, end ), params.stretch )
200+
return curveFromPoints( meshPathCurvePoints( mesh, start, path, end ) )
192201
.and_then( [&]( auto && curve ) { return bendContoursAlongCurve( contours, curve, params ); } );
193202
}
194203

195204
Expected<Mesh> bendContoursAlongSurfacePath( const Contours2f& contours, const Mesh& mesh, const SurfacePath& path,
196205
const BendContoursAlongCurveParams& params )
197206
{
198207
MR_TIMER;
199-
return curveFromPoints( meshPathCurvePoints( mesh, path ), params.stretch )
208+
return curveFromPoints( meshPathCurvePoints( mesh, path ) )
200209
.and_then( [&]( auto && curve ) { return bendContoursAlongCurve( contours, curve, params ); } );
201210
}
202211

203-
Expected<std::vector<float>> findPartialLens( const CurvePoints& cp, bool unitLength, float * outCurveLen )
212+
Expected<std::vector<float>> findPartialLens( const CurvePoints& cp, float * outCurveLen )
204213
{
205214
MR_TIMER;
206215
if ( cp.size() < 2 )
@@ -220,13 +229,6 @@ Expected<std::vector<float>> findPartialLens( const CurvePoints& cp, bool unitLe
220229
if ( lens.back() <= 0 )
221230
return unexpected( "curve has zero length" );
222231

223-
if ( unitLength )
224-
{
225-
// to relative lengths
226-
const auto factor = 1 / lens.back();
227-
for ( auto & l : lens )
228-
l *= factor;
229-
}
230232
return lens;
231233
}
232234

@@ -265,30 +267,36 @@ CurvePoint getCurvePoint( const CurvePoints& cp, const std::vector<float> & lens
265267
return res;
266268
}
267269

268-
Expected<CurveFunc> curveFromPoints( const CurvePoints& cp, bool unitLength, float * outCurveLen )
270+
Expected<CurveFunc> curveFromPoints( const CurvePoints& cp, float* outCurveLen )
269271
{
270272
MR_TIMER;
271-
auto maybeLens = findPartialLens( cp, unitLength, outCurveLen );
273+
auto maybeLens = findPartialLens( cp, outCurveLen );
272274
if ( !maybeLens )
273275
return unexpected( std::move( maybeLens.error() ) );
274276

275-
return [&cp, lens = std::move( *maybeLens )]( float p )
277+
CurveFunc res;
278+
res.totalLength = maybeLens->back();
279+
res.func = [&cp, lens = std::move( *maybeLens )] ( float p )
276280
{
277281
return getCurvePoint( cp, lens, p );
278282
};
283+
return res;
279284
}
280285

281-
Expected<CurveFunc> curveFromPoints( CurvePoints&& cp, bool unitLength, float * outCurveLen )
286+
Expected<CurveFunc> curveFromPoints( CurvePoints&& cp, float * outCurveLen )
282287
{
283288
MR_TIMER;
284-
auto maybeLens = findPartialLens( cp, unitLength, outCurveLen );
289+
auto maybeLens = findPartialLens( cp, outCurveLen );
285290
if ( !maybeLens )
286291
return unexpected( std::move( maybeLens.error() ) );
287292

288-
return [cp = std::move( cp ), lens = std::move( *maybeLens )]( float p )
293+
CurveFunc res;
294+
res.totalLength = maybeLens->back();
295+
res.func = [&cp, lens = std::move( *maybeLens )] ( float p )
289296
{
290297
return getCurvePoint( cp, lens, p );
291298
};
299+
return res;
292300
}
293301

294302
CurvePoints meshPathCurvePoints( const Mesh& mesh, const MeshTriPoint & start, const SurfacePath& path, const MeshTriPoint & end )

source/MRMesh/MRAlignContoursToMesh.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,21 @@ MRMESH_API Expected<Mesh> alignContoursToMesh( const Mesh& mesh, const Contours2
4141
struct BendContoursAlongCurveParams
4242
{
4343
/// Position on the curve, where bounding box's pivot point is mapped
44+
/// (0) - start of the curve, (1) - end of the curve
4445
float pivotCurveTime = 0;
4546

4647
/// Position of the curve(pivotCurveTime) in the contours' bounding box:
4748
/// (0, 0) - bottom left, (0, 1) - bottom right, (0.5, 0.5) - center, (1, 1) - top right
4849
Vector2f pivotBoxPoint{0.0f, 0.0f};
4950

50-
/// if true, curve parameter will be always within [0,1) with repetition: xr := x - floor(x)
51+
/// if true, curve parameter will be always within [0,curve.totalLength) with repetition: xr := mod( x, curve.totalLength )
5152
bool periodicCurve = false;
5253

53-
/// stretch all contours along curve to fit in unit curve range
54+
/// stretch all contours along curve to fit in curve.totalLength
5455
bool stretch = true;
5556

5657
/// Contours extrusion outside of curve level
5758
float extrusion{ 1.0f };
58-
59-
/// To allow passing Python lambdas into `curve`.
60-
MR_BIND_PREFER_UNLOCK_GIL_WHEN_USED_AS_PARAM
6159
};
6260

6361
/// Converts contours in thick mesh, and deforms it along given path
@@ -73,9 +71,8 @@ MRMESH_API Expected<Mesh> bendContoursAlongSurfacePath( const Contours2f& contou
7371

7472
/// given a polyline by its vertices, computes partial lengths along the polyline from the initial point;
7573
/// return an error if the polyline is less than 2 points or all points have exactly the same location
76-
/// \param unitLength if true, then the lengths are normalized for the last point to have unit length
77-
/// \param outCurveLen optional output of the total polyline length (before possible normalization)
78-
MRMESH_API Expected<std::vector<float>> findPartialLens( const CurvePoints& cp, bool unitLength = true, float * outCurveLen = nullptr );
74+
/// \param outCurveLen optional output of the total polyline length
75+
MRMESH_API Expected<std::vector<float>> findPartialLens( const CurvePoints& cp, float * outCurveLen = nullptr );
7976

8077
/// given a polyline by its vertices, and partial lengths as computed by \ref findPartialLens,
8178
/// finds the location of curve point at the given parameter with extrapolation if p outside [0, lens.back()],
@@ -84,10 +81,9 @@ MRMESH_API Expected<std::vector<float>> findPartialLens( const CurvePoints& cp,
8481

8582
/// given a polyline by its vertices, returns curve function representing it;
8683
/// return an error if the polyline is less than 2 points or all points have exactly the same location
87-
/// \param unitLength if true, then the lengths are normalized for the last point to have unit length
88-
/// \param outCurveLen optional output of the total polyline length (before possible normalization)
89-
MRMESH_API Expected<CurveFunc> curveFromPoints( const CurvePoints& cp, bool unitLength = true, float * outCurveLen = nullptr );
90-
MRMESH_API Expected<CurveFunc> curveFromPoints( CurvePoints&& cp, bool unitLength = true, float * outCurveLen = nullptr );
84+
/// \param outCurveLen optional output of the total polyline length
85+
MRMESH_API Expected<CurveFunc> curveFromPoints( const CurvePoints& cp, float * outCurveLen = nullptr );
86+
MRMESH_API Expected<CurveFunc> curveFromPoints( CurvePoints&& cp, float* outCurveLen = nullptr );
9187

9288
/// converts polyline given as a number of MeshTriPoint/MeshEdgePoint into CurvePoints
9389
[[nodiscard]] MRMESH_API CurvePoints meshPathCurvePoints( const Mesh& mesh, const MeshTriPoint & start, const SurfacePath& path, const MeshTriPoint & end );

source/MRMesh/MRCurve.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,17 @@ struct CurvePoint
1313
Vector3f snorm;///< the normal of the surface where the curve is located
1414
};
1515

16-
/// curve given as a function: time -> point
17-
using CurveFunc = std::function<CurvePoint(float)>;
16+
struct CurveFunc
17+
{
18+
/// curve given as a function: position along curve -> point
19+
std::function<CurvePoint( float )> func;
20+
21+
/// total length of the given curve
22+
float totalLength = 1.0f;
23+
24+
/// To allow passing Python lambdas into `func`.
25+
MR_BIND_PREFER_UNLOCK_GIL_WHEN_USED_AS_PARAM
26+
};
1827

1928
/// curve given as a number of points on it samples at arbitrary steps
2029
using CurvePoints = std::vector<CurvePoint>;

source/MRSymbolMesh/MRAlignTextToMesh.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Expected<Mesh> alignTextToMesh(
9090
Expected<Mesh> bendTextAlongCurve( const CurveFunc& curve, const BendTextAlongCurveParams& params )
9191
{
9292
MR_TIMER;
93-
if ( !curve )
93+
if ( !curve.func )
9494
{
9595
assert( false );
9696
return unexpected( "No curve provided" );
@@ -139,7 +139,7 @@ Expected<Mesh> bendTextAlongCurve( const CurvePoints& cp, const BendTextAlongCur
139139
MR_TIMER;
140140

141141
float curveLen = 0;
142-
auto maybeCurveFunc = curveFromPoints( cp, params0.stretch, &curveLen );
142+
auto maybeCurveFunc = curveFromPoints( cp, &curveLen );
143143
if ( !maybeCurveFunc )
144144
return unexpected( std::move( maybeCurveFunc.error() ) );
145145
assert( curveLen > 0 );

source/MRTest/MRBendTextAlongCurveTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ TEST( MRMesh, BendTextAlongCurve )
3535
};
3636
};
3737

38-
auto maybeText = bendTextAlongCurve( curve,
38+
auto maybeText = bendTextAlongCurve( { .func = curve,.totalLength = 1.0f },
3939
BendTextAlongCurveParams{
4040
.symbolMesh = s,
4141
.fontHeight = 0.2f,

0 commit comments

Comments
 (0)