C#二次开发中简单块的定义与应用

csharp 复制代码
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using App = Autodesk.AutoCAD.ApplicationServices.Application;
namespace AutoBlockManager
{
    public class BlockManager
    {
        // 块配置常量
        private const string BLOCK_NAME = "firstBlock";
        private const double OUTER_SQUARE_SIZE = 100.0;
        private const double DEFAULT_SPACING = 150.0;

        [CommandMethod("inFB")]
        public void CreateAndInsertFirstBlock()
        {
            Document doc = App.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            try
            {
                // 步骤1: 检查块是否存在
                bool blockExists = CheckBlockExists(db);

                // 步骤2: 如果不存在,先创建块
                if (!blockExists)
                {
                    ed.WriteMessage("\n⚠ 块 'firstBlock' 不存在,正在创建...");
                    CreateFirstBlock(db, ed);
                    ed.WriteMessage("\n✓ 块创建完成!");
                }
                else
                {
                    ed.WriteMessage("\n✓ 检测到现有块 'firstBlock'");
                }

                // 步骤3: 获取用户输入并插入10个块
                if (GetUserInput(ed, out Point3d startPoint, out double spacing))
                {
                    InsertTenBlocks(db, ed, startPoint, spacing);
                    ed.WriteMessage($"\n✅ 成功插入10个'firstBlock'块!");
                    ed.WriteMessage($"\n起始点: ({startPoint.X:F2}, {startPoint.Y:F2})");
                    ed.WriteMessage($"\n间距: {spacing:F2}");
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n❌ 错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 检查块是否存在
        /// </summary>
        private bool CheckBlockExists(Database db)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                bool exists = bt.Has(BLOCK_NAME);
                tr.Commit();
                return exists;
            }
        }

        /// <summary>
        /// 创建firstBlock块定义
        /// </summary>
        private void CreateFirstBlock(Database db, Editor ed)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;

                // 检查是否已存在同名块(再次确认)
                if (bt.Has(BLOCK_NAME))
                {
                    // 先删除现有的块定义
                    DeleteExistingBlock(bt, tr, ed);
                }

                // 创建块表记录
                BlockTableRecord btr = new BlockTableRecord();
                btr.Name = BLOCK_NAME;

                // 创建几何图形
                CreateGeometricShapes(btr);

                // 添加到数据库
                ObjectId blockId = bt.Add(btr);
                tr.AddNewlyCreatedDBObject(btr, true);

                tr.Commit();
            }
        }

        /// <summary>
        /// 删除已存在的块定义
        /// </summary>
        private void DeleteExistingBlock(BlockTable bt, Transaction tr, Editor ed)
        {
            try
            {
                ObjectId blockId = bt[BLOCK_NAME];
                if (!blockId.IsErased)
                {
                    BlockTableRecord existingBtr = tr.GetObject(blockId, OpenMode.ForWrite) as BlockTableRecord;

                    // 检查是否有块引用
                    ObjectIdCollection refIds = existingBtr.GetBlockReferenceIds(true,true);
                    if (refIds != null && refIds.Count > 0)
                    {
                        ed.WriteMessage($"\n⚠ 块 '{BLOCK_NAME}' 有 {refIds.Count} 个引用,需要清理...");

                        // 删除所有引用
                        foreach (ObjectId refId in refIds)
                        {
                            if (!refId.IsErased)
                            {
                                Entity ent = tr.GetObject(refId, OpenMode.ForWrite) as Entity;
                                ent.Erase();
                            }
                        }
                    }

                    // 删除块定义
                    existingBtr.Erase();
                    ed.WriteMessage($"\n🗑️ 已删除现有块 '{BLOCK_NAME}',重新创建...");
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n⚠ 删除现有块时出错: {ex.Message}");
                // 继续创建新块
            }
        }

        /// <summary>
        /// 创建所有几何图形
        /// </summary>
        private void CreateGeometricShapes(BlockTableRecord btr)
        {
            // 外层正方形
            double halfSize = OUTER_SQUARE_SIZE / 2;
            Polyline outerSquare = new Polyline();
            outerSquare.AddVertexAt(0, new Point2d(-halfSize, -halfSize), 0, 0, 0);
            outerSquare.AddVertexAt(1, new Point2d(halfSize, -halfSize), 0, 0, 0);
            outerSquare.AddVertexAt(2, new Point2d(halfSize, halfSize), 0, 0, 0);
            outerSquare.AddVertexAt(3, new Point2d(-halfSize, halfSize), 0, 0, 0);
            outerSquare.Closed = true;
            outerSquare.ColorIndex = 1;
            btr.AppendEntity(outerSquare);

            // 内切圆
            double circleRadius = halfSize;
            Circle innerCircle = new Circle(Point3d.Origin, Vector3d.ZAxis, circleRadius);
            innerCircle.ColorIndex = 3;
            btr.AppendEntity(innerCircle);

            // 内接正方形
            Polyline innerSquare = new Polyline();
            innerSquare.AddVertexAt(0, new Point2d(0, circleRadius), 0, 0, 0);
            innerSquare.AddVertexAt(1, new Point2d(circleRadius, 0), 0, 0, 0);
            innerSquare.AddVertexAt(2, new Point2d(0, -circleRadius), 0, 0, 0);
            innerSquare.AddVertexAt(3, new Point2d(-circleRadius, 0), 0, 0, 0);
            innerSquare.Closed = true;
            innerSquare.ColorIndex = 5;
            btr.AppendEntity(innerSquare);

            // 三角形
            double triangleRadius = circleRadius * 0.4; // 调整大小
            Polyline triangle = new Polyline();
            for (int i = 0; i < 3; i++)
            {
                double angle = (Math.PI / 2) - (i * 2 * Math.PI / 3);
                double x = triangleRadius * Math.Cos(angle);
                double y = triangleRadius * Math.Sin(angle);
                triangle.AddVertexAt(i, new Point2d(x, y), 0, 0, 0);
            }
            triangle.Closed = true;
            triangle.ColorIndex = 2;
            btr.AppendEntity(triangle);

            // 中心标记
            Line centerX = new Line(new Point3d(-5, 0, 0), new Point3d(5, 0, 0));
            centerX.ColorIndex = 7;
            btr.AppendEntity(centerX);

            Line centerY = new Line(new Point3d(0, -5, 0), new Point3d(0, 5, 0));
            centerY.ColorIndex = 7;
            btr.AppendEntity(centerY);
        }

        /// <summary>
        /// 获取用户输入 - 修正后的方法
        /// </summary>
        private bool GetUserInput(Editor ed, out Point3d startPoint, out double spacing)
        {
            startPoint = Point3d.Origin;
            spacing = DEFAULT_SPACING;

            try
            {
                // 方法1:使用 GetDistance 获取距离
                PromptPointOptions ppo = new PromptPointOptions("\n选择第一个插入点: ");
                PromptPointResult ppr = ed.GetPoint(ppo);
                if (ppr.Status != PromptStatus.OK) return false;
                startPoint = ppr.Value;

                // 正确使用 PromptDistanceOptions 和 GetDistance
                PromptDistanceOptions pdo = new PromptDistanceOptions("\n输入块之间的间距: ");
                pdo.BasePoint = startPoint;
                pdo.UseBasePoint = true;
                pdo.DefaultValue = DEFAULT_SPACING;
                pdo.AllowNegative = false;
                pdo.AllowZero = false;
                pdo.UseDefaultValue = true;

                PromptDoubleResult pdr = ed.GetDistance(pdo);  // 注意:这里是 GetDistance,不是 GetDouble
                if (pdr.Status != PromptStatus.OK) return false;
                spacing = pdr.Value;

                return true;
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n⚠ 输入错误: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 获取用户输入的替代方法(更简单的方式)
        /// </summary>
        private bool GetUserInputAlternative(Editor ed, out Point3d startPoint, out double spacing)
        {
            startPoint = Point3d.Origin;
            spacing = DEFAULT_SPACING;

            try
            {
                // 获取插入点
                PromptPointOptions ppo = new PromptPointOptions("\n选择第一个插入点: ");
                PromptPointResult ppr = ed.GetPoint(ppo);
                if (ppr.Status != PromptStatus.OK) return false;
                startPoint = ppr.Value;

                // 方法2:使用 GetDouble 获取数值(更简单)
                PromptDoubleOptions pdo = new PromptDoubleOptions("\n输入块之间的间距 <" + DEFAULT_SPACING + ">: ");
                pdo.DefaultValue = DEFAULT_SPACING;
                pdo.AllowNegative = false;
                pdo.AllowZero = false;
                pdo.UseDefaultValue = true;

                PromptDoubleResult pdr = ed.GetDouble(pdo);  // 直接获取数值
                if (pdr.Status != PromptStatus.OK) return false;
                spacing = pdr.Value;

                return true;
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n⚠ 输入错误: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 插入10个块
        /// </summary>
        private void InsertTenBlocks(Database db, Editor ed, Point3d startPoint, double spacing)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord modelSpace = tr.GetObject(
                    bt[BlockTableRecord.ModelSpace],
                    OpenMode.ForWrite
                ) as BlockTableRecord;

                // 再次确认块存在
                if (!bt.Has(BLOCK_NAME))
                {
                    ed.WriteMessage($"\n❌ 错误: 块 '{BLOCK_NAME}' 不存在!");
                    return;
                }

                ObjectId blockId = bt[BLOCK_NAME];

                for (int i = 0; i < 10; i++)
                {
                    // 计算位置
                    Point3d insertPoint = new Point3d(
                        startPoint.X + i * spacing,
                        startPoint.Y,
                        startPoint.Z
                    );

                    // 创建块引用
                    BlockReference blockRef = new BlockReference(insertPoint, blockId);

                    // 添加旋转效果(可选)
                    if (i % 2 == 0)
                    {
                        blockRef.Rotation = 15 * Math.PI / 180; // 15度
                    }

                    modelSpace.AppendEntity(blockRef);
                    tr.AddNewlyCreatedDBObject(blockRef, true);

                    // 添加编号
                    AddBlockNumber(tr, modelSpace, insertPoint, i);
                }

                tr.Commit();
            }
        }

        /// <summary>
        /// 添加块编号文字
        /// </summary>
        private void AddBlockNumber(Transaction tr, BlockTableRecord modelSpace, Point3d insertPoint, int index)
        {
            DBText text = new DBText();
            text.Position = new Point3d(insertPoint.X, insertPoint.Y - 60, 0);
            text.Height = 10;
            text.TextString = $"FB-{index + 1}";
            text.ColorIndex = 7;
            text.HorizontalMode = TextHorizontalMode.TextCenter;
            text.VerticalMode = TextVerticalMode.TextBottom;
            text.AlignmentPoint = text.Position;

            modelSpace.AppendEntity(text);
            tr.AddNewlyCreatedDBObject(text, true);
        }

        /// <summary>
        /// 辅助命令:检查块状态
        /// </summary>
        [CommandMethod("CheckFB")]
        public void CheckFirstBlockStatus()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            bool exists = CheckBlockExists(db);

            if (exists)
            {
                ed.WriteMessage("\n✅ 块 'firstBlock' 存在,可以使用 inFB 命令插入。");
            }
            else
            {
                ed.WriteMessage("\n❌ 块 'firstBlock' 不存在。");
                ed.WriteMessage("\n   运行 inFB 命令将自动创建并插入该块。");
            }
        }

        /// <summary>
        /// 辅助命令:删除块定义
        /// </summary>
        [CommandMethod("DeleteFB")]
        public void DeleteFirstBlock()
        {
            Document doc = App.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;

                    if (bt.Has(BLOCK_NAME))
                    {
                        ObjectId blockId = bt[BLOCK_NAME];
                        BlockTableRecord btr = tr.GetObject(blockId, OpenMode.ForWrite) as BlockTableRecord;

                        // 检查是否有块引用
                        bool hasReferences = false;
                        ObjectIdCollection refIds = btr.GetBlockReferenceIds(true, true);
                        if (refIds != null && refIds.Count > 0)
                        {
                            hasReferences = true;
                            ed.WriteMessage($"\n⚠ 块 '{BLOCK_NAME}' 有 {refIds.Count} 个引用。");

                            // 询问用户是否删除引用
                            PromptKeywordOptions pko = new PromptKeywordOptions(
                                $"\n是否删除所有 {refIds.Count} 个块引用?[是(Y)/否(N)] <N>: ");
                            pko.Keywords.Add("Y");
                            pko.Keywords.Add("N");
                            pko.Keywords.Default = "N";

                            PromptResult pr = ed.GetKeywords(pko);
                            if (pr.StringResult == "Y")
                            {
                                // 删除所有块引用
                                foreach (ObjectId refId in refIds)
                                {
                                    if (!refId.IsErased)
                                    {
                                        Entity ent = tr.GetObject(refId, OpenMode.ForWrite) as Entity;
                                        ent.Erase();
                                    }
                                }
                                hasReferences = false;
                                ed.WriteMessage($"\n✓ 已删除 {refIds.Count} 个块引用。");
                            }
                        }

                        if (!hasReferences)
                        {
                            // 删除块定义
                            btr.Erase();
                            ed.WriteMessage($"\n🗑️ 已删除块 '{BLOCK_NAME}' 定义。");
                        }
                        else
                        {
                            ed.WriteMessage($"\n⚠ 保留块定义(引用未删除)。");
                        }
                    }
                    else
                    {
                        ed.WriteMessage($"\n⚠ 块 '{BLOCK_NAME}' 不存在,无需删除。");
                    }

                    tr.Commit();
                }
            }
            catch (Autodesk.AutoCAD.Runtime.Exception ex)
            {
                ed.WriteMessage($"\n❌ 删除失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 辅助命令:插入块并设置参数
        /// </summary>
        [CommandMethod("inFB2")]
        public void InsertFirstBlockWithOptions()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            try
            {
                // 确保块存在
                if (!CheckBlockExists(db))
                {
                    ed.WriteMessage("\n⚠ 块 'firstBlock' 不存在,正在创建...");
                    CreateFirstBlock(db, ed);
                }

                // 获取用户输入(使用替代方法)
                if (GetUserInputAlternative(ed, out Point3d startPoint, out double spacing))
                {
                    // 获取旋转角度
                    double rotation = GetRotationAngle(ed);

                    // 获取缩放比例
                    double scale = GetScaleFactor(ed);

                    // 插入块
                    InsertBlocksWithParameters(db, ed, startPoint, spacing, rotation, scale);

                    ed.WriteMessage($"\n✅ 成功插入10个'firstBlock'块!");
                    ed.WriteMessage($"\n参数: 间距={spacing:F2}, 旋转={rotation:F1}°, 缩放={scale:F2}");
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n❌ 错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取旋转角度
        /// </summary>
        private double GetRotationAngle(Editor ed)
        {
            PromptDoubleOptions pdo = new PromptDoubleOptions("\n输入旋转角度(度) <0>: ");
            pdo.DefaultValue = 0.0;
            pdo.AllowNegative = true;
            pdo.AllowZero = true;
            pdo.UseDefaultValue = true;

            PromptDoubleResult pdr = ed.GetDouble(pdo);
            if (pdr.Status == PromptStatus.OK)
            {
                return pdr.Value * Math.PI / 180.0; // 转换为弧度
            }
            return 0.0;
        }

        /// <summary>
        /// 获取缩放比例
        /// </summary>
        private double GetScaleFactor(Editor ed)
        {
            PromptDoubleOptions pdo = new PromptDoubleOptions("\n输入缩放比例 <1.0>: ");
            pdo.DefaultValue = 1.0;
            pdo.AllowNegative = false;
            pdo.AllowZero = false;
            pdo.UseDefaultValue = true;

            PromptDoubleResult pdr = ed.GetDouble(pdo);
            if (pdr.Status == PromptStatus.OK)
            {
                return pdr.Value;
            }
            return 1.0;
        }

        /// <summary>
        /// 插入块并应用参数
        /// </summary>
        private void InsertBlocksWithParameters(Database db, Editor ed, Point3d startPoint,
                                              double spacing, double rotation, double scale)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord modelSpace = tr.GetObject(
                    bt[BlockTableRecord.ModelSpace],
                    OpenMode.ForWrite
                ) as BlockTableRecord;

                ObjectId blockId = bt[BLOCK_NAME];

                for (int i = 0; i < 10; i++)
                {
                    Point3d insertPoint = new Point3d(
                        startPoint.X + i * spacing,
                        startPoint.Y,
                        startPoint.Z
                    );

                    BlockReference blockRef = new BlockReference(insertPoint, blockId);

                    // 应用旋转
                    blockRef.Rotation = rotation;

                    // 应用缩放
                    blockRef.ScaleFactors = new Scale3d(scale, scale, scale);

                    // 可选:交替旋转
                    if (i % 2 == 1)
                    {
                        blockRef.Rotation += 15 * Math.PI / 180;
                    }

                    modelSpace.AppendEntity(blockRef);
                    tr.AddNewlyCreatedDBObject(blockRef, true);

                    // 添加编号
                    AddBlockNumber(tr, modelSpace, insertPoint, i);
                }

                tr.Commit();
            }
        }
    }
}
相关推荐
不穿格子的程序员5 小时前
Redis篇4——Redis深度剖析:内存淘汰策略与缓存的三大“天坑”
数据库·redis·缓存·雪崩·内存淘汰策略
YJlio6 小时前
BgInfo 学习笔记(11.5):多种输出方式(壁纸 / 剪贴板 / 文件)与“更新其他桌面”实战
笔记·学习·c#
Zhen (Evan) Wang6 小时前
.NET 6 API使用Serilog APM
c#·.net
hans汉斯6 小时前
【软件工程与应用】平移置换搬迁系统设计与实现
数据库·人工智能·系统架构·软件工程·汉斯出版社·软件工程与应用
gugugu.6 小时前
Redis List类型完全指南:从原理到实战应用
数据库·redis·list
Hello.Reader6 小时前
Flink SQL ALTER 语句在线演进 Table/View/Function/Catalog/Model
数据库·sql·flink
白学还是没白学?6 小时前
exec db docker from A to B
数据库·docker·容器
似霰6 小时前
传统 Hal 开发笔记5 —— 添加硬件访问服务
android·framework·hal