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();
            }
        }
    }
}
相关推荐
尋有緣13 分钟前
力扣1355-活动参与者
大数据·数据库·leetcode·oracle·数据库开发
萧曵 丶33 分钟前
MySQL三大日志系统浅谈
数据库·sql·mysql
煎蛋学姐38 分钟前
SSM校园兼职招聘系统x6u36(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·企业管理·ssm 框架·校园兼职招聘系统
stevenzqzq1 小时前
ctrl +B和ctrl+shift +B的区别
android·ide·android studio
似霰2 小时前
HIDL Hal 开发笔记5----Same-Process HALs 实例分析
android·framework·hal
ChineHe2 小时前
Redis基础篇004_Redis Pipeline流水线详解
数据库·redis·缓存
robotx2 小时前
安卓16 设置壁纸中应用网格,有两个5X5的选项
android
故事不长丨2 小时前
C#字典(Dictionary)全面解析:从基础用法到实战优化
开发语言·c#·wpf·哈希算法·字典·dictionary·键值对
西柚补习生2 小时前
通用 PWM 原理基础教学
数据库·mongodb
Yyuanyuxin2 小时前
保姆级学习开发安卓手机软件(三)--安装模拟机并开始简单的进入开发
android·学习