唯杰地图 logo唯杰地图
VJMAP
EN

spline

vjmapext/references/entity/spline.md 4.3 KB91 行
原文

本文回答:SplineEnt 样条曲线 —— 拟合点 / 控制点、阶数、闭合、用法。

一、构造(位置参数)

// new SplineEnt(fitPts?, degree?) —— 拟合点是第一参
const spline = new vjmapext.SplineEnt(
  [[0,0], [50,100], [150,80], [200,0], [250,100]],
  3                      // degree,默认 3(拟合点模式下不影响形状,见第四节)
);
spline.color = 0xff4488;
spline.lineWidth = 2;
mapcadLayer.addEntity(spline);

二、属性(d.ts 真实成员)

属性 类型 说明
fitPoints Point2D[] 拟合点(曲线穿过;按 Catmull-Rom 插值)
controlPoints Point2D[] B 样条控制点(多数不在曲线上;无权重/节点向量)
degree number 阶数,默认 3——只在控制点模式生效,拟合点模式忽略
isClosed boolean 是否闭合(注意:不叫 closed)
fillColor / fillOpacity / borderOpacity number 闭合时填充
isFitMode getter fitPoints.length >= 2 即为真——fitPoints 优先,controlPoints 有值也会被忽略(渲染/夹点/导出都走 activePoints)

控制点模式:构造后改 spline.controlPoints = [...](d.ts 无 knots/weights 暴露)。要走控制点模式须保证 fitPoints.length < 2。

⚠️ controlPoints 必须赋 Point2D 实例数组,不能赋裸 [x,y]——clone()/move()/rotate()/scale()/mirror() 对 controlPoints 无条件 .map(p => p.clone()),裸数组会抛 p.clone is not a function(addEntity 的 undo 快照路径必触发)。而构造器 new SplineEnt(fitPts) 接受裸数组(内部 Ut() 转 Point2D)。赋值写法:s.controlPoints = pts.map(p => new Point2D(p[0], p[1]))。

三、闭合样条

const loop = new vjmapext.SplineEnt([[0,0],[100,80],[200,0],[150,-80],[50,-80]]);
loop.isClosed = true;
loop.fillColor = 0x4488ff;
mapcadLayer.addEntity(loop);

四、阶数(degree)何时生效

拟合点模式(构造传点,fitPoints.length >= 2)按 Catmull-Rom 插值渲染,degree 不参与——new SplineEnt(pts, 5) 与 new SplineEnt(pts) 画出来一样。degree 只在控制点模式(fitPoints.length < 2)下作 B 样条阶数(开口时自动夹到 控制点数 - 1):

const sp = new vjmapext.SplineEnt();          // 不传拟合点 → 控制点模式
sp.controlPoints = [[0,0],[50,200],[150,200],[200,0]].map(p => new vjmapext.Point2D(p[0], p[1]));
sp.degree = 2;                                // 此时 degree 才生效
mapcadLayer.addEntity(sp);

五、替代方案:贝塞尔

SplineEnt 不是严格 NURBS(拟合模式是 Catmull-Rom,控制点模式是无权重 B 样条);若只要光滑曲线,也可用辅助函数生成 PolylineEnt:

// polylineToBezierCurve 返回 BezierCurve 对象(控制点结构),
// 要再经 bezierCurveToPolyline 采样成点数组才能喂 PolylineEnt:
const curve = vjmap.polylineToBezierCurve([[0,0],[100,50],[200,0],[150,-50]]);
const smooth = new vjmapext.PolylineEnt(
  vjmap.bezierCurveToPolyline(curve, 0.5)   // precision?: number 采样精度
);

见 primitive/circle-arc。

六、与 Polyline 的差别

特性 SplineEnt PolylineEnt
光滑 拟合模式 Catmull-Rom(C1 连续) 端点有折角
bulge 弧 不需要 通过 bulgePoints 近似
交互夹点 拟合点 / 控制点 顶点
导出 DWG 保留 SPLINE 类型 转 PLINE

七、编辑

选中后夹点出现在拟合点(或控制点),拖动修改局部形状:

spline.fitPoints[1] = vjmapext.Point2D.fromArray([70, 150]);
spline.changed();

八、常见坑

  1. 构造是位置参数:new SplineEnt(fitPts, degree)——options 对象不会生效(同 TextEnt)。
  2. 闭合属性是 isClosed,不是 closed。
  3. 以为改 degree 能调平滑度:拟合点模式下 degree 被忽略(Catmull-Rom 固定);只有控制点模式才用,且开口样条会自动夹到 控制点数 - 1。
  4. 精确通过某点:必须用 fitPoints;controlPoints 只决定形状。
  5. 大量 Spline 很慢:内部采样重建 Polyline;量大时直接生成 Polyline。