CAD获取外部参照内部图元

通过当前文件的块表记录递归获取图中所有所需的图元(如文字,直线等),如果当前文件的外部参照过多,通过本文件中外部参照的块表记录`BlockTableRecord`读取参照内部的图元速度极慢。这种情况下可以通过`XrefGraph`类获取所有的参照节点,通过`XrefGraph`获取每个外部参照中的图元,同时记录下每个外部参照的位置信息,最后将获取到的图元与外部参照对应,计算出正确的位置信息。代码如下,以获取文字为例。

 

public class Test
    {
        [CommandMethod("TextExtract")]
        public void Start()
        {
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            List<EntityInfo> ebs = new List<EntityInfo>();
            List<EntityInfo> texts = new List<EntityInfo>();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead) as BlockTableRecord;
                LayerTable lt = db.LayerTableId.GetObject(OpenMode.ForRead) as LayerTable;
                GetXrefsInfo(tr, ebs, btr, Point3d.Origin, new Scale3d(1), 0);
                tr.Abort();
            }
            #region 通过XrefGraph获取每个外部参照中的文字信息
            XrefGraph xg = db.GetHostDwgXrefGraph(false);
            for (int i = 0; i < xg.NumNodes; i++)
            {
                XrefGraphNode xNode = xg.GetXrefNode(i) as XrefGraphNode;
                var temp = ebs.FirstOrDefault(x => x.XrefFullPath.ToLower() == xNode.Database.Filename.ToLower());
                if (temp != null || xNode.Database.Filename.ToLower() == doc.Name.ToLower())
                {
                    using (Transaction tr = xNode.Database.TransactionManager.StartTransaction())
                    {
                        BlockTable bt = xNode.Database.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
                        BlockTableRecord btr = bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead) as BlockTableRecord;
                        List<EntityInfo> texts_temp = new List<EntityInfo>();
                        GetTextsInfo(tr, texts_temp, btr, Point3d.Origin, new Scale3d(1), 0);
                        texts_temp.ForEach(p => p.XrefFullPath = xNode.Database.Filename);//获取的文字图元是属于哪个外部参照
                        texts.AddRange(texts_temp);
                        tr.Abort();
                    }
                }
            }
            #endregion
            List<Entity> result = new List<Entity>();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                foreach (var item in texts)
                {
                    var xrefs = ebs.Where(x => x.XrefFullPath.ToLower() == item.XrefFullPath.ToLower()).ToList();//使用where是同一文件可能参照了多次
                    if (xrefs.Count == 0)//不在参照中
                    {
                        Entity entClone = item.Entity.Clone() as Entity;
                        Vector3d vec = item.Position - Point3d.Origin;
                        Matrix3d matrix3D = Matrix3d.Displacement(vec);
                        entClone.TransformBy(matrix3D);
                        if (item.Rotation != 0)//块参照旋转
                        {
                            Matrix3d rmatrix = Matrix3d.Rotation(item.Rotation, Vector3d.ZAxis, item.Position);
                            entClone.TransformBy(rmatrix);
                        }
                        entClone.ColorIndex = 1;
                        result.Add(entClone);
                    }
                    else
                    {
                        foreach (var xref in xrefs)
                        {
                            Vector3d vec = TransPoint3d(item.Position, xref.Position, xref.Scale, xref.Rotation) - Point3d.Origin;
                            Matrix3d matrix3D = Matrix3d.Displacement(vec);
                            Entity entClone = item.Entity.Clone() as Entity;
                            entClone.TransformBy(matrix3D);
                            if (xref.Scale.X * item.Scale.X == -1)//外部参照X轴镜像
                            {
                                Point3d pte = xref.Position + new Vector3d(0, 1, 0);
                                Line3d templ = new Line3d(xref.Position, pte);
                                Matrix3d mmatrix = Matrix3d.Mirroring(templ);
                                entClone.TransformBy(mmatrix);
                            }
                            if (xref.Scale.Y * item.Scale.Y == -1)//外部参照Y轴镜像
                            {
                                Point3d pte = xref.Position + new Vector3d(100, 0, 0);
                                Line3d templ = new Line3d(xref.Position, pte);
                                Matrix3d mmatrix = Matrix3d.Mirroring(templ);
                                entClone.TransformBy(mmatrix);
                            }
                            if (xref.Rotation + item.Rotation != 0)//外部参照旋转
                            {
                                Matrix3d rmatrix = Matrix3d.Rotation(xref.Rotation + item.Rotation, Vector3d.ZAxis, TransPoint3d(item.Position, xref.Position, xref.Scale, xref.Rotation));
                                entClone.TransformBy(rmatrix);
                            }

                            entClone.ColorIndex = 1;
                            result.Add(entClone);
                        }
                    }
                }
                foreach (var item in result)
                {
                    AddToModelSpace(db, item);
                }
                tr.Commit();
            }
        }

        /// <summary>
        /// 获取所有外部参照的位置,缩放,旋转信息
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="blocks"></param>
        /// <param name="btr"></param>
        /// <param name="position"></param>
        /// <param name="scale"></param>
        /// <param name="rotate"></param>
        public void GetXrefsInfo(Transaction trans, List<EntityInfo> blocks, BlockTableRecord btr, Point3d position, Scale3d scale, double rotate)
        {
            foreach (var item in btr)
            {
                Entity ent = item.GetObject(OpenMode.ForRead) as Entity;
                if (ent is BlockReference)
                {
                    BlockReference block = ent as BlockReference;
                    if (block.BlockTableRecord != ObjectId.Null && block.Visible)//如果块隐藏了,就不取该块及其子参照信息
                    {
                        BlockTableRecord blockrecord = block.BlockTableRecord.GetObject(OpenMode.ForRead) as BlockTableRecord;
                        if (blockrecord.IsFromExternalReference || blockrecord.IsFromOverlayReference)
                        {
                            string temppath = blockrecord.PathName;
                            if (temppath.StartsWith(@".\"))
                                temppath = Path.GetFullPath(temppath);
                            EntityInfo eb = new EntityInfo()
                            {
                                Entity = block,
                                Position = TransPoint3d(block.Position, position, scale, rotate),//外部参照在当前文件中的实际位置
                                Scale = block.ScaleFactors * scale,//外部参照在当前文件中的实际缩放
                                Rotation = block.Rotation + rotate,//外部参照在当前文件中的实际旋转角度
                                XrefFullPath = temppath             //外部参照的文件路径
                            };
                            blocks.Add(eb);
                        }
                        GetXrefsInfo(trans, blocks, blockrecord, TransPoint3d(block.Position, position, scale, rotate), block.ScaleFactors * scale, block.Rotation + rotate);
                    }
                }
            }
        }

        /// <summary>
        /// 获取文字的信息
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="texts"></param>
        /// <param name="btr"></param>
        /// <param name="position"></param>
        /// <param name="scale"></param>
        /// <param name="rotate"></param>
        public void GetTextsInfo(Transaction trans, List<EntityInfo> texts, BlockTableRecord btr, Point3d position, Scale3d scale, double rotate)
        {
            foreach (var item in btr)
            {
                Entity ent = item.GetObject(OpenMode.ForRead) as Entity;
                if (ent is BlockReference)
                {
                    BlockReference block = ent as BlockReference;
                    if (block.BlockTableRecord != ObjectId.Null)
                    {
                        BlockTableRecord blockrecord = block.BlockTableRecord.GetObject(OpenMode.ForRead) as BlockTableRecord;
                        if (!blockrecord.IsFromExternalReference && !blockrecord.IsFromOverlayReference && block.Visible)//非外部参照并且可见
                        {
                            GetTextsInfo(trans, texts, blockrecord, TransPoint3d(block.Position, position, scale, rotate), scale * block.ScaleFactors, rotate + block.Rotation);
                        }
                    }
                }
                else if (ent is DBText)
                {
                    EntityInfo eb = new EntityInfo()
                    {
                        Entity = ent,
                        Position = position,//在块中的相对位置
                        Rotation = rotate,//在块中的旋转角度
                        Scale = scale   //在块中的缩放比例
                    };
                    texts.Add(eb);
                }

            }
        }

        public Point3d TransPoint3d(Point3d before, Point3d origin, Scale3d scale, double rotation)
        {
            double X = origin.X + scale.X * before.X;
            double Y = origin.Y + scale.Y * before.Y;
            Point3d pt = new Point3d(X, Y, 0.0);
            double angle = GetAngle(origin, pt) + rotation;
            Point3d pt3d = Polar(origin, angle, pt.DistanceTo(origin));
            return pt3d;
        }

        public double GetAngle(Point3d pt1, Point3d pt2)
        {
            //构建一个从第一点到第二点所确定的矢量
            Vector2d vector = new Vector2d(pt2.X - pt1.X, pt2.Y - pt1.Y);
            //返回该矢量和X轴正半轴的角度(弧度)
            return vector.Angle;
        }

        public Point3d Polar(Point3d point, double angle, double dist)
        {
            return new Point3d(point.X + dist * Math.Cos(angle), point.Y + dist * Math.Sin(angle), point.Z);
        }

        public ObjectId AddToModelSpace(Database db, Entity ent)
        {
            ObjectId result;
            using (Transaction transaction = db.TransactionManager.StartTransaction())
            {
                BlockTable blockTable = (BlockTable)transaction.GetObject(db.BlockTableId, 0);
                BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                result = blockTableRecord.AppendEntity(ent);
                transaction.AddNewlyCreatedDBObject(ent, true);
                transaction.Commit();
            }
            return result;
        }
    }

  

public class EntityInfo
    {
        public Entity Entity { get; set; }

        public double Rotation { get; set; }

        public Point3d Position { get; set; }

        public Scale3d Scale { get; set; }

        public string XrefFullPath { get; set; }

    }

  

 

posted @ 2022-02-21 10:46  三三四三  阅读(334)  评论(0)    收藏  举报