C# CAD二次开发之基本图形

autoCAD二次开发之基本图形(二)

文章目录

  • autoCAD二次开发之基本图形(二)
    • 图形数据库
    • 直线
      • 进一步封装
    • 圆和圆弧
    • 多段线
      • 凸度
    • 面域
    • 文字
    • 总结

本文章基础知识:

  • C# 基础
  • 面向对象编程
  • 事务概念

本文章开发环境:

  • autoCAD 2016
  • VS2017
  • .NET 4.5

在上一篇文章中介绍了最基本的CAD开发的概念,工具,和写了一个Hello World程序,在这一篇文章中将做一些真正有趣,看得见的东西。我们将在CAD的图形区域中画上一些图形。废话不多说,直接进入正题。

图形数据库

首先一个我们需要知道的是在CAD图形空间中画图,实际上就是往图形数据库中添加图元。

在autoCAD中图形数据库占有非常重要的位置,我们经常会跟图形数据库打交道。如果我们需要往图形空间中画图的话,我们需要做如下的事情:

  • 获取当前文档的图形数据库
  • 打开图形数据库中的块表(BlockTable)
  • 打开块表中的块表记录(默认情况下有三个块表记录,其中ModelSpace就是我们画图所需要打开的)
  • 然后把图元添加到块表记录中

上面出现了块表块表记录的概念,那么具体什么是块表块表记录。在图形数据库中其实并不只有块表,也有层表,文字样式表,标注样式表,线形表等。例如对于层表来说它允许有多个层表记录,那么层表记录其实就是每个图层而已。对标注样式表也一样,标注样式表记录就是具体的每个标注样式。

所以表和表记录的关系就是在表中会有多个表记录,每个表记录就是一个具体的东西。

下图就是autoCAD中的数据库的简图

C# CAD二次开发之基本图形_第1张图片

下面我们以添加一条直线为例,说明如何在CAD中添加图形对象。

直线

autoCAD中的直线对象为Line,它有一个无参构造函数和一个带起点,终点的构造函数。

  • Line()
  • Line(Point3d pointer1, Point3d pointer2)

下面是Line对象的一些常用属性:

  • public double Length { get; },获取直线的长度
  • public override Point3d EndPoint { get; set; },获取或设置线段的端点
  • public override Point3d StartPoint { get; set; },获取或设置线段的起点

下面我们就使用带起点终点的构造函数创建直线:

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace CADDemo
{
    public class AddEntity
    {
        [CommandMethod("AddLine")]
        public void AddLine()
        {
            //获取当前文档图形数据库
            Database database = HostApplicationServices.WorkingDatabase;

            //起点
            Point3d startPoint = new Point3d(0, 0, 0);
            //终点
            Point3d endPoint = new Point3d(100, 100, 0);
            //创建直线对象
            Line line = new Line(startPoint,endPoint);
            
            //使用事务打开数据库的块表和块表记录并且添加直线并提交。
            using (Transaction tr = database.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(database.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                btr.AppendEntity(line);
                tr.AddNewlyCreatedDBObject(line, true);
                tr.Commit();
            }
        }
    }
}

可以看到首先我们是获取了一个数据库对象,然后创建了起点和终点(Point3d结构),然后用起点和终点创建了直线对象。

using语句中打开了一个图形数据库的事务对象,通过事务对象来进行读写数据库,在事务中一般调用事务对象中的GetObject()方法来读取数据库中的对象。GetObject()有两个参数,其中第一个参数是一个ObjectId对象,ObjectId代表autoCAD中的任何对象,图形,图层,样式,数据库表和表记录等都有一个ObjectId来唯一标识。第二个参数表示采用何种方式打开对象。例如上面代码第一处调用GetObject()方法的地方,第一个参数为Database对象的属性BlockTableId返回块表id,第二个参数为ForRead,就是说以只读的方式打开一个块表。第二处调用GetObject()的地方表示以写的方式打开块表中的ModelSpace块表记录。

随后我们调用AppendEntity()来往块表记录中添加刚刚我们创建的直线对象,然后调用tr.AddNewlyCreatedDBObject()来通知数据库有更新。最后我们调用Commit()来提交事务。

注意:Point3d对象是结构,而不是类。

注意:往块表记录中添加图形后必须要调用Commit()更新才会真正被写入数据库。这也是基本的数据库事务概念。

进一步封装

其实从上面的例子中我们可以看到创建一条直线的代码其实只有3行,而其他的都是一些千遍一律的打开块表,块表记录,添加图形,提交。所以我们可以把这些多而重复的代码进一步封装而不必每次都写这么长的代码。

我们可以通过拓展方法的方式来进行封装,这也是很多的一些书籍教材所用的方式,也是最方便使用的方式。

public static ObjectId AddEntity(this Database database,Entity entity)
{
    ObjectId objectId = new ObjectId();
    using (Transaction tr = database.TransactionManager.StartTransaction())
    {
        BlockTable bt = (BlockTable)tr.GetObject(database.BlockTableId, OpenMode.ForRead);
        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
        objectId = btr.AppendEntity(entity);
        tr.AddNewlyCreatedDBObject(entity, true);
        tr.Commit();
    }
    return objectId;
}

上面的代码就为Database对象添加了一个名为AddEntity的拓展方法。其中AddEntity方法接收一个Entity类型的参数,Entity是所有图形对象的父类。

添加了上面的拓展方法后,画直线的代码就简化成:

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace CADDemo
{
    public class AddEntity
    {
        [CommandMethod("AddLine")]
        public void AddLine()
        {
            Database database = HostApplicationServices.WorkingDatabase;

            Point3d startPoint = new Point3d(0, 0, 0);
            Point3d endPoint = new Point3d(100, 100, 0);
            Line line = new Line(startPoint,endPoint);

            database.AddEntity(line);
        }
    }
}

在以后的文章我们也将继续沿用该拓展方法来添加图形对象。

圆和圆弧

注意:对于下面所有的角度单位都是使用弧度制

首先我们来看一下圆,在autoCAD中圆对象为Circle类型,该对象的构造函数有两个重载版本

  • Circle()
  • Circle(Point3d center, Vector3d normal, double radius)

第一个构造函数创建一个圆心为原点,半径为0,法向量为(0,0,1)的圆。第二个构造函数通过指定圆心,法向量,半径来创建圆。其中对于一般的X,Y平面法向量为(0,0,1)

我们还可以利用几何对象来通过三点创建圆和圆弧,关于几何对象我们将在下一篇文章中讲解。

其中Circle类型的一些常用属性如下:

  • public Point3d Center { get; set; },获取或设置圆的圆心
  • public double Radius { get; set; },获取或设置圆的半径

下面代码创建一个圆心在原点,半径为100的圆:

[CommandMethod("AddCircle")]
public void AddCircle()
{
    Database database = HostApplicationServices.WorkingDatabase;

    Point3d center = new Point3d();
    double radius = 100;

    Circle circle = new Circle(center, new Vector3d(0, 0, 1), radius);

    database.AddEntity(circle);
}

圆弧对象为Arc类型,该对象的构造函数有三个重载版本

  • Arc()
  • Arc(Point3d center, double radius, double startAngle, double endAngle)
  • Arc(Point3d center, Vector3d normal, double radius, double startAngle, double endAngle)

其中第一个构造函数为无参的默认构造函数。第二个构造函数通过指定圆心,半径,起始角度,端点角度来创建圆弧对象。第三个构造函数只比第二个构造函数多了一个平面法向量参数。一般我们使用第二个构造函数就可以了。

Arc类型的一些常用属性如下:

  • public double TotalAngle { get; },获取圆弧的总角度
  • public double EndAngle { get; set; },获取或设置端点角度
  • public double StartAngle { get; set; },获取或设置起点角度
  • public double Radius { get; set; },获取或设置圆弧半径
  • public Point3d Center { get; set; },获取或设置圆弧圆心

下面的代码创建一个圆心在原点,半径为100,被坐标系截取在第一象限的圆弧:

[CommandMethod("AddArc")]
public void AddArc()
{
    Database database = HostApplicationServices.WorkingDatabase;

    Point3d center = new Point3d();
    double radius = 100;
    double startAngle = 0;
    double endAngle = System.Math.PI / 2;

    Arc arc = new Arc(center, radius, startAngle, endAngle);

    database.AddEntity(arc);
}

圆弧的起始和端点角度有一个需要注意的地方,autoCAD将从起始角度逆时针画到端点角度。举上面画的第一象限圆弧为例,如果把起始角度换成pi/2,把端点角度换成0,那么画出来的圆弧将会从Y轴正半轴逆时针画到X轴正半轴,跨越2,3,4象限,刚好跟上面的例子互补。

多段线

autoCAD中多段线对象为Polyline类型,该对象的构造函数有两个重载版本

  • Polyline()
  • public Polyline(int vertices)

其中第一个是无参构造函数,第二个构造函数通过指定一个固定的顶点数来创建多段线。下面我们都是使用第一个无参构造函数来创建多段线。

下面列出Polyline类型的一些常用属性:

  • public int NumberOfVertices { get; },获取多段线的顶点数
  • public double Length { get; },获取多段线的长度
  • public bool Closed { get; set; },获取多段线是否闭合

下面我们来说一下Polyline类型的一些常用的方法,其中AddVertexAt(int index, Point2d pt, double bulge, double startWidth, double endWidth)方法为多段线添加顶点,其中第一个参数是顶点的索引,索引从零开始,也就是说索引为0就是第一个顶点,为1就是第二个顶点。方法的第二个参数是顶点的点坐标,第三个参数是该顶点的凸度(下面将说明凸度的概念),第四和第五个参数是起点和终点宽度一般为0就好了。

方法GetPoint2dAt(int index)用来返回在指定索引处的点坐标;GetBulgeAt(int index)方法返回在指定索引处的凸度;RemoveVertexAt(int index)方法移除指定索引的顶点;

我们用多段线画一个正方形的代码如下:

[CommandMethod("AddPolyline")]
public void AddPolyline()
{
    Database database = HostApplicationServices.WorkingDatabase;

    Point2d p1 = new Point2d(0, 0);
    Point2d p2 = new Point2d(0, 100);
    Point2d p3 = new Point2d(100, 100);
    Point2d p4 = new Point2d(100, 0);

    Polyline polyline = new Polyline();
    polyline.AddVertexAt(0, p1, 0, 0, 0);
    polyline.AddVertexAt(1, p2, 0, 0, 0);
    polyline.AddVertexAt(2, p3, 0, 0, 0);
    polyline.AddVertexAt(3, p4, 0, 0, 0);
    polyline.AddVertexAt(4, p1, 0, 0, 0);

    database.AddEntity(polyline);
}

上面代码调用Polyline类型的默认构造函数后通过调用AddVertexAt方法来往多段线添加顶点,其中顶点之间是直线连接(因为凸度都为0)。

凸度

好了,那么如果多段线需要有圆弧的话需要怎么画?关键就在AddVertexAt的第三个参数(凸度)。凸度定义为该顶点和下一个顶点的圆弧的起始和端点角度差的四分一正切值,即tan(△angle/4))),其中△angle就是圆弧的起始和端点角度差。

其中凸度有正负之分,正的凸度值表示从该顶点画出的圆弧在多段线的前进方向的右侧,负的凸度值表示从该顶点画出的圆弧在多段线前进方向的左侧。

如果我们在上面用多段线画的正方形的上边画成一个半圆,我们可以作如下修改。

[CommandMethod("AddPolyline")]
public void AddPolyline()
{
    Database database = HostApplicationServices.WorkingDatabase;

    Point2d p1 = new Point2d(0, 0);
    Point2d p2 = new Point2d(0, 100);
    Point2d p3 = new Point2d(100, 100);
    Point2d p4 = new Point2d(100, 0);

    Polyline polyline = new Polyline();
    polyline.AddVertexAt(0, p1, 0, 0, 0);
    //画从p2到p3的半圆
    polyline.AddVertexAt(1, p2, Math.Tan((0-Math.PI)/4), 0, 0);
    polyline.AddVertexAt(2, p3, 0, 0, 0);
    polyline.AddVertexAt(3, p4, 0, 0, 0);
    polyline.AddVertexAt(4, p1, 0, 0, 0);

    database.AddEntity(polyline);
}

可以看到上面只在添加第二个顶点的AddVertexAt函数中的第三个参数改为Math.Tan((0-Math.PI)/4),也就是我们要求半圆的起始角度和端点角度的差值的四分之一,然后再对其求tan正切值,这样来求出凸度。注意:从上面的式子中求出的凸度值为负数,所以我们的半圆应该是在正方形外部。如果凸度值为正的话半圆会在正方形的内部。

面域

面域是一个封闭的的区域,我们可以利用面域来求不规则图形的面积,周长,而且还可以利用面域来跟其他面域作布尔运算。

面域在autoCAD中用Region类型来表示,Region类型的创建跟上面的对象有点不一样的,它是通过Region类的一个静态函数public static DBObjectCollection CreateFromCurves(DBObjectCollection curveSegments)来创建。

可以看到该方法的参数是一个DBObjectCollection对象,它是一个表示cad对象的集合,该类实现IList接口,所以我们可以当它是集合来使用就好了,在这里就是用集合中的对象来创建闭合的面域。方法的返回值也是一个DBObjectCollection,因为如果参数中的对象可以围成多个闭合的面域那么方法也会一一返回。

Region类型常用的属性如下:

  • public virtual double Area { get; },返回面域的面积
  • public virtual double Perimeter { get; },返回面域的周长

下面的代码实例创建一个正方形的面域:

[CommandMethod("AddRegion")]
public void AddRegion()
{
    Database database = HostApplicationServices.WorkingDatabase;

    Point3d p1 = new Point3d(0, 0, 0);
    Point3d p2 = new Point3d(0, 100, 0);
    Point3d p3 = new Point3d(100, 100, 0);
    Point3d p4 = new Point3d(100, 0, 0);

    Line line1 = new Line(p1, p2);
    Line line2 = new Line(p2, p3);
    Line line3 = new Line(p3, p4);
    Line line4 = new Line(p4, p1);

    DBObjectCollection collection = new DBObjectCollection()
    {
        line1,
        line2,
        line3,
        line4
    };
    Region region = (Region)Region.CreateFromCurves(collection)[0];

    database.AddEntity(region);
}

在上面的事例中,因为由collection围成的正方形面域只可能有一个,所以在下面调用CreateFromCurves时我们就直接返回第一个元素并且强制转换为Region类型。

面域还可以进行布尔运算,在面域之间求并,交和差,下面就是一个例子:

region.BooleanOperation(BooleanOperationType.BoolSubtract, region2);

上面的例子就是对region2作布尔减运算,要作布尔运算可以调用Region类型的BooleanOperation方法。其中第一个参数是布尔运算的类型枚举,该枚举共有三个值分别为BoolUnite(并),BoolIntersect(交),BoolSubtract(差)。第二个参数为要作布尔运算的另一个面域。运算的结果赋给调用该方法的面域。

文字

文字在autoCAD中用类型DBText来表示,该类型只有一个无参构造函数Arc()

DBText常用的属性如下:

  • public string TextString { get; set; },返回或设置文字显示的字符串
  • public Point3d Position { get; set; },返回或设置文字的显示位置
  • public Point3d AlignmentPoint { get; set; },返回或设置文字的对齐点位置
  • public double Height { get; set; },返回或设置文字高度
  • public double Rotation { get; set; },返回或设置文字的旋转角度
  • public TextHorizontalMode HorizontalMode { get; set; },返回或设置文字的水平对齐方式
  • public TextVerticalMode VerticalMode { get; set; },返回或设置文字的垂直对齐方式
  • public AttachmentPoint Justify { get; set; },返回或设置文字对齐方式

上面的PositionAlignmentPoint属性一般设置为同一个点就可以了(之前测试过如果不同会报错,目前还不清楚具体原因)。

还有上面列出的属性中共有3种对齐方式,其中水平对齐和垂直对齐应该都能理解,这里就说一下最后一个Justify。可以看到该属性接受一个AttachmentPoint类型,该类型是一个枚举类型,因为该类型的枚举太多所以我这列出两个来进行举例。其中AttachmentPoint.BottomRight表示把文字的右下角对齐到AlignmentPoint属性设置的点;AttachmentPoint.MiddleCenter则表示把文字的中心对齐到AlignmentPoint属性设置的点。

下面的例子说明如何创建一个简单的文字对象:

[CommandMethod("AddText")]
public void AddText()
{
    Database database = HostApplicationServices.WorkingDatabase;

    DBText text = new DBText();
    text.TextString = "Hello World";
    text.Position = new Point3d(0,0,0);
    text.AlignmentPoint = text.Position;
    text.Height = 150;
    text.HorizontalMode = TextHorizontalMode.TextCenter;
    text.VerticalMode = TextVerticalMode.TextVerticalMid;
    text.Justify = AttachmentPoint.MiddleCenter;

    database.AddEntity(text);
}

总结

上面就是一些常用的图形对象,更多的其他图形对象可以查看AutoCAD的官方文档,里面有完整的API文档。

下一篇文章将为大家介绍一些常用的几何对象来进行辅助计算。

该篇文章是根据本人已有的知识来写,如有不对或者更好的方式可以告诉我。

本人的公众号,欢迎有兴趣的关注下

C# CAD二次开发之基本图形_第2张图片

你可能感兴趣的:(CAD二次开发,CAD,CAD二次开发,二次开发,C#)