本文章开发环境:
在上一篇文章中介绍了最基本的CAD开发的概念,工具,和写了一个Hello World
程序,在这一篇文章中将做一些真正有趣,看得见的东西。我们将在CAD的图形区域中画上一些图形。废话不多说,直接进入正题。
首先一个我们需要知道的是在CAD图形空间中画图,实际上就是往图形数据库中添加图元。
在autoCAD中图形数据库占有非常重要的位置,我们经常会跟图形数据库打交道。如果我们需要往图形空间中画图的话,我们需要做如下的事情:
BlockTable
)ModelSpace
就是我们画图所需要打开的)上面出现了块表
和块表记录
的概念,那么具体什么是块表
和块表记录
。在图形数据库中其实并不只有块表,也有层表,文字样式表,标注样式表,线形表等。例如对于层表
来说它允许有多个层表记录
,那么层表记录
其实就是每个图层而已。对标注样式表
也一样,标注样式表记录
就是具体的每个标注样式。
所以表和表记录的关系就是在表中会有多个表记录,每个表记录就是一个具体的东西。
下图就是autoCAD
中的数据库的简图
下面我们以添加一条直线为例,说明如何在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; }
,返回或设置文字对齐方式上面的Position
和AlignmentPoint
属性一般设置为同一个点就可以了(之前测试过如果不同会报错,目前还不清楚具体原因)。
还有上面列出的属性中共有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文档。
下一篇文章将为大家介绍一些常用的几何对象来进行辅助计算。
该篇文章是根据本人已有的知识来写,如有不对或者更好的方式可以告诉我。
本人的公众号,欢迎有兴趣的关注下