cad.net 链式选择和断分标注

说明:

这篇可以用四叉树优化但是我懒用的暴力遍历🤣,见四叉树

由于cad自身的图元特性,标注作为一个复合型图元却没有做到磁性选择,

这样很糟糕,而我们非自定义图元的时候只能通过链式选择和断分标注模拟.

磁性选择:当存在共同点的时候,可以直接吸附起来,跟磁铁特性一样,
不是组也不是块参照,而是基于之间的状态,
组可以被s命令点击移动单个图元...块参照只能移动整体,块ctrl+1特性页不显示标注内容.
所以才有磁铁体,它应该显示夹点和可以直接修改磁铁体内的图元,例如标注和标注,引线和文字,自动吸附起,
解开才需要命令,可惜cad并没有这样的东西,比较失望...
而和天正标注很不一样的感觉是,天正标注没有自动吸附的感觉,也就是当鼠标移动标注对齐的时候,鼠标出现捕捉点的时候是可以获取交点图元的,此时则可以直接利用反应器制造关联.
啊,我才不要二次开发实现呢,一次开发做好才是最好的...不是桌子想不到,而是他们没有动力重构了.

链式选择:先选择所有图元,然后判断点击的图元共同点碰撞到下一个图元的公共点,则选择起来.(这里甚至可以建设一个B+树加快搜寻速度,我懒)

断分标注:直接看动图即可...

如果缺少函数,可利用搜索功能对博客进行搜索,如果真的缺了就留言吧.请登陆博客园看评论,我已经回答过全部的缺省.

源泉的作者告诉阿惊说,
标注避让的思路是上下左右移动文字,然后有优先排序的方式,例如优先的是上下上下上下上下的排序.
但是阿惊现在已经没空完成这个函数了...
若完成你就提供出来给大家吧.

动图演示

mac-lee的链式选择展示:点我

img

命令

//断分标注
[CommandMethod("nn", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)] //预选  | CommandFlags.DocExclusiveLock
public void JJ_dd()
{
    var dm = Acap.DocumentManager;
    var doc = dm.MdiActiveDocument;
    var db = doc.Database;
    var ed = doc.Editor;
    ed.WriteMessage(Environment.NewLine + "****惊惊连盒-断分标注");

    var peo = new PromptEntityOptions(Environment.NewLine + "点选标注:")
    {
        AllowObjectOnLockedLayer = false,
        AllowNone                = false
    };
    var optionsA = new PromptPointOptions(Environment.NewLine + "选取[断分/延长点]或[输入等分段数,负数为改数值)]:<空格退出>")
    {
        AllowArbitraryInput = true, //任意输入
    };
    //peo.Keywords.Add("D", "D", "多选来源块(D)");
    try
    {
        DimInfo dimInfo = null;
        Entity ent = null;
        List<ObjectId> dimIdList = new();

        db.Action(tr => {
            //获取基础块的ID
            object idOrKeyword = ed.SelectImpliedGetOne(tr, peo, new EntityType[] { EntityType.RotatedDimension, EntityType.AlignedDimension });

            var baseId = ObjectId.Null;
            if (idOrKeyword is ObjectId idv && idv.IsOk())
            {
                baseId = idv;
            }
            else
            {
                ed.WriteMessage("输入了关键字");
                return;
                ////输入了关键字
                //string str = idOrKeyword as string;
                //switch (str)
                //{
                //    case "D": //用户要求附加选择
                //        break;
                //}
            }
            ent = baseId.ToEntity(tr);
            dimIdList = ed.ChainReactor(ent, tr);//链式选择
            if (dimIdList == null || dimIdList.Count() == 0)
                return;
            tr.EntityRedraw(dimIdList, Bright.Highlight);//亮显
            dimInfo = ent.GetDimInfo();                  //获取标注信息
        });


        var pprA = ed.GetPoint(optionsA);
        if (pprA.Status == PromptStatus.Keyword)
        {
            //用户输入了数字,进行改变尺寸操作
            int.TryParse(pprA.StringResult, out int a);
            if (a < 0)
            {
                string str = (dimInfo.DimLength / -a).ToString("#0.00") + "*" + (-a).ToString() + "=<>";
                if (dimInfo.DimType == EntityType.AlignedDimension.ToString())//对齐标注
                {
                    if (ent is AlignedDimension dim)
                        dim.DimensionText = str;
                }
                else if (dimInfo.DimType == EntityType.RotatedDimension.ToString())//转角标注
                {
                    if (ent is RotatedDimension dim)
                        dim.DimensionText = str;
                }
            }
            else
            {
                //根据等分份数生成标注
                double yifen = dimInfo.DimLength / a;
            }
        }
        else if (pprA.Status == PromptStatus.OK)
        {
            dimIdList = DivideDim(ed, ent, pprA.Value, dimIdList);
            //这里是留来写标注避让....
            //这里是留来写标注避让....
            //这里是留来写标注避让....
        }
        db.Action(tr => {
            tr.EntityRedraw(dimIdList, Bright.Unhighlight);//取消亮显
        });
    }
    catch (System.Exception e)
    {
        ed.WriteMessage("断分标注错误::" + e.Message);
    }
}

/// <summary>
/// 循环分裂标注
/// </summary>
/// <param name="ent">选中的图元</param>
/// <param name="getpoint">分裂点</param>
/// <param name="idArr">选择集数组</param>
/// <returns>最终链条上面的图元</returns>
List<ObjectId> DivideDim(Editor ed, Entity ent, Point3d? getpoint, IEnumerable<ObjectId> idArr)
{
    ed.GetWcsUcs(out _, out CoordinateSystemV ucs);

    //获取标注信息
    var entDimInfo = ent.GetDimInfo();

    //链条的角度
    double angle;

    var pts2 = new Point3d[] { entDimInfo.DimLinePoint, entDimInfo.DimLinePointN };
    var minToMax2 = pts2.OrderBy(a => a.X).ThenBy(a => a.Y).ThenBy(a => a.Z).ToArray();
    if (minToMax2[0] == entDimInfo.DimLinePoint)
        angle = -(entDimInfo.DimLinePoint.ToPointV().GetAngle2XAxis(entDimInfo.DimLinePointN));
    else
        angle = -(entDimInfo.DimLinePointN.ToPointV().GetAngle2XAxis(entDimInfo.DimLinePoint));

    ed.WriteMessage(Environment.NewLine + "继续分裂/延长点");
    var optionsA = new PromptPointOptions("")
    {
        AllowArbitraryInput = true, //任意输入
    };

    //遍历链式选择集
    var dimIdList = idArr.ToList();

    bool getPointBool = true;
    while (getPointBool)
    {
        ent.Database.Action(tr => {
            //第二次才执行
            if (getpoint == null)
            {
                var ppr = ed.GetPoint(optionsA);
                if (ppr.Status != PromptStatus.OK)
                {
                    getPointBool = false;
                    return;
                }
                getpoint = ppr.Value;
            }

            //链条前后两个点
            var pts = GetDimLinePoints(tr, dimIdList);
            var dimMinToMaxs = pts.OrderBy(a => a.X).ThenBy(a => a.Y).ThenBy(a => a.Z).ToArray();

            var dimMinPoint = dimMinToMaxs[0];
            var dimMaxPoint = dimMinToMaxs[dimMinToMaxs.Length - 1];

            //增点旋转到x轴
            var getpointRo = getpoint.Value.RotateBy(angle, ucs.ZAxis.ToVector3d(), dimMinPoint);
            var dimMaxRo = dimMaxPoint.RotateBy(angle, ucs.ZAxis.ToVector3d(), dimMinPoint);

            //那ent到的顶点作为新图元的延伸点
            var entXLine1PointRo = entDimInfo.XLine1Point.RotateBy(angle, ucs.ZAxis.ToVector3d(), dimMinPoint);
            var shengchengList = new List<Point3d[]>();

            Entity entok = null;//更改点最近的图元

            //判断增点是否在范围外,是就补充尺寸,否就分裂尺寸
            //pprARo只能够判断方向用
            //用ent的点作为生成点
            if (getpointRo.X < dimMinPoint.X)  //增点在左外
            {
                var ddd = new Point3d[]
                {
            new Point3d( dimMinPoint.X, entXLine1PointRo.Y, entXLine1PointRo.Z),//标注边点2
            dimMinPoint,                                                        //标注确认点
                };
                shengchengList.Add(ddd);
            }
            else if (getpointRo.X > dimMaxRo.X)  //增点在右外
            {
                var ddd = new Point3d[]
                {
            new Point3d(dimMaxRo.X, entXLine1PointRo.Y, entXLine1PointRo.Z), //标注边点2
            dimMaxRo,                                                        //标注确认点
                };
                shengchengList.Add(ddd);
            }
            else  //增点在中  getpointRo 在链表中间的那个位置
            {
                //获取链条上所有的确认点的位置,判断分裂位置.
                var lenthList = new List<double>();
                foreach (var item in dimMinToMaxs)
                {
                    var pt = item.RotateBy(angle, ucs.ZAxis.ToVector3d(), dimMinPoint);
                    lenthList.Add(pt.X - getpointRo.X);
                }
                //这里就是一个一维坐标值,通过x判断,负值到正值之间,大于0,然后前一个和它就是之间了
                var newDimTwo = new Point3d[2];
                for (int i = 0; i < lenthList.Count; i++)
                {
                    if (lenthList[i] > 0)
                    {
                        newDimTwo[0] = dimMinToMaxs[i - 1];
                        newDimTwo[1] = dimMinToMaxs[i];
                        break;
                    }
                }
                //获取选择集上面与其相同点的
                foreach (ObjectId item in dimIdList)
                {
                    var entN = item.ToEntity(tr);
                    var dimInfoN = entN.GetDimInfo();
                    if (dimInfoN.DimLinePoint == newDimTwo[0] && dimInfoN.DimLinePointN == newDimTwo[1] ||
                        (dimInfoN.DimLinePoint == newDimTwo[1] && dimInfoN.DimLinePointN == newDimTwo[0])
                        )
                    {
                        entok = entN;
                        break;
                    }
                }
                if (entok != null)
                {
                    //获取标注信息
                    var dimInfoOk = entok.GetDimInfo();
                    var xLine1OkRo = dimInfoOk.XLine1Point.RotateBy(angle, ucs.ZAxis.ToVector3d(), dimMinPoint);
                    var xLine2OkRo = dimInfoOk.XLine2Point.RotateBy(angle, ucs.ZAxis.ToVector3d(), dimMinPoint);

                    //添加到生成表
                    var ddd = new Point3d[]
                    {
                    new Point3d(xLine1OkRo.X,entXLine1PointRo.Y, dimMinPoint.Z),//标注边点2
                    new Point3d(xLine1OkRo.X,dimMinPoint.Y, dimMinPoint.Z)      //标注确认点
                    };
                    shengchengList.Add(ddd);
                    ddd = new Point3d[]
                    {
                    new Point3d(xLine2OkRo.X,entXLine1PointRo.Y, dimMinPoint.Z),//标注边点2
                    new Point3d(xLine2OkRo.X,dimMinPoint.Y, dimMinPoint.Z)      //标注确认点
                    };
                    shengchengList.Add(ddd);
                }
            }

            //新建标注
            var bdq1 = new Point3d(getpointRo.X, entXLine1PointRo.Y, entXLine1PointRo.Z);//标注边点1
            bool fa = true;
            bool del = true;
            if (entok == null)//不是分裂的时候就为空
            {
                entok = ent;
                del   = false;
            }
            foreach (var bdq in shengchengList)
            {
                //点1 == 点2 表示标注值为0,点在了标注的脚上面
                if (bdq1 == bdq[0])
                {
                    fa = false;
                    break;
                }
            }
            if (fa)
            {
                var idsnew = new List<ObjectId>();
                foreach (var bdq in shengchengList)
                {
                    var id = entDimInfo.AddCreateDimToMsPs(tr, entok, bdq1, bdq[0], bdq[1]);
                    if (id != null)
                    {
                        idsnew.Add(id);    //新图元用来旋转
                        dimIdList.Add(id); //新图元加入链条
                    }
                }
                //新增标注旋转回去.
                tr.EntityRotate(idsnew.ToArray(), -angle, ucs.ZAxis.ToVector3d(), dimMinPoint);
                if (del)
                {
                    //删除原本,在增设的时候不删,在分裂的时候删掉
                    tr.EntityErase(entok.ObjectId.ToIEnumerable());
                    dimIdList.Remove(entok.ObjectId);
                }
            }
        });

        ent.Database.Action(tr => {
            tr.EntityRedraw(dimIdList.ToArray(), Bright.Highlight);//亮显
        });
        getpoint = null;//设置为空才重新点选
    }
    return dimIdList;
}

标注信息

/// <summary>
/// 获取标注的信息
/// </summary> 
public static DimInfo GetDimInfo(this Entity ent)
{
    DimInfo dimre = null;
    if (ent is AlignedDimension al)//对齐标注
    {
        dimre = new DimInfo(al);
    }
    else if (ent is RotatedDimension ro)//转角标注
    {
        dimre = new DimInfo(ro);
    }
    return dimre;
}
/// <summary>
/// 新建标注所需信息
/// </summary>
public class DimInfo
{
    /// <summary>
    /// 求标注的未知点
    /// </summary>
    /// <param name="xLine1Point">点1</param>
    /// <param name="dimLinePoint">旋转点</param>
    /// <param name="dimAngle">角度</param>
    /// <returns>未知点</returns>
    private static Point3d DimPointN(Point3d xLine1Point, Point3d dimLinePoint, double dimAngle)
    {
        //求出标注第一点下面那点
        Point3d dimLinePointN = new Point3d(xLine1Point.RotateBy(-dimAngle, Vector3d.ZAxis, dimLinePoint).X, dimLinePoint.Y, dimLinePoint.Z);
        dimLinePointN = dimLinePointN.RotateBy(dimAngle, Vector3d.ZAxis, dimLinePoint);
        return dimLinePointN;
    }

    /// <summary>
    /// 标注的类型
    /// </summary>
    public string DimType { get; set; }
    /// <summary>
    /// 标注的第一点
    /// </summary>
    public Point3d XLine1Point { get; set; }
    /// <summary>
    /// 标注的第二点
    /// </summary>
    public Point3d XLine2Point { get; set; }
    /// <summary>
    /// 标注的确定点与XLine2Point垂直的,甚至重合
    /// </summary>
    public Point3d DimLinePoint { get; set; }
    /// <summary>
    /// 标注的xLine1Point下面的点
    /// </summary>
    public Point3d DimLinePointN { get; set; }
    /// <summary>
    /// 标注的样式 
    /// </summary>
    public ObjectId DimensionStyle { get; set; }
    /// <summary>
    /// 标注的测量距离
    /// </summary>
    public double DimLength { get; set; }
    /// <summary>
    /// 标注的线性比例 
    /// </summary>
    public double DimScale { get; set; }
    /// <summary>
    /// 标注的标注角度
    /// </summary>
    public double DimAngle { get; set; }
    /// <summary>
    /// 全局比例
    /// </summary>
    public double Dimscale { get; set; }

    public DimInfo(AlignedDimension dim)
    {
        DimType = dim.GetType().Name;
        XLine1Point = dim.XLine1Point;  //标注第一点
        XLine2Point = dim.XLine2Point;  //标注的第二点
        DimLinePoint = dim.DimLinePoint;//确认点,在第二点下 
        DimensionStyle = dim.DimensionStyle;//标注样式
        DimLength = dim.Measurement;        //测量距离
        DimScale = dim.Dimlfac;             //线性比例 
        DimAngle = -(Pi2 - XLine1Point.GetAngle2XAxis(XLine2Point)); //标注角度
        DimLinePointN = DimPointN(XLine1Point, DimLinePoint, DimAngle); //求未知点 
        Dimscale = dim.Dimscale;//全局比例
    }
    public DimInfo(RotatedDimension dim)
    {
        DimType = dim.GetType().Name;
        XLine1Point = dim.XLine1Point;  //标注第一点
        XLine2Point = dim.XLine2Point;  //标注的第二点
        DimLinePoint = dim.DimLinePoint;//确认点,在第二点下 
        DimensionStyle = dim.DimensionStyle;//标注样式
        DimLength = dim.Measurement;        //测量距离
        DimScale = dim.Dimlfac;             //线性比例 
        DimAngle = dim.Rotation;            //标注角度 
        DimLinePointN = DimPointN(XLine1Point, DimLinePoint, DimAngle);//求未知点
        Dimscale = dim.Dimscale; //全局比例
    }
}

零零散散的子函数

/// <summary>
/// 标注链式反应器
/// </summary>
/// <param name="ed"></param>
/// <param name="ent"></param>
/// <param name="tr"></param>
/// <returns></returns>
public static List<ObjectId> ChainReactor(this Editor ed, Entity ent, Transaction tr)
{
    //清空选择集
    ed.SetImpliedSelection(new ObjectId[0]);

    //获取标注的后面两个点,然后通过这两个点获取选中标注样式    
    var dimInfoA = ent.GetDimInfo();

    //标注点,如果含有则选取
    var dimpts = new List<Point3d>() { dimInfoA.DimLinePoint, dimInfoA.DimLinePointN };

    //链式选择根据做个选择集  
    var ssids = new List<ObjectId>();

    //利用ssget将标注两点的图元选中
    //创建选择集过滤器,只选择标注
    TypedValue[] filList = new TypedValue[]
    {
        new TypedValue((int)DxfCode.Start, "DIMENSION")
    };
    SelectionFilter filter = new SelectionFilter(filList);
    var ss = ed.SelectAll(filter);

    if (ss.Status != PromptStatus.OK)
    {
        return null;
    }

    var ss1ids = ss.Value.GetObjectIds().ToList();
    Tolerance oldtol = Tolerance.Global; //旧容差
    Tolerance.Global = new Tolerance(1e-6, 1e-6);//新容差 
    bool fa = true;
    while (fa)
    {
        fa = false;
        foreach (ObjectId id in ss1ids.ToArray())
        {
            Entity dimN = id.ToEntity(tr);
            DimInfo dimInfoN = dimN.GetDimInfo();
            if (dimInfoN != null)
            {
                if (dimpts.Contains(dimInfoN.DimLinePoint) || dimpts.Contains(dimInfoN.DimLinePointN))
                {
                    double an = Math.Abs(dimInfoA.DimAngle - dimInfoN.DimAngle);
                    if (an < 1e-10 || Math.Abs(an - Math.PI) < 1e-10) //目标向量与X的夹角 || 目标逆向量与X的夹角
                    {
                        dimpts.Add(dimInfoN.DimLinePoint);
                        dimpts.Add(dimInfoN.DimLinePointN);
                        ssids.Add(id);//加入选择集
                        ss1ids.Remove(id);
                        fa = true;
                    }
                }
            }
        }
        //选择集在遍历的时候是有顺序的,但是点选并不一定在末尾位置,可能在中间,
        //所以通过点表判断前面的图元时,因为点表中并不存在邻点,所以出现链式选择失败.
        //一,通过向量判断,但是不在链条的同向量标注也会被选择上.
        //二,通过反向遍历一次,但是会增加时间,之所以要循环是因为若1,2的2在第一次没有加入,那么543这样加入了,导致链式选择少了..
        ss1ids.Reverse();
    }
    Tolerance.Global = oldtol;//恢复旧容差   
    return ssids;
}

/// <summary>
/// 获取标注链条所有的标注两个确认点
/// </summary>
public static IEnumerable<Point3d> GetDimLinePoints(Transaction tr, IEnumerable<ObjectId> idArr)
{
    var dimPointList = new List<Point3d>();
    foreach (var id in idArr)
    {
        Entity dimN = id.ToEntity(tr);
        DimInfo dimInfoN = dimN.GetDimInfo();
        dimPointList.Add(dimInfoN.DimLinePoint);
        dimPointList.Add(dimInfoN.DimLinePointN);
    }
    return dimPointList;
}

/// <summary>
/// 获取坐标系统三维
/// </summary>
/// <param name="ed"></param>
/// <param name="wcs"></param>
/// <param name="ucs"></param>
public static void GetWcsUcs(this Editor ed, out CoordinateSystem3d wcs, out CoordinateSystem3d ucs)
{
    Matrix3d Ide_wcs = Matrix3d.Identity;//获取世界坐标系
    wcs = Ide_wcs.CoordinateSystem3d;
    Matrix3d used_ucs = ed.CurrentUserCoordinateSystem;//当前用户坐标系
    ucs = used_ucs.CoordinateSystem3d;
}

(完)

posted @ 2021-02-26 22:10  惊惊  阅读(970)  评论(3编辑  收藏  举报