天天看點

python:ActiveX一、application 版本二、基本操作三、資料轉換四、建立選擇集五、對象常用方法六、建立新圖形

文章目錄

  • 一、application 版本
  • 二、基本操作
  • 三、資料轉換
  • 四、建立選擇集
  • 五、對象常用方法
    • 1、對象相交
    • 2、對象上色
    • 3、圖層對象
  • 六、建立新圖形

一、application 版本

AutoCAD産品名 版本号 ProgID
AutoCAD 2004 R16 AutoCAD.Application.16
AutoCAD 2005 R16.1 AutoCAD.Application.16.1
AutoCAD 2006 R16.2 AutoCAD.Application.16.2
AutoCAD 2007 R17 AutoCAD.Application.17
AutoCAD 2008 R17.1 AutoCAD.Application.17.1
AutoCAD 2009 R17.2 AutoCAD.Application.17.2
AutoCAD 2010 R18 AutoCAD.Application.18
AutoCAD 2011 R18.1 AutoCAD.Application.18.1
AutoCAD 2014 R19.1 AutoCAD.Application.19.1
AutoCAD 2015 R20 AutoCAD.Application.20
AutoCAD 2016 R20.1 AutoCAD.Application.20.1
AutoCAD 2017 R21 AutoCAD.Application.21
AutoCAD 2018 R22 AutoCAD.Application.22
AutoCAD 2019 R23 AutoCAD.Application.23
使用者最後一次使用的CAD AutoCAD.Application
CAD類
import pythoncom
import win32com.client as win32

# todo:cad基本操作類
class Cad():
    def __init__(self):
        self.version = self.version()
        self.cad = win32.Dispatch('AutoCAD.Application.%s' % self.version)  # 20.1
        self.color = self.cad.GetInterfaceObject('AutoCAD.AcCmColor.%s' % self.version)
        self.doc = self.cad.ActiveDocument
        self.docs = self.cad.Documents
        self.msp = self.doc.ModelSpace
        self.utl = self.doc.Utility
    def vtpnt(self, x, y, z=0):
        """坐标點轉化為浮點數"""
        return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, (x, y, z))
    def vtobj(self, obj):
        """轉化為對象數組"""
        return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_DISPATCH, obj)
    def vtfloat(self, lst):
        """清單轉化為浮點數"""
        return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, lst)
    def vtInt(self, list):
        """清單轉化為整數"""
        return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_I2, list)
    def vtVariant(self, list):
        """清單轉化為變體"""
        return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_VARIANT, list)

    # todo:全部範圍選擇
    def select_all(self, name, filterType, filterData):
        # cad = win32.Dispatch("AutoCAD.Application")
        # doc = cad.ActiveDocument
        try:
            ssget1 = self.doc.SelectionSets.Add("%s" % name)  # 若無選擇集,嘗試新增"SS1"選擇集
        except BaseException:
            ssget1 = self.doc.SelectionSets("%s" % name)  # 如果"SS1"選擇集已存在,就以它作為我們的選擇集
            ssget1.Clear()  # 清空"SS1"選擇集的内容

        # filterType = [2, 8]  # 定義過濾類型
        # filterData = ["FWSX", "FWSX"]  # 設定過濾參數
        filterType = self.vtInt(filterType)  # 資料類型轉換
        filterData = self.vtVariant(filterData)  # 資料類型轉換

        ssget1.Select(5, 0, 0, filterType, filterData)  # 實作過濾選擇

        return ssget1
    # todo:部分範圍選擇
    def select_little(self, name, filterType, filterData, coordinates):
        """選擇模式1,選擇矩形框相交的對象"""
        try:
            ssget1 = self.doc.SelectionSets.Add("%s" % name)
        except BaseException:
            ssget1 = self.doc.SelectionSets("%s" % name)
            ssget1.Clear()
        # filterType = [2, 8]  # 定義過濾類型
        # filterData = ["FWSX", "FWSX"]  # 設定過濾參數
        filterType = self.vtInt(filterType)  # 資料類型轉化
        filterData = self.vtVariant(filterData)  # 資料類型轉化

        ssget1.Select(1, self.vtpnt(coordinates[0] - 30, coordinates[1] + 30),
                      self.vtpnt(coordinates[0] + 30, coordinates[1] - 30), filterType, filterData)  # 實作過濾

        return ssget1
    # todo:利用多邊形選擇
    def select_poly(self, name, mode, lst, filterType, filterData):
        try:
            ssget1 = self.doc.SelectionSets.Add("%s" % name)  # 若無選擇集,嘗試新增"SS1"選擇集
        except BaseException:
            ssget1 = self.doc.SelectionSets("%s" % name)  # 如果"SS1"選擇集已存在,就以它作為我們的選擇集
            ssget1.Clear()  # 清空"SS1"選擇集的内容

        # filterType = [2, 8]  # 定義過濾類型
        # filterData = ["FWSX", "FWSX"]  # 設定過濾參數
        filterType = self.vtInt(filterType)  # 資料類型轉換
        filterData = self.vtVariant(filterData)  # 資料類型轉換

        ssget1.SelectByPolygon(mode, self.vtfloat(lst), filterType, filterData)  # 實作過濾選擇

        return ssget1

    # todo:擷取對象交集坐标
    def get_union_points(self, objlist):
        try:
            # # 判斷多邊形是否相交
            # rel = objlist[0].IntersectWith(objlist[1], 0)
            # if len(rel) == 0:
            #     return None
            # 多邊形形成面域
            self.msp.AddRegion(self.vtobj(objlist))
            # 查找生成的面域
            region_union = self.select_all('ss2', [8, 0], ['0', 'region'])
            # 将所有面域并成一個面域
            while len(region_union)>1:
                # 面域進行并集
                region_union[0].Boolean(0, region_union[1])
                # 查找生成的面域
                region_union = self.select_all('ss2', [8, 0], ['0', 'region'])
            # 炸開合并後的這一整個面域(如果隻有一個面域則傳回多條直線,如果有多個面域,則傳回每個獨立的面域)
            line = region_union[0].Explode()
            region_union[0].Delete() # 删除已炸開面域
            # 判斷炸開面域後是否還存在面域
            region_union = self.select_all('ss2', [8, 0], ['0', 'region'])
            points_lst = []
            if len(region_union) > 0: # 被炸的是多個面域,傳回的是每個獨立面域
                for i in region_union: # 周遊每個面域,轉換為坐标清單
                    lines = i.Explode()
                    i.Delete()  # 删除已炸開面域
                    points_lst.append(self.union2points(lines))
            else: # 被炸的是一個面域,傳回的是直線段
                points_lst.append(self.union2points(line))

            return points_lst
        except Exception as e:
            print('get_union_points出錯:' + str(e))
    # todo:炸開後的直線合并成多邊形,傳回坐标
    def union2points(self, lines):
        """
        :param lines: 多個直線段對象
        :return: 多邊形坐标清單[x,y,x1,y1...xn,yn]
        """
        # 擷取炸開後的直線坐标并删除直線
        point_list = []
        for i in lines:
            point_list.append([i.StartPoint, i.EndPoint])
            i.Delete()

        # 處理坐标
        lst = [point_list[0]]
        point_list.pop(0)
        for _ in range(len(lines) - 1):
            for i in point_list:
                if lst[-1][-1] == i[0]:
                    lst.append(i)
                    point_list.remove(i)
                    break
                elif lst[-1][-1] == i[1]:
                    lst.append([i[1], i[0]])
                    point_list.remove(i)
                    break

        result_lst = []
        for i in lst:
            result_lst.extend([i[0][0], i[0][1]])
        # result_lst.append(result_lst[0])
        # 删除多餘節點
        result_lst = self.delete_point(result_lst)
        # 坐标序列改為逆時針
        result_lst = self.coordinate_sorting(result_lst, -1)

        return result_lst

    # todo:坐标序列轉換
    def coordinate_sorting(self, lst, flag):
        # z小于0說明原坐标清單為順時針,z大于0說明原坐标清單為逆時針,flag正為順,flag負為逆
        # lst = [431699.3549,3473066.7616,431715.2278,3473083.8972,431732.0926,3473073.7823,431716.9179,3473057.0712]

        # 坐标轉為元組
        point_lst = []
        for i in range(0, len(lst), 2):
            point_lst.append((lst[i], lst[i + 1]))

        point_lst.append(point_lst[0])
        point_lst.insert(0, point_lst[-2])

        # print(point_lst)
        # 查找最右上角的坐标
        max_point = (0, 0)
        for i in range(1, len(point_lst) - 1):
            if point_lst[i][0] > max_point[0]:
                max_point = point_lst[i]
            elif point_lst[i][0] == max_point[0]:
                if point_lst[i][1] >= max_point[1]:
                    max_point = point_lst[i]

        # print(max_point)
        # 記錄max坐标的索引
        index_num = point_lst[1:-1].index(max_point) + 1
        # 傳回需要的三個點
        p1 = point_lst[index_num - 1]
        p2 = point_lst[index_num]
        p3 = point_lst[index_num + 1]
        # print(p1, p2, p3)
        x1 = p2[0] - p1[0]
        y1 = p2[1] - p1[1]
        x2 = p3[0] - p2[0]
        y2 = p3[1] - p2[1]
        z = x1 * y2 - x2 * y1  # z<0,順時針
        if z < 0 and flag < 0:
            # print('逆時針')
            point_lst.reverse()
        elif z > 0 and flag > 0:
            point_lst.reverse()
        new_lst = []
        for i in range(1, len(point_lst) - 1):
            new_lst.extend(point_lst[i][:])
        # print(new_lst)

        return new_lst
    # todo:計算兩點方位角
    def degree(self, x, y, x1, y1):
        try:
            dx = x1 - x  # 最長線段的x坐标差
            dy = y1 - y  # 最長線段的y坐标差
            dy = dy + m.pow(10, -10)
            degree = m.pi * (1 - np.sign(dy) / 2) - m.atan(dx / dy)  # 計算最長線段的方位角

            return degree
        except Exception as e:
            print('degree出錯:' + str(e))
    # todo:删除多餘節點
    def delete_point(self, lst):
        try:
            # 添加起點坐标
            lst.extend(lst[:2])
            # 清單轉為元組
            new_lst = []
            for i in range(0, len(lst), 2):
                new_lst.append((lst[i], lst[i + 1]))
            # 開頭插入元素
            new_lst.insert(0, new_lst[-2])
            delete = []
            # 查找多餘節點
            for i in range(1, len(new_lst) - 1):
                d1 = round(self.degree(new_lst[i - 1][0], new_lst[i - 1][1], new_lst[i][0], new_lst[i][1]), 4)
                d2 = round(self.degree(new_lst[i][0], new_lst[i][1], new_lst[i + 1][0], new_lst[i + 1][1]), 4)

                if d1 == d2:
                    delete.append((new_lst[i]))

            # 元組清單删除頭尾
            del new_lst[0]
            del new_lst[-1]

            # 删除多餘節點
            for i in delete:
                while i in new_lst:
                    new_lst.remove(i)
            # # 末尾添加起點坐标
            # new_lst.append(new_lst[0])
            lst = []
            # 還原坐标格式
            for i in new_lst:
                lst.extend([i[0], i[1]])

            return lst
        except Exception as e:
            print('delete_point出錯:' + str(e))
    # todo:cad版本查詢
    def version(self):
        applist = ['16','16.1','16.2','17','17.1','17.2','18','18.1','19.1','20','20.1','21','22','23']
        for i in applist:
            try:
                win32.Dispatch('AutoCAD.Application.%s' % i)  # 20.1
                return i
            except Exception:
                pass
        return None


if __name__ == '__main__':
    cad = Cad()
    cad.cad.ZoomExtents()
    
    ssget1 = cad.select_all('ss1', [2, 8], ["FWSX", "FWSX"])

    insertionPoint = (434817.9258476031, 3476325.6359382486, 0.0)
    ssget2 = cad.select_little('ss2', [0, 0], ['lwpolyline', 'lwpolyline'], insertionPoint)

    new_lst = [434813.7128951931, 3476307.5265556867, 0,
               434826.12550053425, 3476313.3009239333, 0,
               434827.8843840688, 3476309.5200207722, 0,
               434815.4717787276, 3476303.7456525257, 0]
    ssget3 = cad.select_poly('ss3', 6, new_lst, [8, 0], ['面積插入', 'TEXT'])
           

二、基本操作

import pythoncom
import win32com.client as win32

cad = win32.Dispatch("AutoCAD.Application")
doc = cad.ActiveDocument
msp = doc.ModelSpace
color = cad.GetInterfaceObject("AutoCAD.AcCmColor.17")
           

三、資料轉換

def vtpnt(x, y, z=0):
    """坐标點轉化為浮點數"""
    return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, (x, y, z))

def vtobj(obj):
    """轉化為對象數組"""
    return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_DISPATCH, obj)

def vtfloat(lst):
    """清單轉化為浮點數"""
    return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, lst)

def vtInt(list):
    """清單轉化為整數"""
    return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_I2, list)

def vtVariant(list):
    """清單轉化為變體"""
    return win32.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_VARIANT, list)
           

四、建立選擇集

try:
    ssget1 = doc.SelectionSets.Add("SS1")  # 若無選擇集,嘗試新增"SS1"選擇集
except BaseException:
    ssget1 = doc.SelectionSets("SS1")  # 如果"SS1"選擇集已存在,就以它作為我們的選擇集
    ssget1.Clear()  # 清空"SS1"選擇集的内容

filterType = [2, 8]  # 定義過濾類型
filterData = ["FWSX", "FWSX"]  # 設定過濾參數
filterType = vtInt(filterType)  # 資料類型轉換
filterData = vtVariant(filterData)  # 資料類型轉換

ssget1.Select(5, 0, 0, filterType, filterData)  # 實作過濾選擇
           

文法:

  • object:選擇集
  • Mode:選擇模式
模式 說明
選擇完全在矩形區域内的所有對象,矩形對角由 Point1 和 Point2 定義
1 選擇在矩形區域内和與矩形區域相交的對象,矩形對角由 Point1 和 Point2 定義
3 選擇最近的選擇集。如果使用者在圖紙空間和模型空間之間進行切換并試圖使用選擇集,該模式将被忽略
4 選擇最近生成的可見對象
5 選擇所有對象
  • Point1:3維坐标點
  • Point2:3維坐标點
  • FilterType:過濾類型(DXF組碼)
DXF代碼 過濾器類型
對象類型(字元串),如“Line”、“Circle”、“Arc”等等
2 對象類型(字元串),命名對象的表(給定)名稱
8 圖層名稱(字元串),如“Layer0”
60 對象的可見性(整數),0可見,1不可見
62 顔色号(整數),0到256的數字索引值,0代表随塊,256代表随層,負值代表圖層關閉
67 模型/圖紙空間訓示(整數),使用0或忽略為模型空間,1為圖紙空間
  • FilterData:過濾參數

其他對象選擇方法:

方法 說明
Addltem 添加一個或多個對象到指定的選擇集。
Select 選擇對象并将其放入活動的選擇集中。使用者可選擇所有對象、矩形窗選區域或矩形框選區域的對象、多邊形窗選區域或多邊形框選區域的對象、栅選的對象、最近建立的對象、最近選擇集的對象。
SelectAtPoint 選擇通過給定點的對象并将其放入活動的選擇集中。
SelectByPolygon 通過栅選的對象并将其放入活動的選擇集中。
SelectOnScreen 提示使用者從螢幕中拾取對象并将其添加到活動的選擇中。

五、對象常用方法

1、對象相交

rel = obj1.IntersectWith(obj2, 0)
print(rel)

(1218.1517971803642, 625.2198412500425, 0.0, 1144.7959481512107, 361.0629323395639, 0.0)
           

2、對象上色

# 擷取顔色接口
color = cad.GetInterfaceObject('AutoCAD.AcCmColor.17')
# 設定顔色
color.ColorIndex = 1
color.SetRGB(0, 255, 255)
# 給對象上色
obj.TrueColor = color
           
python:ActiveX一、application 版本二、基本操作三、資料轉換四、建立選擇集五、對象常用方法六、建立新圖形

3、圖層對象

# 添加圖層
layer1 = doc.Layers.Add("戶主名稱")
# 設定目前圖層
doc.ActiveLayer = layer1
# 指定圖層的狀态
layer1.LayerOn = False

# 周遊所有圖層
for i in doc.Layers:
    if i.Name == '0':
        layer2 = i
    if i.Name == '面積插入':
        layer3 = i
# 設定目前圖層
doc.ActiveLayer = layer2
# 删除圖層
layer3.Delete()
           

六、建立新圖形

cad = Cad()

new_doc = cad.docs.Add(r'C:\Users\liu\Desktop\1.dwg')

startPoint = cad.vtpnt(0, 0)
endPoint = cad.vtpnt(10, 10)

lineobj = new_doc.ModelSpace.AddLine(startPoint, endPoint)

new_doc.SaveAs(r'C:\Users\liu\Desktop\1.dwg')
new_doc.Close('TRUE')