07-图元操作与几何处理教程

第七章:图元操作与几何处理教程

7.1 图元基础操作

7.1.1 创建基本图元

AutoCAD中的图元(Entity)是数据库中的图形对象。IFoxCAD简化了图元的创建和操作。

创建点

using var tr = new DBTrans();

// 创建点(DBPoint)
var point = new DBPoint(new Point3d(50, 50, 0));
point.Layer = "点图层";
tr.CurrentSpace.AddEntity(point);

创建直线

using var tr = new DBTrans();

// 创建直线
var line = new Line(
    new Point3d(0, 0, 0),    // 起点
    new Point3d(100, 100, 0) // 终点
);
line.Color = Color.FromColorIndex(ColorMethod.ByAci, 1);
tr.CurrentSpace.AddEntity(line);

创建圆

using var tr = new DBTrans();

// 创建圆
var circle = new Circle(
    new Point3d(50, 50, 0),  // 圆心
    Vector3d.ZAxis,           // 法向量
    25                        // 半径
);
tr.CurrentSpace.AddEntity(circle);

创建圆弧

using var tr = new DBTrans();

// 通过圆心、半径和角度创建圆弧
var arc = new Arc(
    new Point3d(50, 50, 0),  // 圆心
    25,                       // 半径
    0,                        // 起始角度(弧度)
    Math.PI                   // 终止角度(弧度)
);
tr.CurrentSpace.AddEntity(arc);

// 三点圆弧
Point3d pt1 = new Point3d(0, 0, 0);
Point3d pt2 = new Point3d(50, 50, 0);
Point3d pt3 = new Point3d(100, 0, 0);

var circArc = new CircularArc3d(pt1, pt2, pt3);
var arc2 = new Arc(
    circArc.Center,
    circArc.Normal,
    circArc.Radius,
    circArc.StartAngle,
    circArc.EndAngle
);
tr.CurrentSpace.AddEntity(arc2);

创建椭圆

using var tr = new DBTrans();

// 创建椭圆
var ellipse = new Ellipse(
    new Point3d(50, 50, 0),        // 中心点
    Vector3d.ZAxis,                 // 法向量
    new Vector3d(50, 0, 0),        // 主轴向量
    0.5,                            // 长短轴比
    0,                              // 起始角度
    Math.PI * 2                     // 终止角度
);
tr.CurrentSpace.AddEntity(ellipse);

7.1.2 创建多段线

轻量多段线(Polyline)

using var tr = new DBTrans();

// 创建矩形
var pline = new Polyline();
pline.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0);
pline.AddVertexAt(1, new Point2d(100, 0), 0, 0, 0);
pline.AddVertexAt(2, new Point2d(100, 50), 0, 0, 0);
pline.AddVertexAt(3, new Point2d(0, 50), 0, 0, 0);
pline.Closed = true;

tr.CurrentSpace.AddEntity(pline);

带圆弧的多段线

using var tr = new DBTrans();

// 创建带圆角的矩形
var pline = new Polyline();

// 凸度(bulge)计算:bulge = tan(角度/4)
// 90度圆弧的凸度约为 0.414

double bulge = Math.Tan(Math.PI / 8); // 45度/4

pline.AddVertexAt(0, new Point2d(10, 0), 0, 0, 0);
pline.AddVertexAt(1, new Point2d(90, 0), bulge, 0, 0);
pline.AddVertexAt(2, new Point2d(100, 10), 0, 0, 0);
pline.AddVertexAt(3, new Point2d(100, 40), bulge, 0, 0);
pline.AddVertexAt(4, new Point2d(90, 50), 0, 0, 0);
pline.AddVertexAt(5, new Point2d(10, 50), bulge, 0, 0);
pline.AddVertexAt(6, new Point2d(0, 40), 0, 0, 0);
pline.AddVertexAt(7, new Point2d(0, 10), bulge, 0, 0);
pline.Closed = true;

tr.CurrentSpace.AddEntity(pline);

变宽度多段线

using var tr = new DBTrans();

// 创建箭头形状
var pline = new Polyline();

pline.AddVertexAt(0, new Point2d(0, 5), 0, 5, 5);    // 尾部
pline.AddVertexAt(1, new Point2d(70, 5), 0, 5, 15);  // 中段
pline.AddVertexAt(2, new Point2d(70, 15), 0, 15, 0); // 箭头底
pline.AddVertexAt(3, new Point2d(100, 0), 0, 0, 0);  // 箭尖

tr.CurrentSpace.AddEntity(pline);

7.1.3 创建样条曲线

using var tr = new DBTrans();

// 通过控制点创建样条曲线
var points = new Point3dCollection
{
    new Point3d(0, 0, 0),
    new Point3d(25, 50, 0),
    new Point3d(50, 0, 0),
    new Point3d(75, 50, 0),
    new Point3d(100, 0, 0)
};

var spline = new Spline(
    points,
    3,      // 阶数
    0       // 拟合公差
);

tr.CurrentSpace.AddEntity(spline);

7.1.4 创建填充

using var tr = new DBTrans();

// 创建边界多段线
var boundary = new Polyline();
boundary.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0);
boundary.AddVertexAt(1, new Point2d(100, 0), 0, 0, 0);
boundary.AddVertexAt(2, new Point2d(100, 100), 0, 0, 0);
boundary.AddVertexAt(3, new Point2d(0, 100), 0, 0, 0);
boundary.Closed = true;

ObjectId boundaryId = tr.CurrentSpace.AddEntity(boundary);

// 创建填充
var hatch = new Hatch();
hatch.SetHatchPattern(HatchPatternType.PreDefined, "ANSI31");
hatch.Associative = true;
hatch.AppendLoop(HatchLoopTypes.Default, new ObjectIdCollection { boundaryId });
hatch.EvaluateHatch(true);

tr.CurrentSpace.AddEntity(hatch);

7.2 文字与标注

7.2.1 创建单行文字

using var tr = new DBTrans();

// 创建单行文字
var text = new DBText();
text.Position = new Point3d(0, 0, 0);
text.TextString = "Hello IFoxCAD";
text.Height = 5;
text.WidthFactor = 0.8;
text.Rotation = 0; // 弧度

tr.CurrentSpace.AddEntity(text);

// 居中对齐的文字
var centerText = new DBText();
centerText.TextString = "居中文字";
centerText.Height = 10;
centerText.HorizontalMode = TextHorizontalMode.TextCenter;
centerText.VerticalMode = TextVerticalMode.TextVerticalMid;
centerText.AlignmentPoint = new Point3d(50, 50, 0);

tr.CurrentSpace.AddEntity(centerText);

7.2.2 创建多行文字

using var tr = new DBTrans();

// 创建多行文字
var mtext = new MText();
mtext.Location = new Point3d(0, 100, 0);
mtext.TextHeight = 5;
mtext.Width = 100;
mtext.Contents = "这是多行文字\\P第二行\\P第三行";
mtext.Attachment = AttachmentPoint.TopLeft;

tr.CurrentSpace.AddEntity(mtext);

// 带格式的多行文字
var formattedMtext = new MText();
formattedMtext.Location = new Point3d(0, 50, 0);
formattedMtext.TextHeight = 5;
formattedMtext.Width = 200;
formattedMtext.Contents = @"{\C1;红色文字}\\P{\C3;绿色文字}\\P{\fSimHei|b1;粗体黑体}";

tr.CurrentSpace.AddEntity(formattedMtext);

7.2.3 创建标注

线性标注

using var tr = new DBTrans();

// 创建线性标注
var dim = new AlignedDimension(
    new Point3d(0, 0, 0),      // 第一点
    new Point3d(100, 0, 0),    // 第二点
    new Point3d(50, 20, 0),    // 标注线位置
    "",                         // 标注文字(空表示自动)
    tr.Database.DimStyleTableId
);

tr.CurrentSpace.AddEntity(dim);

// 水平标注
var hDim = new RotatedDimension(
    0,                          // 旋转角度
    new Point3d(0, 0, 0),
    new Point3d(100, 50, 0),
    new Point3d(50, 70, 0),
    "",
    tr.Database.DimStyleTableId
);

tr.CurrentSpace.AddEntity(hDim);

角度标注

using var tr = new DBTrans();

// 创建角度标注
var angDim = new Point3AngularDimension(
    new Point3d(50, 50, 0),    // 圆心/顶点
    new Point3d(100, 50, 0),   // 第一条线上的点
    new Point3d(50, 100, 0),   // 第二条线上的点
    new Point3d(80, 80, 0),    // 标注弧位置
    "",
    tr.Database.DimStyleTableId
);

tr.CurrentSpace.AddEntity(angDim);

半径和直径标注

using var tr = new DBTrans();

// 创建圆
var circle = new Circle(new Point3d(50, 50, 0), Vector3d.ZAxis, 30);
ObjectId circleId = tr.CurrentSpace.AddEntity(circle);

// 半径标注
var radDim = new RadialDimension(
    new Point3d(50, 50, 0),    // 圆心
    new Point3d(80, 50, 0),    // 圆上点
    15,                         // 引线长度
    "",
    tr.Database.DimStyleTableId
);

tr.CurrentSpace.AddEntity(radDim);

// 直径标注
var diaDim = new DiametricDimension(
    new Point3d(20, 50, 0),    // 弦点1
    new Point3d(80, 50, 0),    // 弦点2
    20,                         // 引线长度
    "",
    tr.Database.DimStyleTableId
);

tr.CurrentSpace.AddEntity(diaDim);

7.3 块操作

7.3.1 创建块定义

using var tr = new DBTrans();

// 创建块定义
tr.BlockTable.Add("MySymbol", btr =>
{
    // 创建块内容
    var circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10);
    var line1 = new Line(new Point3d(-10, 0, 0), new Point3d(10, 0, 0));
    var line2 = new Line(new Point3d(0, -10, 0), new Point3d(0, 10, 0));
    
    // 添加图元到块定义
    btr.AppendEntity(circle);
    tr.Transaction.AddNewlyCreatedDBObject(circle, true);
    btr.AppendEntity(line1);
    tr.Transaction.AddNewlyCreatedDBObject(line1, true);
    btr.AppendEntity(line2);
    tr.Transaction.AddNewlyCreatedDBObject(line2, true);
});

tr.Editor?.WriteMessage("\n块定义创建完成!");

7.3.2 创建带属性的块

using var tr = new DBTrans();

// 创建带属性的块
tr.BlockTable.Add("LabelBlock", btr =>
{
    // 创建块图形
    var rect = new Polyline();
    rect.AddVertexAt(0, new Point2d(-50, -10), 0, 0, 0);
    rect.AddVertexAt(1, new Point2d(50, -10), 0, 0, 0);
    rect.AddVertexAt(2, new Point2d(50, 10), 0, 0, 0);
    rect.AddVertexAt(3, new Point2d(-50, 10), 0, 0, 0);
    rect.Closed = true;
    
    btr.AppendEntity(rect);
    tr.Transaction.AddNewlyCreatedDBObject(rect, true);
    
    // 创建属性定义
    var attDef = new AttributeDefinition();
    attDef.Position = new Point3d(0, 0, 0);
    attDef.Tag = "NAME";
    attDef.Prompt = "输入名称";
    attDef.TextString = "默认名称";
    attDef.Height = 5;
    attDef.HorizontalMode = TextHorizontalMode.TextCenter;
    attDef.VerticalMode = TextVerticalMode.TextVerticalMid;
    attDef.AlignmentPoint = new Point3d(0, 0, 0);
    
    btr.AppendEntity(attDef);
    tr.Transaction.AddNewlyCreatedDBObject(attDef, true);
});

7.3.3 插入块参照

using var tr = new DBTrans();

// 插入简单块参照
ObjectId blockId = tr.BlockTable["MySymbol"];
if (!blockId.IsNull)
{
    var blockRef = new BlockReference(new Point3d(100, 100, 0), blockId);
    blockRef.ScaleFactors = new Scale3d(2, 2, 2);
    blockRef.Rotation = Math.PI / 4; // 45度
    
    tr.CurrentSpace.AddEntity(blockRef);
}

7.3.4 插入带属性的块参照

using var tr = new DBTrans();

ObjectId blockId = tr.BlockTable["LabelBlock"];
if (!blockId.IsNull)
{
    // 创建块参照
    var blockRef = new BlockReference(new Point3d(200, 100, 0), blockId);
    ObjectId blockRefId = tr.CurrentSpace.AddEntity(blockRef);
    
    // 获取块定义以添加属性
    var btr = tr.BlockTable.GetRecord(blockId);
    if (btr != null && btr.HasAttributeDefinitions)
    {
        foreach (ObjectId id in btr)
        {
            var attDef = tr.GetObject<AttributeDefinition>(id);
            if (attDef != null && !attDef.Constant)
            {
                // 创建属性参照
                var attRef = new AttributeReference();
                attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
                attRef.TextString = "设备名称"; // 设置属性值
                
                using (blockRef.ForWrite())
                {
                    blockRef.AttributeCollection.AppendAttribute(attRef);
                }
                tr.Transaction.AddNewlyCreatedDBObject(attRef, true);
            }
        }
    }
}

7.3.5 修改块参照属性

using var tr = new DBTrans();

// 选择块参照
var filter = OpFilter.Build(e => e.Dxf(0) == "INSERT" & e.Dxf(2) == "LabelBlock");
var result = tr.Editor?.GetSelection(filter);

if (result?.Status == PromptStatus.OK)
{
    foreach (SelectedObject obj in result.Value)
    {
        if (obj == null) continue;
        
        var blockRef = tr.GetObject<BlockReference>(obj.ObjectId, OpenMode.ForWrite);
        if (blockRef == null) continue;
        
        // 遍历属性
        foreach (ObjectId attId in blockRef.AttributeCollection)
        {
            var attRef = tr.GetObject<AttributeReference>(attId, OpenMode.ForWrite);
            if (attRef != null && attRef.Tag == "NAME")
            {
                attRef.TextString = "新的名称";
            }
        }
    }
}

7.4 图元变换

7.4.1 变换矩阵基础

变换矩阵是进行图元几何变换的核心工具。

// 平移矩阵
Matrix3d moveMatrix = Matrix3d.Displacement(new Vector3d(100, 50, 0));

// 旋转矩阵(绕Z轴)
Matrix3d rotateMatrix = Matrix3d.Rotation(
    Math.PI / 4,        // 角度(弧度)
    Vector3d.ZAxis,     // 旋转轴
    Point3d.Origin      // 旋转中心
);

// 缩放矩阵
Matrix3d scaleMatrix = Matrix3d.Scaling(
    2.0,                // 缩放比例
    Point3d.Origin      // 缩放中心
);

// 镜像矩阵
Matrix3d mirrorMatrix = Matrix3d.Mirroring(
    new Line3d(Point3d.Origin, new Point3d(0, 100, 0))
);

// 组合变换
Matrix3d combinedMatrix = scaleMatrix * rotateMatrix * moveMatrix;

7.4.2 应用变换

using var tr = new DBTrans();

// 选择图元
var result = tr.Editor?.GetSelection();
if (result?.Status != PromptStatus.OK) return;

// 获取变换参数
var baseResult = tr.Editor?.GetPoint("\n指定基点:");
if (baseResult?.Status != PromptStatus.OK) return;
Point3d basePoint = baseResult.Value;

var targetResult = tr.Editor?.GetPoint("\n指定目标点:", basePoint);
if (targetResult?.Status != PromptStatus.OK) return;
Point3d targetPoint = targetResult.Value;

// 创建变换矩阵
Vector3d displacement = targetPoint - basePoint;
Matrix3d matrix = Matrix3d.Displacement(displacement);

// 应用变换
foreach (SelectedObject obj in result.Value)
{
    if (obj == null) continue;
    
    var ent = tr.GetObject<Entity>(obj.ObjectId, OpenMode.ForWrite);
    if (ent != null)
    {
        ent.TransformBy(matrix);
    }
}

tr.Editor?.WriteMessage($"\n已移动 {result.Value.Count} 个图元");

7.4.3 复制与变换

using var tr = new DBTrans();

// 选择图元
var result = tr.Editor?.GetEntity("\n选择要阵列的图元:");
if (result?.Status != PromptStatus.OK) return;

var ent = tr.GetObject<Entity>(result.ObjectId);
if (ent == null) return;

// 矩形阵列
int rows = 3;
int cols = 4;
double rowSpacing = 50;
double colSpacing = 80;

for (int i = 0; i < rows; i++)
{
    for (int j = 0; j < cols; j++)
    {
        if (i == 0 && j == 0) continue; // 跳过原始位置
        
        var clone = ent.Clone() as Entity;
        if (clone != null)
        {
            Matrix3d matrix = Matrix3d.Displacement(
                new Vector3d(j * colSpacing, i * rowSpacing, 0));
            clone.TransformBy(matrix);
            
            tr.CurrentSpace.AddEntity(clone);
        }
    }
}

tr.Editor?.WriteMessage($"\n已创建 {rows * cols - 1} 个副本");

7.4.4 环形阵列

using var tr = new DBTrans();

var result = tr.Editor?.GetEntity("\n选择要阵列的图元:");
if (result?.Status != PromptStatus.OK) return;

var ent = tr.GetObject<Entity>(result.ObjectId);
if (ent == null) return;

// 获取圆心
var centerResult = tr.Editor?.GetPoint("\n指定圆心:");
if (centerResult?.Status != PromptStatus.OK) return;
Point3d center = centerResult.Value;

// 阵列参数
int count = 8;
double totalAngle = Math.PI * 2; // 360度
double angleStep = totalAngle / count;

for (int i = 1; i < count; i++)
{
    var clone = ent.Clone() as Entity;
    if (clone != null)
    {
        Matrix3d matrix = Matrix3d.Rotation(
            angleStep * i,
            Vector3d.ZAxis,
            center);
        clone.TransformBy(matrix);
        
        tr.CurrentSpace.AddEntity(clone);
    }
}

tr.Editor?.WriteMessage($"\n已创建 {count - 1} 个副本");

7.5 几何计算

7.5.1 点与曲线

using var tr = new DBTrans();

// 创建曲线
var pline = new Polyline();
pline.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0);
pline.AddVertexAt(1, new Point2d(100, 0), 0, 0, 0);
pline.AddVertexAt(2, new Point2d(100, 100), 0, 0, 0);
tr.CurrentSpace.AddEntity(pline);

// 曲线长度
double length = pline.Length;
tr.Editor?.WriteMessage($"\n曲线长度:{length:F2}");

// 获取曲线上的点
Point3d midPoint = pline.GetPointAtDist(length / 2);
tr.Editor?.WriteMessage($"\n中点:{midPoint}");

// 获取点到曲线的最近点
Point3d testPoint = new Point3d(50, 50, 0);
Point3d closestPoint = pline.GetClosestPointTo(testPoint, false);
tr.Editor?.WriteMessage($"\n最近点:{closestPoint}");

// 获取曲线上某点的切线方向
Vector3d tangent = pline.GetFirstDerivative(closestPoint);
tr.Editor?.WriteMessage($"\n切线方向:{tangent.GetNormal()}");

7.5.2 曲线求交

using var tr = new DBTrans();

// 创建两条曲线
var line1 = new Line(new Point3d(0, 0, 0), new Point3d(100, 100, 0));
var line2 = new Line(new Point3d(0, 100, 0), new Point3d(100, 0, 0));

tr.CurrentSpace.AddEntity(line1);
tr.CurrentSpace.AddEntity(line2);

// 计算交点
Point3dCollection intersections = new Point3dCollection();
line1.IntersectWith(line2, Intersect.OnBothOperands, intersections, IntPtr.Zero, IntPtr.Zero);

tr.Editor?.WriteMessage($"\n找到 {intersections.Count} 个交点");
foreach (Point3d pt in intersections)
{
    tr.Editor?.WriteMessage($"\n  交点:{pt}");
    
    // 在交点处创建标记
    var point = new DBPoint(pt);
    tr.CurrentSpace.AddEntity(point);
}

7.5.3 区域计算

using var tr = new DBTrans();

// 创建闭合多段线
var pline = new Polyline();
pline.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0);
pline.AddVertexAt(1, new Point2d(100, 0), 0, 0, 0);
pline.AddVertexAt(2, new Point2d(100, 50), 0, 0, 0);
pline.AddVertexAt(3, new Point2d(0, 50), 0, 0, 0);
pline.Closed = true;

tr.CurrentSpace.AddEntity(pline);

// 计算面积
double area = pline.Area;
tr.Editor?.WriteMessage($"\n面积:{area:F2}");

// 使用区域计算更复杂的形状
DBObjectCollection curves = new DBObjectCollection { pline };
var regions = Region.CreateFromCurves(curves);

if (regions.Count > 0)
{
    var region = regions[0] as Region;
    if (region != null)
    {
        // 获取区域属性
        var props = region.AreaProperties;
        tr.Editor?.WriteMessage($"\n区域面积:{region.Area:F2}");
        tr.Editor?.WriteMessage($"\n周长:{region.Perimeter:F2}");
    }
}

7.5.4 边界计算

using var tr = new DBTrans();

// 选择多个图元
var result = tr.Editor?.GetSelection();
if (result?.Status != PromptStatus.OK) return;

// 计算边界框
Extents3d? totalExtents = null;

foreach (SelectedObject obj in result.Value)
{
    if (obj == null) continue;
    
    var ent = tr.GetObject<Entity>(obj.ObjectId);
    if (ent == null) continue;
    
    try
    {
        var entExtents = ent.GeometricExtents;
        if (totalExtents == null)
        {
            totalExtents = entExtents;
        }
        else
        {
            totalExtents?.AddExtents(entExtents);
        }
    }
    catch
    {
        // 某些图元可能没有几何范围
    }
}

if (totalExtents != null)
{
    tr.Editor?.WriteMessage($"\n边界框:");
    tr.Editor?.WriteMessage($"\n  最小点:{totalExtents?.MinPoint}");
    tr.Editor?.WriteMessage($"\n  最大点:{totalExtents?.MaxPoint}");
    
    // 创建边界框多段线
    var min = totalExtents!.Value.MinPoint;
    var max = totalExtents!.Value.MaxPoint;
    
    var boundingBox = new Polyline();
    boundingBox.AddVertexAt(0, new Point2d(min.X, min.Y), 0, 0, 0);
    boundingBox.AddVertexAt(1, new Point2d(max.X, min.Y), 0, 0, 0);
    boundingBox.AddVertexAt(2, new Point2d(max.X, max.Y), 0, 0, 0);
    boundingBox.AddVertexAt(3, new Point2d(min.X, max.Y), 0, 0, 0);
    boundingBox.Closed = true;
    boundingBox.Color = Color.FromColorIndex(ColorMethod.ByAci, 1);
    
    tr.CurrentSpace.AddEntity(boundingBox);
}

7.6 本章小结

本章我们深入学习了图元操作与几何处理:

  1. 基本图元创建:掌握了点、线、圆、弧、椭圆等基本图元的创建
  2. 多段线操作:学习了创建各种类型的多段线,包括带圆弧和变宽度的
  3. 文字与标注:掌握了单行文字、多行文字和各种标注的创建
  4. 块操作:学习了块定义创建、块参照插入和属性操作
  5. 图元变换:掌握了变换矩阵的使用和各种变换操作
  6. 几何计算:学习了曲线计算、求交、区域计算和边界计算

这些是CAD二次开发中最常用的图元操作技术。下一章我们将通过实战案例来综合应用所学知识。

posted @ 2025-11-27 12:00  我才是银古  阅读(0)  评论(0)    收藏  举报