cad.net 曲线类操作
说明
如果你想在界面上面画一个曲线,那么推荐你这个whudj博客
以下都是cad的曲线操作
cad曲线函数中文帮助
创建样条曲线
/// <summary>
/// 创建样条曲线
/// </summary>
/// <param name="splineType"><see langword="true"/>控制点ControlPoints;<see langword="false"/>:拟合点FitPoints</param>
/// <param name="points">点集</param>
/// <param name="tolerance">精度</param>
/// <returns></returns>
public static Entity AddSplineToEntity(bool splineType,
IEnumerable<Point3d> points,
double tolerance = 1e-10)
{
if (points.Count() < 2)
throw new ArgumentNullException(nameof(points) + "点集少于2");
var pts = new Point3dCollection(points).Collection;
if (!splineType)
return new Spline(pts, 4, tolerance);/*order 创建的样条曲线的顺序(在2到26的范围内),arx默认4 */
//首尾相同就闭合
var tol = new Autodesk.AutoCAD.Geometry.Tolerance(tolerance, tolerance);
bool closed = points.First().IsEqualTo(points.Last(), tol);
// 要创建的样条的阶数(ARX说明: 在1到11的范围内,我们目前只支持阶数为3)
int degree;
switch (pts.Count)
{
case 2:
degree = 1;
break;
case 3:
degree = 2;
break;
default:
degree = 3;
break;
}
DoubleCollection knots = new();
{
//节点数计算方式:
var num = pts.Count + degree + 1;
for (int i = 0; i < num; i++)
knots.Add(0);
//通过spl命令绘制的基本规律
if (num <= 8)
{
//对半分0/1
for (int i = num / 2; i < num; i++)
knots[i] = 1;
}
else
{
//前面四个值相同0,中间值递增,尾部4个值相同
int addNum = 0;
for (int i = 4; i < num; i++)
{
if (i < num - 4)
{
addNum = i - 3;
knots[i] = addNum;
}
else
knots[i] = addNum + 1;//末尾4个用
}
}
}
//权重,cad的都是-1
DoubleCollection weights = new();
for (int i = 0; i < pts.Count; i++)
weights.Add(-1.0);
return new Spline(degree, false, closed, false,
pts,
knots.Collection,
weights.Collection,
tolerance, tolerance);
}
#if false
// 0x01 官网这个例子不对,用拟合点作为参数的话,控制点比拟合点多,造成末尾抖动
// https://help.autodesk.com/view/ACD/2016/ENU/?guid=GUID-A48AD068-9868-4F7A-8A51-F72A358EBB09
// 0x02 LibreCAD的样条曲线 https://wiki.librecad.org/lc3doc/lckernel/html/db/d07/spline_8cpp_source.html
// 0x03 因为cad08用不了,但是这个函数是可行的.
/// <summary>
/// 控制点创建样条曲线
/// </summary>
/// <param name="points">控制点集</param>
/// <returns></returns>
public static Entity AddSplineToEntity(Point3d[] points)
{
var spl = new Spline();
spl.SetDatabaseDefaults();
spl.Type = SplineType.ControlPoints;
spl.Rebuild(3, points.Length);
//控制点覆盖拟合点
for (int i = 0; i < points.Length; i++)
spl.SetControlPointAt(i, points[i]);
return spl;
}
#endif
曲线投影
依照旧样条曲线数据生成一条新样条曲线
Spline spl = entity as Spline; //拿到旧的spline图元...
//样条曲线生成条件
var controlPoints = new Point3dCollection();
for (int i = 0; i < spl.NumControlPoints; i++) //控制点
{
controlPoints.Add(spl.GetControlPointAt(i));
}
NurbsData nu = spl.NurbsData;
entnew = new Spline(spl.Degree, spl.IsRational, spl.Closed,
spl.IsPeriodic, //周期性
controlPoints, //控制点
nu.GetKnots(), //节点
nu.GetWeights(), //权重
nu.ControlPointTolerance, //控制点容差
nu.KnotTolerance //节点容差
);
也可以直接克隆
var splClone = spl.Clone();
记得降权,参考cad.net 所有的克隆方式
曲线采样
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
namespace JoinBox
{
public class CurveSplit
{
public List<Curve> Curves { get; set; }
/// <summary>
/// 获取定值分割的曲线集合
/// </summary>
/// <param name="curve">曲线</param>
/// <param name="fixedValue">定值分割</param>
public CurveSplit(Curve curve, double fixedValue)
{
Curves = new();
//算曲线长度
double curveLength = curve.GetLength();
//若少于定值,则直接返回这条曲线,表示返回这段长度
if (curveLength < fixedValue)
{
Curves.Add(curve);
return;
}
var pts = new Point3dCollection();
//用来叠加长度
double overlyingLength = 0;
//定值采集点
while (overlyingLength < curveLength)
{
//求起点到长度的点
pts.Add(curve.GetPointAtDist(overlyingLength));
overlyingLength += fixedValue;
}
//最后没有完全重合,加入尾巴点
if (overlyingLength - curveLength < 1e-6)
pts.Add(curve.GetPointAtDist(curveLength));
//通过点集,分割曲线
var splits = curve.GetSplitCurves(pts.Collection);
foreach (var item in splits)
{
var cuItem = (Curve)item;
Curves.Add(cuItem);
}
pts.Dispose();
splits.Dispose();//释放
}
/// <summary>
/// 手动释放生成出来的曲线,
/// 因为cad的Point3d没有继承,所以不能用 <see cref="IDisposable">进行释放</see>
/// 否则提示:Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.Arc): DisposableWrapper
/// </summary>
public void Dispose()
{
Curves?.ForEach(cu => {
cu.Dispose();
});
}
}
public class CurveSample
{
Curve _curve { get; set; }
int _numSample { get; set; }
/// <summary>
/// 曲线采样
/// </summary>
/// <param name="curve">曲线</param>
/// <param name="sampleNum">采样份数</param>
public CurveSample(Curve curve, int sampleNum = 256)
{
_curve = curve;
_numSample = sampleNum;
}
/// <summary>
/// 曲线采样(注意尾点是否缺少哦)
/// </summary>
/// <returns></returns>
public IEnumerable<Point3d> GetSamplePoints
{
get
{
if (_numSample == 0)
throw new System.Exception("NumSample参数不能为0");
var length = _curve.GetLength();
var fixedValue = length / _numSample;
var cs = new CurveSplit(_curve, fixedValue);
var curves = cs.Curves;
var pts = new List<Point3d>();
pts.Add(curves[0].StartPoint);//起点
foreach (var item in curves)
pts.Add(item.EndPoint);//间隔点,尾点
//末尾两个点可能一样,需要判断去除
if (pts[pts.Count - 1] == pts[pts.Count - 2])
pts.RemoveAt(pts.Count - 1);
cs.Dispose();
return pts;
}
}
}
}
调用方式见:葛立恒凸包 CurveSample
曲线长度
namespace JoinBox
{
public static partial class MathHelper
{
/// <summary>
/// 曲线长度
/// </summary>
/// <param name="curve">曲线</param>
/// <returns></returns>
public static double GetLength(this Curve curve)
{
return curve.GetDistanceAtParameter(curve.EndParam);
}
}
}
曲线起点到鼠标点长度
public partial class CmdTest
{
[CommandMethod("CmdTest_Param")]
public void CmdTest_Param()
{
var dm = Acap.DocumentManager;
var doc = dm.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var peo = new PromptEntityOptions("\n选择样条曲线:");
var per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
var ps = ed.GetPoint(new PromptPointOptions("\n获取的点: "));
if (ps.Status != PromptStatus.OK)
return;
var pt = ps.Value;
ed.WriteMessage(pt.ToString());
db.Action(tr => {
var cur = tr.GetObject(per.ObjectId, OpenMode.ForRead) as Curve;
if (cur == null)
return;
/*
* 验证哪个是曲线长度很简单的操作是:
* div命令1000,取一份直线长度,然后*1000,就很好拟合误差了.
* 所以下面这句 曲线总长 就是对的.
*/
var curLength = cur.GetLength();//曲线总长
ed.WriteMessage("\n曲线总长: " + curLength);
var cp = cur.GetClosestPointTo(pt, true);//最近点(为了点在曲线上)
ed.WriteMessage("\n最近的点: " + cp);
double ptParam = cur.GetParameterAtPoint(cp);//点参数(貌似是一种单位化之后得到的数值)
ed.WriteMessage("\n点的参数: " + ptParam.ToString());
ed.WriteMessage("\n末尾参数: " + cur.EndParam);
var curPtLength = ptParam * (curLength / cur.EndParam);//曲线起点到鼠标点长度==点参数*(总长/总参数)
ed.WriteMessage("\n点击长度: " + curPtLength);
});
}
}
缺省函数
图示
spl的曲线参数就是拟合点连线长度(不过会受到缩放影响)
拟合点和控制点的定义
没有缩放的时候,获取末尾点参数就是拟合点连线长度(正常情况)
操作: 选择曲线,然后输入测试命令,选择曲线,点击末尾
缩放了之后只会呈现未缩放的长度(缩放情况,关闭cad之后自动修改回来)
操作: 缩放样条曲线,然后输入测试命令,选择曲线,点击末尾
相关阅读
(完)