1. 程式人生 > 程式設計 >python3讀取autocad圖形檔案.py例項

python3讀取autocad圖形檔案.py例項

廢話不多說,看程式碼吧!

'''
待完善。
此程式碼實現了,根據標註文字的
屬性,數值,位置,及 容差,
去判斷 設計 和 實測兩圖中的同一位置的尺寸。
如果是同一位置的尺寸,則進行比較,
並把結果存成表格,到執行此程式碼的當前目錄。

此程式碼執行時,要讀取的 dwg檔案 必須處於開啟狀態。
且 不能在 移動(pan) 模式。

啟動程式碼:
python dwg_measurements_comparison4.py [8]

其中,8代表,判定兩圖尺寸為同一尺寸的最大距離,
單位:米(圖上單位)。自己決定具體是多少。

注意:
啟動此程式碼後,首先要在cad軟體中開啟 對比圖,
當該圖讀完後,提示切換到實測圖時,請在cad軟體中切換。
切換完成後,回車,即可。

包的安裝:
pip install pyautocad
注:
1.該操作會自動安裝 comtypes模組。
2.如要使用tables 命令,要另外安裝xlrd 和 tablib

'''
from pyautocad import Autocad
import sys
from pyautocad.contrib.tables import Table
import re

acad = Autocad(create_if_not_exists=True)
def getDescription_Measurement_TextPositions():
 '''
 此函式用於讀取 實測圖 的尺寸標註的 屬性,尺寸,尺寸位置。
 並返回結果。
 目前實測圖帶屬性,對比圖不帶。
 '''
 print('正在讀取 ',acad.doc.Name,' ...')
 description_measurement_textPositions = []
 for obj in acad.iter_objects('Dimension'):
  description_measurement_textPositions.append(
   (obj.GetXData("MyDimDist")[1][1],round(obj.Measurement,2),obj.TextPosition)
  )
 return description_measurement_textPositions

def getMeasurement_TextPositions():
 '''
 此函式用於讀取 對比圖 的尺寸,尺寸位置。
 並返回結果。
 '''
 print('正在讀取 ',' ...')
 measurements_textPositions = []
 for a in acad.iter_objects('Dimension'):
  measurements_textPositions.append((round(a.Measurement,a.TextPosition))  
 return measurements_textPositions

def isTheSameMeasurement(point1,point2,tolerance):
 '''
 point1,類似這樣(82.37,(81953.97462829649,276686.2885731713,0.0)),
 82.37,代表標註的尺寸,後邊代表,該尺寸在圖上顯示的位置座標。
 point2,類似這樣('車間二;長',82.44,(81951.56923143109,276679.7827104012,0.0))
 
 此函式通過 兩個標註的距離來判斷,
 兩個尺寸,是否是同一位置處的尺寸。
 是,return True
 否,return False

 tolerance,設計/實測圖的同一位置兩個尺寸標註允許的距離差。
 即,在這個距離差之內,認為是同一個物件的尺寸,可以進行比對。
 ''' 
 p1x = point1[1][0]
 p1y = point1[1][1]
 p2x = point2[2][0]
 p2y = point2[2][1]
 d = ((p1x - p2x) ** 2 + (p1y - p2y) ** 2) ** 0.5
 if d < tolerance:
  return True
 else:
  return False

def handleData(lst):
 '''
 此函式用於處理讀取到的原始資料,
 把原始資料分成三類:
 長,寬,間距 三個列表如下:
 lengthLst,widthLst,distanceLst,
 並返回。
 '''
 lengthLst = []
 widthLst = []
 distanceLst = []
 for i in lst:
  key = i[0].split(';')[1]
  if key == '間距':
   distanceLst.append(i)
  elif key == '長':
   lengthLst.append(i)
  elif key == '寬':
   widthLst.append(i)
 return lengthLst,widthLst,distanceLst

def handleLengthWidth(lengthLst,widthLst):
 '''
 此函式用於處理長度列表和寬度列表,
 組合成一個列表,即報告中需要的資料結構。

 其中,連廊只有寬度,需單獨處理。
 '''
 tableContents = []
 tableName = '竣工建(構)築物滿外尺寸對比表'
 tableHead = ['\\','發證長度','實測長度','長度差值(允許誤差值)','發證寬度','實測寬度','寬度差值(允許誤差值)'  
 ]
 tableContents.append(tableHead)
 # 處理連廊尺寸。
 for w in widthLst:
  keyW = w[0].split(';')[0]
  if re.match('連廊',keyW):
   w2 = [keyW]
   w2.extend(['---','---','---'])
   w2.extend(w[1:])
   tableContents.append(w2)
 # 處理同時有長寬的尺寸。
 for l in lengthLst:
  keyL = l[0].split(';')[0]
  for w in widthLst:
   keyW = w[0].split(';')[0]   
   if keyL == keyW:
    w2 = w[1:]
    l[0] = l[0].split(';')[0]
    l.extend(w2)
    tableContents.append(l)
    break
 tableContents.sort()
 return tableName,tableContents

def handleDistance(distanceLst):
 '''
 此函式用於處理建築物 間距尺寸。 
 '''
 tableContents = []
 tableName = '竣工建(構)築物間距對比表'
 tableHead = [
  '\\','發證間距','實測間距','差值','允許誤差值'
 ]
 tableContents.append(tableHead)
 for dl in distanceLst:
  dl[0] = dl[0][:-3]
  new = dl[-1][6:-1]
  dl[-1] = dl[-1][:5]
  dl.append(new)
  tableContents.append(dl)
 tableContents.sort()
 return tableName,tableContents

def handleDJ():
 '''
 此函式用於處理地界特徵點。
 '''
 tableContents = []
 tableName = '用地界址座標表'
 tableHead = [
  '點號','X座標(米)','Y座標(米)'
 ]
 tableContents.append(tableHead)
 area = 0
 for obj in acad.iter_objects("PolyLine"):
  if obj.Layer == 'DJHX':
   area = '%.1f' % obj.Area
   t = obj.Coordinates
   if 0 in t:
    DJHX = [('%.3f' % t[i],'%.3f' % t[i+1],t[i+2]) for i in range(0,len(t),3)]
   else:
    DJHX = [('%.3f' % t[i],0) for i in range(0,2)]
   break
 for i in range(len(DJHX)):
  tableContents.append(['J' + str(i + 1),DJHX[i][1],DJHX[i][0]])
 tableContents.append(['用地面積',area,'平方米'])
 return tableName,tableContents 

def write_to_table(tableName,tableContents):
 table = Table()
 for row in tableContents:
  table.writerow(row)
 table.save(tableName + '.xls','xls')

def main(tolerance):
 i = input('請在CAD軟體中開啟 對比圖。打開了嗎?[Y]')
 if i == '' or i.upper() == 'Y':
  # dmt1,第一次讀取的尺寸,設計尺寸。
  dmt1 = getMeasurement_TextPositions()
  print('此圖有效尺寸數:',len(dmt1),' 個')
  # print(dmt1)
  print()
 i = input('請在CAD軟體中切換到 實測圖。切換了嗎?[Y]')
 if i == '' or i.upper() == 'Y':
  # dmt2,第二次讀取的尺寸,實測尺寸。
  dmt2 = getDescription_Measurement_TextPositions()
  print('此圖有效尺寸數:',len(dmt2),' 個')
  # print(dmt2)
  print()
 # print(dmt1,dmt2,sep='\n\n')
 # d_value,儲存兩個同位置尺寸的 屬性,設計尺寸,實測尺寸,及差值。
 d_value = []
 for m1 in dmt1:
  for m2 in dmt2:
   if isTheSameMeasurement(m1,m2,tolerance):
    d_value.append([
     m2[0],'%.2f' % m1[0],'%.2f' % m2[1],'%.2f' % (m2[1] - m1[0]) + '(±' + '%.2f' % (m1[0] * 0.005) + ')'
    ])
    break
 print('比對兩圖尺寸數:',len(d_value),' 個')
 print('兩圖中判定為同一尺寸的容差:',tolerance,' 米(圖上單位)。') 

 lengthLst,distanceLst = handleData(d_value)
 # print(lengthLst,distanceLst,sep='\n')
 tableName,tableContents = handleLengthWidth(lengthLst,widthLst)
 print()
 print(tableName)
 write_to_table(tableName,tableContents)

 tableName,tableContents = handleDistance(distanceLst)
 print(tableName)
 write_to_table(tableName,tableContents = handleDJ()
 print(tableName)
 write_to_table(tableName,tableContents)

if __name__ == '__main__':
 try:
  tolerance = sys.argv[1]
  main(int(tolerance))
 except IndexError:
  # 預設兩圖尺寸相差2米內算同一個尺寸。
  main(2)

補充知識:使用python來操作autocad,並且將座標點轉換成cad可見物件

由於工作需要,在專案中遇到一個棘手的問題,如何將(mssql)資料庫中的BLOB檔案轉成cad可見圖形

(可能每個專案需求不一樣,解決方式不同)

第一步 . 需要轉換的圖形型別

python3讀取autocad圖形檔案.py例項

第二步 . 那我們先查詢這個欄位

python3讀取autocad圖形檔案.py例項

第三步 試試將這個寫入一個文字中 看看是那種圖形 (data:image/*;base64) *號 為圖片格式字尾

1.試試用新學的python 來操作,當然java也可以

(這個連結資料庫,寫入某個欄位的內容就貼出來了,畢竟是做python與cad的)

2.生成後的檔案內容

python3讀取autocad圖形檔案.py例項

3.不是我們期待的普通圖形,是cad的一些座標點什麼的,那我們就可以找到座標點來操作

檢視文字內容後,我們看到的是開頭識別符號T,TEXT,LINE,JZMJ (還有其他的圖形包含 ARC,ARRORW,PL,DIMQJ)還有一部分 就不一一寫了(主要是目前就只用到幾個常用的開頭識別符號)

轉換一下(在cad命令列中輸入) 可以知道 PL LINE RULEDIM 為直線,有兩個座標點

如: p1 = (0,0) p2 = (0,10) 就可以生成一條直線

4 . 那麼從上面的內容中可以看到,我們找到座標點,

如:LINE_宋體_1_120_-1__18_1_0__clBlack_0_0_3_13580_-7520_7280_-7520_0_0_13580_-7520_

p1 = (13580,-7520)

p2 = (7280,-7520)

5 . 找到座標之後發現一個規律 可以將這一行 擷取(“_”),生成陣列下標為 [14],[15],[16],[17]

第四步 開啟CAD (任意版本的cad都可以)

python3讀取autocad圖形檔案.py例項

(個人使用的是2017版)

第五步 使用python操作CAD

1.首先匯入pyautocad庫,並且看看自己python的comtypes是否安裝

2.先插入一條測試線 看看能否成功

from pyautocad import Autocad,APoint
 
p1 = APoint(10,20)
p2 = APoint(10,80)
 
acad = Autocad(create_if_not_exists = True)
acad.model.AddLine(p1,p2)

3.提示錯誤:

_ctypes.COMError: (-2147352567,'發生意外。',('無法獲取 Document 物件','AutoCAD','C:\\Program Files\\Autodesk\\AutoCAD 2017\\HELP\\OLE_ERR.CHM',-2145320900,None))

4.這個錯誤一般是cad沒有新建一個視窗

python3讀取autocad圖形檔案.py例項

5.新建一個畫圖視窗就可以執行上面測試程式碼了

6.介紹幾個常用命令:

AddLine(p1,p2)

新增直線

點一,點二

AddText(text,p1,fontSize)

新增文字

文字內容,點一,字型高度

AddArc(center,radius,sDrgress,eDrgress)

新增圓弧

圓心 , 半徑 ,開始弧 , 結束弧

SaveAs(filepath ,1)

儲存當前畫好的圖形

檔案絕對路徑 , 後面預設寫1 不知道原因 (這方面文件很少,所以不知道怎麼查)

最後,如果有不懂得地方,或者我哪些沒有做好,都可以聯絡我,感謝!

以上這篇python3讀取autocad圖形檔案.py例項就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。