cad.net 投影三维图元到某个平面上+求图元交点

投影三维图元到某个平面上

如果遇到复杂的三维图元,要先进行消隐hide命令,但是我还没研究好这个命令.

红色(1号色)是三维的,黄色(2号色)投影下来的,它是曲线,因为曲线是直线的父类.可以依照曲率转换为自己喜欢的直线或者多段线,圆弧等等.
image

命令

[CommandMethod(nameof(JJ_testty)]
public static void JJ_testty() {
    var dm = Acap.DocumentManager;
    var doc = dm.MdiActiveDocument;
    var db = doc.Database;
    var ed = doc.Editor;
    ed.WriteMessage("\n****{惊惊连盒}测试,投影三维图元到某个平面上");

    using DBTrans tr = new();
    // 三维的线 
    var line = new Line(Point3d.Origin, new Point3d(1, 1, 1));
    line.ColorIndex = 1;
    var lineId = tr.AddEntityToMsPs(db, line);
    var ids = new List<ObjectId>() { lineId };
    var cus = tr.Entitys2Plane(ids);
    foreach (var item in cus) {
        item.ColorIndex = 2;
        tr.AddEntityToMsPs(db, item);
    }
}

投影平面

/// <summary>
/// 投影平面
/// </summary> 
/// <param name="tr">事务</param>
/// <param name="ids">图元</param>
/// <param name="normal">投影方向</param>
/// <returns>投影到某个平面的图元</returns>
public static List<Curve> Entitys2Plane(this Transaction tr,
    IEnumerable<ObjectId> ids, Vector3d? normal = null) {
    normal ??= Vector3d.ZAxis; // 绕Z轴,也就是XY平面
    var tr = DBTrans.Top;
    var ls = new List<Curve>();
    var plane = new Plane(Point3d.Origin, normal.Value);
    foreach (var sobject in ids) {
        if (!sobject.IsOk()) continue;
        using var curve = (Curve)tr.GetObject(sobject, OpenMode.ForRead);
        if (curve is null) continue;
        try {
            var pCurve = curve.GetOrthoProjectedCurve(plane);
            ls.Add(pCurve);
        } catch { }
    }
    return ls;
} 

缺省函数

public static partial class EntityEdit {
    /// <summary>
    /// id有效,未被删除
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public static bool IsOk(this ObjectId id)
    {
        return !id.IsNull && id.IsValid && !id.IsErased && !id.IsEffectivelyErased && id.IsResident;
    }

    /// <summary>
    /// 将图形添加到数据库的当前空间中
    /// </summary>
    /// <param name="db">图形数据库</param>
    /// <param name="ent">图形对象</param>
    /// <returns>图形的ObjectId</returns>
    public static ObjectId AddEntityToMsPs(this Transaction tr, Database db, Entity ent) {
        // 在位编辑的时候自动加到块内了,而不是模型空间,
        // 因为会把临时的数据拷贝回去块表记录上面
        // 出现eLockViolation 是因设置flags又没有锁文档:
        // CommandFlags.Session | CommandFlags.Redraw 
        using var btRec = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
        // 加图元到块表记录,设定返回值
        var entId = btRec.AppendEntity(ent);
        // 更新数据
        tr.AddNewlyCreatedDBObject(ent, true);
        btRec.DowngradeOpen();
        return entId;
    }
}

求直线交点

数学篇 求两条直线的交点,说明过程 中有一个纯数学的解决方法.
那么cad的图元上面也有一个:Entity.IntersectWith函数.
但是展示这个函数前需要先说明一下,这个函数遇到两个坐标值特别大的图元会计算不出来,
例如两条spl样条曲线会计算不出来,而特大的坐标的直线却可以计算,原因可能是内部求导函数的问题.

Acad2008复现问题的方法是:画pline,设置坐标:
(内存长度) (1e15,1e15) ~ (2e15,2e15)~ (3e15,3e15)
然后在这个范围上画spl,你会发现画得断断续续的...甚至卡死你的cad

而当你求不出交点的时候要注意是否小数点后数字过多!
如果遇到不妨将两条spl平移回原点附近再进行求交.

[CommandMethod(nameof(IntersectionTest))]
public void IntersectionTest() {
    var dm = Acap.DocumentManager;
    var doc = dm.MdiActiveDocument;
    var db = doc.Database;
    var ed = doc.Editor;
    ed.WriteMessage("\n求空间两曲线交点");

    // 可以选择line,因为父类是曲线
    var per = ed.GetEntity("\n选择第一条曲线:");
    if (per.Status != PromptStatus.OK) return;
    ObjectId id1 = per.ObjectId;

    per = ed.GetEntity("\n选择第二条曲线:");
    if (per.Status != PromptStatus.OK) return;
    ObjectId id2 = per.ObjectId;

    using DBTrans tr = new();
    using var cur1 = (Curve)tr.GetObject(id1, OpenMode.ForRead);
    using var cur2 = (Curve)tr.GetObject(id2, OpenMode.ForRead);
    using var ints = new Point3dCollection();

    // plane是投影面
    // 得出的所有交点在c1曲线上
    cur1.IntersectWith(cur2, Intersect.OnBothOperands, new Plane(), ints, 0, 0);
    if (ints.Count == 0) {
        ed.WriteMessage($"\n无交点或图元交点过大(小数点过多)");
    }
    else {
        foreach (Point3d pt in ints)
            ed.WriteMessage($"\n第一条曲线与第二条曲线交点:{pt}");
    }

    ed.WriteMessage("\n========================");
    ints.Clear();

    // 得出的所有交点在c2曲线上
    cur2.IntersectWith(cur1, Intersect.OnBothOperands, new Plane(), ints, 0, 0);
    if (ints.Count == 0) {
        ed.WriteMessage($"\n无交点或图元交点过大(小数点过多)");
    }
    else {
        foreach (Point3d pt in ints)
            ed.WriteMessage($"\n第二条曲线与第条曲线一交点:{pt}");
        }
    }
}

子函数

db.Action

(完)

posted @ 2021-03-29 21:25  惊惊  阅读(1167)  评论(0编辑  收藏  举报