因为做Revit的二次开发多一点,拿到Teigha的时候还有点懵,看完样例还是觉得一知半解的,原因还是对于AutoCad的底层逻辑不是很明白,包括视图与布局之间的层级关系,块与视图的关系等等,看代码会有些累。
下面通过一个案例说一下昨天一天整理的知识点。
- teigha本身是ODA下面的Cad分项,有需要的可以去ODA官网下载或是从CSDN的链接下载。刚申请完会有一段时间的试用期,这个时间可以和ODA邮件沟通。
- Teigha本身沿用AutoCad的逻辑,如果和我一样有Revit或是其他Autodesk家的开发经验有一些还是比较容易理解的,比如事务(transation)
- CAD中模型视图(Model Space),布局1(Paper_Space),布局2(Paper_Space),各种块(Block)<其实各种块在CAD中看作一个视图,我们在遍历模型视图内构件时,块的类定义为’BlockReference’从名称上可以看出这是一个引用>,昨天我一直在尝试在BlockReference中获取快内部构件信息,但是一直没有头绪,后来打开CAD点击-编辑块功能,发现他与视图这类是并列层级,后台打印BlockTable发现在其中
- 还是建议使用Teigha开发前了解一下AutoCad的API,这样能够更快速的入门
下面代码是我查询一个cad文件中Geometry信息的案例,包括从模型视图提取数据与从块中提取信息。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Teigha.DatabaseServices;
using Teigha.Runtime;
namespace RdFileLayer
{
class Program
{
static void Main(string[] args)
{
using (Services serv = new Services())
{
var path = @"C:\Users\Desktop\二次开发\Teigha_cad_test.dwg";
using (Database db = new Database(false,false))
{
db.ReadDwgFile(path,FileShare.Read,false,null);
using (LayerTable pTable = (LayerTable)db.LayerTableId.GetObject(OpenMode.ForRead))
{
foreach (ObjectId id in pTable)
{
using (var tr = db.TransactionManager.StartTransaction())
{
LayerTableRecord record = (LayerTableRecord) tr.GetObject(id, OpenMode.ForRead);
Console.WriteLine("-------");
Console.WriteLine("<" + record.GetRXClass().Name + ">");
Console.WriteLine(record.Name);
Console.WriteLine("In Use" + record.IsUsed);
Console.WriteLine("Color" + record.Color);
Console.WriteLine("LineWeight" + record.LineWeight);
}
}
}
using (var tr = db.TransactionManager.StartTransaction())
{
using (var bTable = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead))
{
foreach (ObjectId id in bTable)
{
var record = tr.GetObject(id, OpenMode.ForRead) as BlockTableRecord;
int count = 0;
// var objectId = bTable[BlockTableRecord.ModelSpace];
// BlockTableRecord record =
// (BlockTableRecord)tr.GetObject(objectId, OpenMode.ForRead);
Console.WriteLine("DB_BlockTableRecord Type is : "+record.Name);
if (record.Name == BlockTableRecord.ModelSpace|| record.Name == "Block")
{
Console.WriteLine("----------------" + record.Name + "----------------");
foreach (ObjectId id1 in record)
{
var entity = (Entity)tr.GetObject(id1, OpenMode.ForRead, false, true);
Console.WriteLine("Entity Type MutiType is : ");
Console.WriteLine("DB_Type : " + entity.GetType());
if (entity is Line)
{
var item = entity as Line;
Console.WriteLine("Line - " + count);
Console.WriteLine("Line 0" + item.StartPoint);
Console.WriteLine("Line 1" + item.EndPoint);
Console.WriteLine("Line Type Name" + item.Layer);
}
else if (entity is Polyline)
{
var item = entity as Polyline;
var allNums = item.NumberOfVertices;
Console.WriteLine("DB_PolyLine : ");
for (int i = 0; i < allNums; i++)
{
var subLine = item.GetLineSegmentAt(i);
Console.WriteLine("SubLine - " + i);
Console.WriteLine("SubLine 0" + subLine.StartPoint);
Console.WriteLine("SubLine 1" + subLine.EndPoint);
Console.WriteLine("SubLine Type Name" + item.Layer);
}
Console.WriteLine("DB_PolyLine Coordinates : " + "DB_PolyLine count is : " + item.NumberOfVertices);
for (int i = 0; i < item.NumberOfVertices; i++)
{
var vertex = item.GetPoint3dAt(i);
Console.WriteLine("SubVertex Coordinate index : " + i + " Location : " + vertex);
}
}
else if (entity is Circle cItem)
{
Console.WriteLine("DB_Circle original : " + cItem.Center);
Console.WriteLine("DB_Circle Radius is : " + cItem.Radius);
}
else if (entity is DBText item)
{
Console.WriteLine("DB_Text is :" + item.TextString);
Console.WriteLine("DB_Text Position : "+ item.Position);
}
else if (entity is MText mItem)
{
Console.WriteLine("DB_MText value is : " + mItem.Text);
Console.WriteLine("DB_MText position is : " + mItem.Location);
}
count++;
}
}
}
}
}
}
}
Console.Read();
}
}
}
08.25 嵌套快提取,一个车库中有时会将整个车库图层打成一个块车位单独一个块,当我们想提取车位块中的信息时,需要提取嵌套块。但是当我们提取嵌套块时坐标会发生变化变为块内坐标,所以需要进行坐标转换,才能得到真实坐标,所以提取所有数据信息最好还是从Model-Space开始 遍历,获得块参照进入后对坐标进行修正才可以,有几层嵌套可能会需要添加几层,这一点我没有测试。
code:
else if (entity is BlockReference bItem)
{
var angle = (bItem.Rotation * 180) / Math.PI;
Console.WriteLine("DB_BlockReference : " + bItem.Name);
Console.WriteLine("DB_BlockReference Location ; " + bItem.Position);
Console.WriteLine("DB_BlockReference Rotation : " + angle);
if (angle - 0.00 < 0.001)
{
var subTable =
bItem.Database.BlockTableId.GetObject(OpenMode.ForRead) as
BlockTable;
var fakeTable = (BlockTableRecord) tr.GetObject(bItem.BlockTableRecord,
OpenMode.ForRead);
Console.WriteLine("Fake_Table type name is : " + fakeTable.Name);
Console.WriteLine("Fake_Table type Location is : " + fakeTable.Origin);
foreach (ObjectId objectId in fakeTable)
{
var subTableRecord =
tr.GetObject(objectId, OpenMode.ForRead) as Entity;
Console.WriteLine("DB_Entity Type is : "+subTableRecord.GetType());
Console.WriteLine("SubRecord PolyLines Vertex is : ");
if (subTableRecord is Polyline pl)
{
for (int i = 0; i < pl.NumberOfVertices; i++)
{
var nPoint = new Point2d(pl.GetPoint2dAt(i).X+bItem.Position.X,pl.GetPoint2dAt(i).Y+bItem.Position.Y);
Console.WriteLine("polyLines vertex index is : " + nPoint);
}
}
// if (subTableRecord.Name.ToLower() == BlockTabl
// foreach (var id2 in subTableRecord)
// {eRecord.ModelSpace.ToLower())
// {
// var subEntity = tr.GetObject(id2, OpenMode.ForRead, false,
// false) as Entity;
// Console.WriteLine("DB_Entity Type is : "+entity.GetType());
// }
// }
}
}
}
- 所有的操作都需要在Services,Database,Transation…这类命令中,今天尝试将查询命令单独创建一个dll发现teigha报错,使用时最好还是在一个类中完成查询,先记录一下,能够编写成接口再更新接口的代码
08.26
- 在数据运算时,为了降低耦合度,将数据提出另外创建一个类,但是依旧是报错,后台看是空指针问题,估计还是无法将在结构体内部的数据提到其他模块处理,现在自己创建了一个Point,Vector,Line类进行数据处理,如果还需要其他的则需要创建更多的类型。
- 第一阶段宣布失败,我的最终目标是实现Revit中建筑图纸停车位的翻模,最后发现最后一个拦路虎是目前设计师的块标准,因为停车位具有方向,所以就算我们将块内部的偏移点算出也无法快速确认停车位的基点与方向。因为我已经实现Revit中直接解析CADLinkType的Geometry的停车位翻模,想用CAD替换结果发现时间损耗与计算机损耗都比较大,还是沿用原有方案进行翻模吧。QAQ。下一个阶段想实现翻模功能,可能里面对于平行线段与几何位置算法权重比较大,有空写了再分享一下。