在利用 MS 二开的时候,我们经常会等分线段,通常我们会用到 fraction
来操作,在此记录下 MS 中 fraction 小坑,以作提醒。
原理介绍
fraction 对于 B样条曲线 来说不是各段长度相等的等分点。
fraction 在开始时总是 0,然后结束时总是 1。
fraction 只有在下列基础类型时,才是线性增加的
- line segment,线段
- circular arc,圆或者圆弧
- transition spirals,螺旋线
而在其它复杂类型的曲线中, fraction
的含义与曲线类型的内部参数化有关。
- 对于有N个线段(即N+1个点)的线串 (Linestring),各个顶点的 fraction
分别为 0,1/N,2/N,…1。
- 对于bspline 曲线,fraction 表示节点范围的分数。
- 对于椭圆弧(elliptic arc),fraction 与角度变化成正比,公式为:X =
center + vector0 * cos(theta) + vector90 * sin (theta)
源代码
在此,分享一个等分线段的算法,若有不足之处,还请指教。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
public static DPoint3d GlobalFraction2Point(this CurveVector curve, double globalFraction, out DVector3d vectorAtFraction) { if (globalFraction <= 0) { curve.GetStartEnd(out DPoint3d pa, out _, out DVector3d ua, out _); double length = curve.SumOfLengths(); DPoint3d pnt = pa + ua * length * globalFraction; vectorAtFraction = ua; return pnt; } else if (globalFraction >= 1) { curve.GetStartEnd(out _, out DPoint3d pb, out _, out DVector3d ub); double length = curve.SumOfLengths(); DPoint3d pnt = pb + ub * length * (globalFraction - 1); vectorAtFraction = ub; return pnt; }
double totalLength = 0; double targetLength = globalFraction * curve.SumOfLengths(); foreach (var cp in curve) { cp.Length(out var length); totalLength += length; if(totalLength >= targetLength) { var distance = targetLength - totalLength; var curveDetail = cp.PointAtSignedDistanceFromFraction(1, distance, false); cp.FractionToPoint(curveDetail.Fraction, out DPoint3d point, out vectorAtFraction); return point; } }
vectorAtFraction = DVector3d.Zero; return DPoint3d.Zero; }
|
参考
CurveLocationDetail的fraction总是得不到正确结果