• cad.net Attsync命令导致属性块的属性位置在高低cad版本产生不同的效果


    演示

    左边是旋转的,右边是左边镜像的.

    用了Attsync命令之后,左边是旋转的,会发现文字是正的..右边则是反的.

    img

    用了Attsync命令之后,左边是旋转的,会发现文字是正的..右边则是反的.*2

    img

    动图演示

    img

    出问题的函数

    at.SetAttributeFromBlock(attDef, brf.BlockTransform);//从块设置属性                                     
    

    原因

    Acad2008和Acad2019使用Attsync命令处理镜像的属性块的属性时会有不同的效果.
    而桌子并不是重写一个新的命令或者写一个拓展函数,而是修改了原本的函数.
    因为我用代码实现,依然会发生这样的事情.

    桌子的想法也很简单:
    1,考虑了法向量.
    2,对齐方式是"调整",桌子还会位移了.
    但是这就给我们二次开发一个很不好的地方是,我们需要自行去处理不同呈现的结果.

    处理方式是写一个命令来替换掉cad自带的命令,
    然后自己的命令需要对旋转或者镜像分别处理,某些情况下不调用SetAttributeFromBlock.

    代码

    我没有动过SetAttributeFromBlock,仅仅是注释一下其中的意义:

    /// <summary>
    /// 设置块属性
    /// </summary>
    /// <param name="at">属性引用(块外)</param>
    /// <param name="blockTransform">块的矩阵变换</param> 
    /// <param name="definition">属性定义(块内)</param>  
    public static void SetAttributeFromBlockEx(this AttributeReference at, Matrix3d blockTransform,  AttributeDefinition definition = null)
    {
        // 为了解决SetAttributeFromBlock的新旧版本不同的问题,所以这里写一个替换函数
        // 强行将cad2008的旋转方式修改成与cad2019一样.因为cad2019留意到法向量的问题
        // 原本这个函数会令TextString丢失,所以后面要重设(这里考虑不改变它
        // 旋转矩阵则不要用它,不然会设置两次旋转
        // 平移矩阵则不要用它,不然会设置两次平移
    
        if (definition == null) // 不提供属性定义表示不对比块内信息,就直接执行矩阵.
        {
            at.SetAttributeFromBlock(blockTransform);
        }
        else
        {
            at.SetAttributeFromBlock(definition, blockTransform);
        }
    }
    

    更为具体要看这里的操作:
    ps:由于缺少的函数太多了,这里仅仅提供关键的几个操作,请不要跟我要具体的代码.

    public class Command_JJAttsync
    {
        //如果属性块镜像后更新,会导致属性翻转,这个功能用来翻转回来 
        [CommandMethod("JJ_Attsync", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public static void JJ_Attsync()
        {
            try
            {
                Database db = HostApplicationServices.WorkingDatabase;//当前的数据库
                Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;
                ed.WriteMessage(Environment.NewLine + "****惊惊连盒-翻转属性块更新");
                var ssIdArray = Command_jjak.AllSelectByBlockName(ed, db, BlockTool.EnumAttIdentical.AllBlockName);
                if (ssIdArray.Length == 0)
                {
                    return;
                }
    
                //遍历块内所有的属性引用,如果缺失属性引用的话,就新建属性引用;
                //如果不缺失,就将属性引用修改信息(矩阵)为属性引用上,保留文字
                Acap.DocumentManager.MdiActiveDocument.Action(() =>
                {
                    var tags = new List<string>();//用来删除没有tag的属性引用.
                    db.Action(tr =>
                    {
                        foreach (var item in ssIdArray)
                        {
                            var ent = item.ToEntity(tr);
                            if (ent is BlockReference brf)
                            {
                                //储存属性引用
                                var attrlst = brf.ToAttributes(tr);
    
                                //遍历块内
                                var btRec = tr.GetObject(brf.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
                                foreach (ObjectId id in btRec)
                                {
                                    btRec.TraversalAttribute(tr, (attDef) =>
                                    {
                                        tags.Add(attDef.Tag);
                                        bool isNewAtt = false;
                                        AttributeReference at = null;
                                        string textString = "";
                                        foreach (var ata in attrlst)
                                        {
                                            //设置 标记Tag 提示Prompt 默认TextString
                                            if (ata.Tag == attDef.Tag)
                                            {
                                                at = ata;
                                                textString = at.TextString;
                                                at.UpgradeOpen();
                                                break;
                                            }
                                        }
                                        if (at == null)
                                        {
                                            isNewAtt = true;
                                            at = new AttributeReference
                                            {
                                                Tag = attDef.Tag,
    #if AC2008 || AC2009
                                                TextStyle = attDef.TextStyle,
    #else
                                                TextStyleId = attDef.TextStyleId,
    #endif
                                            };
                                            if (textString == "")
                                            {
                                                textString = attDef.TextString;
                                            }
                                        }
    
                                        //从属性定义获取属性对象的对象特性
                                        at.SetAttributeFromBlockEx(brf.BlockTransform, attDef);
                                        at.AdjustAlignment(brf.Database);//调整对齐
    
                                        //设置 标记Tag 提示Prompt 默认TextString 
                                        at.TextString = textString;
                                        if (isNewAtt)
                                        {
                                            //向块参照添加属性对象
                                            brf.UpgradeOpen();
                                            brf.AttributeCollection.AppendAttribute(at);
                                            brf.DowngradeOpen();
                                            tr.AddNewlyCreatedDBObject(at, true);
                                        }
                                    });
    
                                    foreach (ObjectId attId in brf.AttributeCollection)
                                    {
                                        if (attId.IsOk())
                                        {
                                            var ata = tr.GetObject(attId, OpenMode.ForRead) as AttributeReference;
                                            //设置 标记Tag 提示Prompt 默认TextString 
                                            if (!tags.Contains(ata.Tag))
                                            {
                                                ata.UpgradeOpen();
                                                ata.Erase(); //删除没有属性的(和as一样)
                                                ata.Dispose();
                                            }
                                        }
                                    }
                                }
                                tags.Clear();
                            }
                        }
                    });
    
                    db.Action(tr =>
                    {
                        foreach (var item in ssIdArray)
                        {
                            var ent = item.ToEntity(tr);
                            if (ent is BlockReference brf) //旋转到当前鼠标坐标系 CoordinateSystem3d
                            {
                                //储存属性引用
                                var attrlst = brf.ToAttributes(tr);
    
                                //症结点在于整体缩放时候无法通过X<1来判断块的镜像
                                //缩放或者变形
                                if (brf.ScaleFactors.X >= 0 && brf.Normal.Z == 1) //没有镜像的图元,法向量正常=> 
                                {
                                    //旋转
                                    foreach (var at in attrlst)
                                    {
                                        at.UpgradeOpen();
                                        RotateAttributeReference(brf, at);
                                        at.DowngradeOpen();
                                        at.Dispose();
                                    }
                                }
                                else if (brf.ScaleFactors.X >= 0 && brf.Normal.Z == -1)//没有镜像的图元,法向量不正常=>
                                {
                                    //镜像并旋转 
                                    foreach (var at in attrlst)
                                    {
                                        at.UpgradeOpen();
                                        var ro = at.Rotation;
                                        MirrorAttributeReference(brf, at, ro);
                                        at.DowngradeOpen();
                                        at.Dispose();
                                    }
                                }
                                else if (brf.ScaleFactors.X < 0 && brf.Normal.Z == 1)//镜像的图元,法向量正常=>
                                {
                                    foreach (var at in attrlst)
                                    {
                                        at.UpgradeOpen();
    #if AC2008
                                        //镜像并旋转
                                        var ro = at.Rotation;
                                        MirrorAttributeReference(brf, at, -ro);
    #else
                                        //测试是AC2019
                                        Alignment2019Mr1(brf, at);
    #endif
                                        at.DowngradeOpen();
                                        at.Dispose();
                                    }
                                }
                                else if (brf.ScaleFactors.X < 0 && brf.Normal.Z == -1) //镜像的图元,法向量不正常=>
                                {
                                    foreach (var at in attrlst)
                                    {
                                        at.UpgradeOpen();
    #if AC2008
                                        //旋转
                                        RotateAttributeReference(brf, at);
    #else
                                        //测试是AC2019
                                        Alignment2019Mr2(brf, at);
    #endif
                                        at.DowngradeOpen();
                                        at.Dispose();
                                    }
                                }
                            }
                        }
                    });
    
                });
    
                ed.SetImpliedSelection(new ObjectId[] { }); //选择
            }
            catch
            { }
        }
    
        /// <summary>
        /// 处理2019cad的属性块2
        /// </summary>
        /// <param name="brf">块参照</param>
        /// <param name="at">属性</param> 
        private static void Alignment2019Mr2(BlockReference brf, AttributeReference at)
        {
            var ro = at.Rotation;
    
            if (at.Justify == EntityAdd.TxtAlignment("铺满") ||
                at.Justify == EntityAdd.TxtAlignment("调整"))
            {
                at.Rotation = 0;//这个角度是不会设置到图元中的,但是之后求包围盒都是0角度的了,很有趣
                var boxEdge = new GeometricExtents(at).Edge3;//求包围盒
    
                boxEdge.RotateBy(ro, at.Normal, at.Position);
                var ro_RightUpper = boxEdge.RightUpper;//右上
                var ro_RightDown = boxEdge.RightDown;//右下 
                var ro_MidstUpper = boxEdge.MidstUpper;//中上
                var ro_MidstDown = boxEdge.MidstDown; //中下
                var ro_Midst = boxEdge.Midst;//中间
    
                //先平移,不然用上下镜像会有误差的
                at.EntityMove(ro_RightUpper, ro_RightDown);
    
                //上下镜像  
                var mt = at.EntityMirror(ro_MidstUpper, ro_MidstDown, out _);
                at.SetAttributeFromBlockEx(mt);
    
                if (!(brf.Rotation > Math.PI / 2 && brf.Rotation < Math.PI / 2 * 3))
                {
                    ro_Midst += ro_RightUpper.GetVectorTo(ro_RightDown);
                    at.EntityRotate(Math.PI, at.Normal, ro_Midst);
                }
            }
            else
            {
                MirrorAttributeReference(brf, at, ro);
    
                //保证右边的旋转是对的.这里是镜像过,所以要判断brf.Rotation>=的
                if (brf.Rotation >= Math.PI / 2 && brf.Rotation < Math.PI / 2 * 3)
                {
                    //求包围盒
                    var boxEdge = new GeometricExtents(at).Edge3;
                    {
                        at.EntityRotate(Math.PI, at.Normal, boxEdge.Midst);
                    }
                }
            }
            at.AdjustAlignment(brf.Database);//调整对齐
        }
    
        /// <summary>
        /// 处理2019cad的属性块1
        /// </summary>
        /// <param name="brf">块参照</param>
        /// <param name="at">属性</param> 
        private static void Alignment2019Mr1(BlockReference brf, AttributeReference at)
        {
            if (at.Justify == EntityAdd.TxtAlignment("铺满") ||
                at.Justify == EntityAdd.TxtAlignment("调整"))
            {
                //求包围盒          
                var boxEdge = new GeometricExtents(at).Edge3;
                if (brf.Rotation > Math.PI / 2 && brf.Rotation < Math.PI / 2 * 3)
                {
                    //平移
                    var ro = at.Rotation;
                    at.Rotation = 0;//这个角度是不会设置到图元中的,但是之后求包围盒都是0角度的了,很有趣
                    boxEdge = new GeometricExtents(at).Edge3;//求包围盒  
                    var leftUpper = boxEdge.LeftUpper.RotateBy(ro, at.Normal, at.Position);
                    at.EntityMove(leftUpper, at.Position);
                }
                else
                {
                    //旋转
                    at.EntityRotate(Math.PI, at.Normal, boxEdge.Midst);
                    at.AdjustAlignment(brf.Database);//调整对齐
    
                    //平移
                    var ro = at.Rotation;
                    at.Rotation = 0;//这个角度是不会设置到图元中的,但是之后求包围盒都是0角度的了,很有趣
                    boxEdge = new GeometricExtents(at).Edge3;//求包围盒  
                    var leftUpper = boxEdge.LeftUpper.RotateBy(ro, at.Normal, at.Position);
                    at.EntityMove(at.Position, leftUpper);
                }
            }
            else
            {
                if (brf.Rotation == Math.PI / 2)
                {
                    //求包围盒
                    var boxEdge = new GeometricExtents(at).Edge3;
                    {
                        at.EntityRotate(Math.PI, at.Normal, boxEdge.Midst);
                        //不要at.AttributeFromBlock(mt)的,否则会set两次角度...很奇怪耶 
                        at.AdjustAlignment(brf.Database);//调整对齐 不然08和19不一样显示 
                    }
                }
            }
        }
    
        /// <summary>
        /// 镜像块的属性引用
        /// </summary>
        /// <param name="brf">块参照</param>
        /// <param name="at">属性</param>
        /// <param name="rotation">旋转角度,因为法向量不同而选择块的正值或负值</param>
        private static void MirrorAttributeReference(BlockReference brf, AttributeReference at, double rotation)
        {
            //克隆一份属性来旋转,计算它的最小包围盒
            var atClone = at.Clone() as AttributeReference;
            atClone.Rotation = 0;
            var boxEdge = new GeometricExtents(atClone).Edge3;//求包围盒  
            //将包围盒上下两个点逆旋转到文字的位置,提供给镜像使用.
            var muPt = boxEdge.MidstUpper.RotateBy(rotation, brf.BlockTransform.CoordinateSystem3d.Zaxis, atClone.Position);
            var mdPt = boxEdge.MidstDown.RotateBy(rotation, brf.BlockTransform.CoordinateSystem3d.Zaxis, atClone.Position);
            atClone.Dispose();
    
            //镜像矩阵
            var mt = at.EntityMirror(muPt, mdPt, out _);
            at.SetAttributeFromBlockEx(mt);
            RotateAttributeReference(brf, at);
        }
    
        /// <summary>
        /// 旋转块的属性引用
        /// </summary>
        /// <param name="brf"></param>
        /// <param name="at"></param>
        private static void RotateAttributeReference(BlockReference brf, AttributeReference at)
        {
            //模仿标注,0~90度不改,270~360度不改
            //90~270度就改成与块的旋转的+180度->所以只需要处理这种情况  
            //一般的块是从x轴上面开始计算0度的,逆时针    
            if (brf.Rotation > Math.PI / 2 && brf.Rotation < Math.PI / 2 * 3)
            {
                //求包围盒
                var boxEdge = new GeometricExtents(at).Edge3;
    
                //at.EntityRotate(Math.PI, brf.BlockTransform.CoordinateSystem3d.Zaxis, boxEdge.Midst);
                at.EntityRotate(Math.PI, at.Normal, boxEdge.Midst);
                //不要at.AttributeFromBlock(mt)的,否则会set两次角度...很奇怪耶 
                at.AdjustAlignment(brf.Database);//调整对齐 不然08和19不一样显示
            }
        }
    }
    

    (完)

  • 相关阅读:
    JavaWeb 之 使用 commons-fileupload.jar 实现文件上传
    JavaWeb 之 web项目中的路径问题
    JavaWeb 之 GET请求和POST请求的乱码问题
    URI、URL 和 URN 的区别
    JavaWeb 之 ServletConfig 接口
    JavaWeb 之 使用开发工具创建 Servlet 程序
    JavaWeb 之 GET和POST 请求的分发处理
    JavaWeb 【目录】----------------------------------------【目录】
    JavaWeb 之 开发工具整合 Tomcat服务器
    【LeetCode-数学】Excel表列序号
  • 原文地址:https://www.cnblogs.com/JJBox/p/12433735.html
Copyright © 2020-2023  润新知