目 录

  • 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二次开发 python二次开发CAD选择方法_SelectionSets



  官方二次开发帮助文档的获取方式详见博文: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 , 便可查看各种数据类型的转化。



python二次开发 python二次开发CAD选择方法_Python_02


PyWin32帮助文档的获取


python二次开发 python二次开发CAD选择方法_python二次开发_03


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 ,便可得到官方的权威解释,操作如下:



python二次开发 python二次开发CAD选择方法_AutoCAD_04


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



python二次开发 python二次开发CAD选择方法_二次开发_05



  以下代码实现将用户选择的图元的颜色更改为红色。



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 同学的大力支持,特此感谢!