Skip to content

样条线 ​

在 mxcad 中,我们可以通过实例化一个 McDbSpline() 对象来创建样条线。根据数据源的不同,主要有两种创建方式:通过拟合点 (Fit Points) 和通过控制点 (Control Vertices)。

1. 通过拟合点 (Fit Points) 绘制 ​

这种方式通过指定一系列曲线必须经过的点来生成一条平滑的曲线,是交互式绘图中最常用的方法。

我们可以通过调用 McDbSpline() 实例对象的 setFitPoints() 方法来设置样条线的拟合数据。

点击 McDbSpline()、setFitPoints() 查看详细属性和方法说明。

setFitPoints() 参数说明 ​

setFitPoints() 方法的参数 data 对象包含以下属性:

  • degree: 样条曲线的次数(degree),表示曲线的数学阶次。通常,AutoCAD 中的样条曲线是三次曲线(degree 为 3),意味着它们是三阶多项式。
  • fitTolerance: 拟合公差,这是一个数值,代表了拟合点到实际生成的样条曲线之间的最大允许距离。较小的值意味着样条曲线将更紧密地跟随拟合点,但可能会导致曲线更加复杂。
  • tangentsExist: 一个布尔值,指示是否指定了起点切线和终点切线。如果为 true,则表示存在自定义的起始和结束切线方向,这可以控制曲线在端点处的方向。
  • startTangent: 如果 tangentsExist 为 true,此参数是一个 McGeVector3d 对象,表示曲线起点的切线方向。它决定了曲线开始时的方向。
  • endTangent: 类似于 startTangent,但如果 tangentsExist 为 true,这个参数指定的是曲线结束时的切线方向,影响曲线如何到达其终点。
  • fitPoints: 这是一个 McGePoint3dArray 类型的数组,包含了一系列的三维点 (McGePoint3d),这些点是样条曲线要经过的拟合点。根据这些点的位置,mxcad 会计算出一条平滑通过所有点的曲线。

以下代码演示了如何响应用户点击,动态预览并绘制一条拟合样条线。

typescript
import { MxCpp, MxCADUiPrPoint, McDbSpline, McGePoint3dArray, McGeVector3d } from "mxcad";

// 绘样条线函数
async function Mx_drawSpline() {
  const getPoint = new MxCADUiPrPoint();
  getPoint.setMessage("\n指定第一点:");
  let prvPoint = await getPoint.go();
  if (!prvPoint) return;

  getPoint.setMessage("\n指定下一个点:");
  let fitPoints = new McGePoint3dArray();
  fitPoints.append(prvPoint);

  // 样条线循环取点
  while (true) {
    getPoint.setBasePt(prvPoint as any);
    if (fitPoints.length() == 1) {
      getPoint.setUseBasePt(true);
    } else {
      getPoint.setUseBasePt(false);
      // 动态绘制预览逻辑
      getPoint.setUserDraw((pt, pw) => {
        let tmpFitPoints = new McGePoint3dArray();
        tmpFitPoints.copy(fitPoints);
        tmpFitPoints.append(pt);

        let tmpSPline = new McDbSpline();
        tmpSPline.setFitPoints({
          degree: 3,
          fitTolerance: 0.000001,
          tangentsExist: false,
          startTangent: McGeVector3d.kIdentity,
          endTangent: McGeVector3d.kIdentity,
          fitPoints: tmpFitPoints,
        });
        pw.drawMcDbEntity(tmpSPline);
      });
    }

    let pt = await getPoint.go();
    if (!pt) break;
    fitPoints.append(pt);
    prvPoint = pt;
  }

  // 最终绘制实体
  if (fitPoints.length() > 2) {
    let sp = new McDbSpline();
    sp.setFitPoints({
      degree: 3,
      fitTolerance: 0.000001,
      tangentsExist: false,
      startTangent: McGeVector3d.kIdentity,
      endTangent: McGeVector3d.kIdentity,
      fitPoints: fitPoints,
    });
    MxCpp.getCurrentMxCAD().drawEntity(sp);
  }
}

2. 通过控制点 (Control Vertices) 绘制 ​

这种方式提供了更底层的控制,允许直接定义 NURBS(非均匀有理B样条)的数学数据。它通过控制点、节点向量和权重来精确定义曲线,适用于需要精确数学定义或从其他系统导入几何数据的场景。

我们可以通过调用 McDbSpline() 实例对象的 setNurbsData() 方法来设置这些 NURBS 数据。

点击 McDbSpline()、setNurbsData() 查看详细属性和方法说明。

setNurbsData() 参数说明 ​

setNurbsData() 方法的参数 data 对象包含以下属性:

  • degree: 曲线的次数(如 3 次)。
  • rational: 是否为有理样条。若为 false,权重通常忽略或全为 1。
  • closed: 曲线是否闭合。
  • periodic: 曲线是否周期性。
  • controlPoints: McGePoint3dArray 类型的数组,即控制点。这些点定义曲线的控制多边形,曲线通常不经过这些点(除首尾外),而是被它们“吸引”。
  • knots: McGeDoubleArray 类型的数组,即节点向量。它定义了参数空间的划分,影响曲线段的连续性。节点数量通常等于 控制点数量 + 次数 + 1。
  • weights: McGeDoubleArray 类型的数组,即权重。若非有理样条,可为空。
  • controlPtTol: 控制点容差。
  • knotTol: 节点容差。

以下代码演示了如何手动构建控制点、节点向量并生成一条 NURBS 样条线。

typescript
import { MxCpp, McDbSpline, McGePoint3dArray, McGeDoubleArray, McGePoint3d } from "mxcad";

function Mx_DrawSpline() {
  const mxcad = MxCpp.getCurrentMxCAD();
  
  // 1. 创建样条线对象
  const spline = new McDbSpline();

  // 2. 设置控制点 (Control Vertices)
  const controlPoints = new McGePoint3dArray();
  controlPoints.append(new McGePoint3d(89.5, 174.5, 0));
  controlPoints.append(new McGePoint3d(123.69, 226.98, 0));
  controlPoints.append(new McGePoint3d(194.96, 336.35, 0));
  controlPoints.append(new McGePoint3d(241.15, 63.93, 0));
  controlPoints.append(new McGePoint3d(427.44, 306.12, 0));
  controlPoints.append(new McGePoint3d(521.19, 159.27, 0));
  controlPoints.append(new McGePoint3d(578.5, 69.5, 0));

  // 3. 设置节点向量 (Knot Vector)
  const knots = new McGeDoubleArray();
  knots.append(0); knots.append(0); knots.append(0); knots.append(0); // 起点重复度
  knots.append(130.82);
  knots.append(272.65);
  knots.append(424.77);
  knots.append(664.03); knots.append(664.03); knots.append(664.03); knots.append(664.03); // 终点重复度

  // 4. 设置权重 (Weights)
  // 对于非有理样条,权重数组可以为空
  const weights = new McGeDoubleArray();

  // 5. 使用 setNurbsData 设置数据
  spline.setNurbsData({
    degree: 3,
    rational: false,
    closed: false,
    periodic: false,
    controlPoints: controlPoints,
    knots: knots,
    weights: weights,
    controlPtTol: 1e-9,
    knotTol: 1e-9
  });

  // 6. 绘制并验证
  mxcad.drawEntity(spline);
  mxcad.zoomAll();
  mxcad.updateDisplay();

  // 验证数据读取
  const data = spline.getNurbsData();
  console.log("样条线数据验证:");
  console.log("degree:", data.degree);
  console.log("controlPoints count:", data.controlPoints.length());
  console.log("knots count:", data.knots.length());
}