目 录
- Blog Links
- 一、前言
- 二、连接CAD的方式
- 2.1. ProgID
- 三、数据转换
- 四、创建测试图元
- 五、创建选择集
- 六、常规选择
- 6.1. 屏幕拾取
- 6.2. 选择过定点图元
- 6.3. 多边形框选
- 6.4. 全选
- 七、快速选择
- 7.1. 语法
- 7.2. DXF组码
- 7.3. 实例
- 八、GetEntity
- 九、致谢
- 十、尾声
- 十、参考文献
一、前言
用户要对已有的一些对象进行删除、复制、移动等编辑操作,都需要选中被操作的对象。选择对象或对操作对象进行筛选的过程,称为构造选择集。选择对象可以只选择一个对象,也可以同时选择多个对象。AutoCAD 中常用构造选择集有直接拾取、窗口、窗交、栏选等多种方式。[1]
本文简要介绍在 CAD 二次开发过程中几种常用选择对象即构造选择集的方法。
二、连接CAD的方式
为了保证代码的顺利运行,本文采用 win32com 库连接 CAD,具体代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
=============================
Author:DalNur
Email: liyang@alu.hit.edu.cn
=============================
'''
import win32com.client
import pythoncom
acad = win32com.client.Dispatch("AutoCAD.Application.19")
# AutoCAD.Application.19为 ProgID
doc = acad.ActiveDocument
doc.Utility.Prompt("Hello AutoCAD\n")
mp = doc.ModelSpace
print(doc.Name)
2.1. ProgID
根据 CAD 版本的不同, ProgID 可能发生变化,部分版本 CAD 的 ProgID 如下:
AutoCAD 版本 | ProgID |
2010 | AutoCAD.Application.18 |
2014 | AutoCAD.Application.19 |
常见版本 CAD 的 ProgID 详见博文: autocad application 版本 。
其余版本 CAD 的 ProgID 在官方二次开发帮助文档中查看,具体查找位置如下图所示。
官方二次开发帮助文档的获取方式详见博文:Python pyautocad库 使用简介 前沿部分。
三、数据转换
说明:本人非计算机专业出身,文中某些表述可能不严谨甚至错误,还请各位见谅。
Python 中的数据类型较少,且对数据本身的要求也较为宽松,如一个列表中的各个元素可以分别属于不同的数据类型,这虽然有利于降低程序的编写难度,但也对 CAD 的二次开发产生了一些不必要的麻烦。
在 CAD 二次开发过程中,很多函数/方法的参数要求输入的数据类型为 Variant (array of objects) ,但在 Python 中似乎又没有哪一种数据类型与之直接相对应,若采用 list 代替 Variant,那么程序无法顺利执行,报错为 “ 对象数组无效 ”。因此,需要某种转换方式,将Python中定义的变量转换为能够被CAD识别的数据类型 Variant 。
VARIANT 结构体主要是使用在 COM(组件对象模型)中用于传递参数使用,它的存在主要是为了保持一个在 COM 参数传递方法的统一性,它几乎包含了所有普通常用类型的数据类型的传递,如整型,浮点型,布尔型等,以及相应类型的指针类型,如整型指针。[3]
部分类型与变量对应关系如下表:
Member name | Description |
VT_EMPTY | Indicates that a value was not specified. |
VT_R8 | Indicates a double value. |
VT_DISPATCH | Indicates an IDispatch pointer. |
另外,NumPy arrays can be passed as VARIANT arrays arguments. The array is converted to a SAFEARRAY according to its type. [4] ( 此为 comptypes 库帮助文档原文,本人对计算机了解有限,为了不曲解原文,此处不做翻译),部分对应关系如下:
NumPy type | VARIANT type |
int32, int, intc, int_ | VT_I4 |
uint32, uint, uintc | VT_UI4 |
float64, float_ | VT_R8 |
本文用到的数据转化函数代码如下:
def vtpnt(x, y, z=0):
"""坐标点转化为浮点数"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, (x, y, z))
def vtobj(obj):
"""转化为对象数组"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_DISPATCH, obj)
def vtFloat(list):
"""列表转化为浮点数"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, list)
def vtInt(list):
"""列表转化为整数"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_I2, list)
def vtVariant(list):
"""列表转化为变体"""
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_VARIANT, list)
其他数据类型的转化方式可查询 PyWin32 的官方帮助文档,它的获取方式如下:首先确保你已经成功安装了 pywin32 模块,然后在搜索神器 Everything 的搜索栏中输入 PyWin32.chm,便可得到其所在的路径,打开文件 PyWin32.chm,在搜索栏中输入 pythoncom.VT_ARRAY , 便可查看各种数据类型的转化。
PyWin32帮助文档的获取
VARIANT的查询
四、创建测试图元
[pnt1, pnt2, pnt3, pnt4, pnt5, pnt6] = [vtpnt(-40, -40), vtpnt(500, 500), vtpnt(300, 200),
vtpnt(600, 200), vtpnt(700, 200), vtpnt(100, 0)]
LineObj = mp.AddLine(pnt1, pnt2)
CircleObj = mp.AddCircle(pnt3, 100)
ArcObj = mp.AddArc(pnt4, 50, 0, 1.57)
EllObj = mp.AddEllipse(pnt5, pnt6, 0.5)
五、创建选择集
创建名称为 SS1 的选择集。
try:
doc.SelectionSets.Item("SS1").Delete()
except:
print("Delete selection failed")
slt = doc.SelectionSets.Add("SS1")
六、常规选择
6.1. 屏幕拾取
slt.SelectOnScreen()
print("请在屏幕拾取图元,以Enter键结束")
obj = slt[0]
print(obj.ObjectID)
print(slt)
6.2. 选择过定点图元
pnt = APoint(0, 0)
slt.SelectAtPoint(pnt)
obj = slt[0]
print(obj.StartPoint) # 当不止一个图元过点pnt时,slt中的元素也不止一个。
6.3. 多边形框选
多边形由给定各点依次连直线形成,最终实现该多边形区域内的全选。
pnts = [-50, -50, 0, -50, 550, 0, 550, 550, 0, 550, -50, 0, -50, -50, 0]
pnts=vtFloat(pnts)
slt.SelectByPolygon(6, pnts) # acSelectionSetWindowPolygon = 6
obj = slt[0]
print(obj.ObjectID)
obj = slt[1]
print(obj.ObjectID)
6.4. 全选
slt.Select(5) # acSelectionSetAll = 5
obj = slt[0]
print(obj.layer)
七、快速选择
7.1. 语法
• object.Select(Mode, Point1, Point2, FilterType, FilterData)
object:SelectionSet. The object this method applies to 。
Mode:选择模式,AcSelect enum,具体含义下表。
Point1:3维坐标点。
Point2:3维坐标点。
FilterType:A DXF group code specifying the type of filter to use 。
FilterData:The value to filter on 。
Mode | enum | Description |
acSelectionSetWindow | 0 | Selects all objects completely inside a rectangular area whose corners are defined by Point1 and Point2. |
acSelectionSetCrossing | 1 | Selects objects within and crossing a rectangular area whose corners are defined by Point1 and Point2. |
acSelectionSetPrevious | 3 | Selects the most recent selection set. This mode is ignored if you switch between paper space and model space and attempt to use the selection set. |
acSelectionSetLast | 4 | Selects the most recently created visible objects. |
acSelectionSetAll | 5 | Selects all objects. |
7.2. DXF组码
此外,在二次开发帮助文档 ActiveX Developer’s Guide 中,搜索 DXF ,便可得到官方的权威解释,操作如下:
7.3. 实例
选择 0 图层上所有半径大于 5 的圆并删除,代码如下:
filterType = [0, -4, 40, 8] # 定义过滤类型
filterData = ["Circle", ">=", 5, "0"] # 设置过滤参数
filterType = vtInt(filterType) # 数据类型转化
filterData = vtVariant(filterData) # 数据类型转化
slt.Select(5, 0, 0, filterType, filterData) # 实现过滤
obj = slt[0]
print(obj.Diameter)
slt.Erase() # 删除符合条件的所有圆
八、GetEntity
以下代码实现将用户选择的图元的颜色更改为红色。
print("请在屏幕中鼠标左键点选图元,未选中则报错!") # try...except处理报错
rtnObj = doc.Utility.GetEntity() # 返回对象
print(rtnObj)
print("所选图元的ID:", rtnObj[0].ObjectID)
print("鼠标单击处的坐标:", rtnObj[1])
sltObject = doc.ObjectIdToObject(rtnObj[0].ObjectID) # 图元ID转化为对应的图元
clr = doc.Application.GetInterfaceObject("AutoCAD.AcCmColor.19")
clr.SetRGB(255, 0, 0) # 创建红色
sltObject.TrueColor = clr # 指定颜色
doc.Application.Update()
九、致谢
选择集功能的顺利实现离不开 ke1078 同学的大力支持,特此感谢!