hytos / DTI_PID / DTI_PID / ImportTextFromCADDialog.py @ e02478ba
이력 | 보기 | 이력해설 | 다운로드 (75.4 KB)
1 |
# coding: utf-8
|
---|---|
2 |
"""This is text importing module from AutoCAD"""
|
3 |
import math |
4 |
import os |
5 |
import sys |
6 |
from PyQt5.QtCore import * |
7 |
from PyQt5.QtGui import * |
8 |
from PyQt5.QtWidgets import * |
9 |
from AppDocData import AppDocData |
10 |
from functools import reduce, partial |
11 |
import subprocess |
12 |
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse |
13 |
from SymbolRegiDataListDialog import QSymbolRegiDataListDialog |
14 |
import uuid |
15 |
from Drawing import Drawing |
16 |
|
17 |
import ImportTextFromCAD_UI |
18 |
|
19 |
|
20 |
class LineTypeMappingDelegate(QStyledItemDelegate): |
21 |
def __init__(self, layer_names: list, parent=None): |
22 |
QStyledItemDelegate.__init__(self, parent)
|
23 |
|
24 |
self._layer_names = layer_names
|
25 |
|
26 |
def createEditor(self, parent, option, index): |
27 |
editor = None
|
28 |
|
29 |
item = index.model().itemFromIndex(index) |
30 |
if not item.parent(): |
31 |
if index.column() == 1: |
32 |
editor = QComboBox(parent) |
33 |
editor.addItems(self._layer_names if self._layer_names else ['']) |
34 |
|
35 |
return editor if editor else super(LineTypeMappingDelegate, self).createEditor(parent, option, index) |
36 |
|
37 |
|
38 |
class SymbolMappingDelegate(QStyledItemDelegate): |
39 |
def __init__(self, symbol_types: list, parent=None): |
40 |
QStyledItemDelegate.__init__(self, parent)
|
41 |
|
42 |
self._symbol_types = symbol_types
|
43 |
|
44 |
def createEditor(self, parent, option, index): |
45 |
"""create a editor for symbol mapping"""
|
46 |
editor = None
|
47 |
|
48 |
item = index.model().itemFromIndex(index) |
49 |
if item.parent() and not item.parent().parent(): |
50 |
if index.column() == 1: |
51 |
editor = QComboBox(parent) |
52 |
editor.addItems(self._symbol_types if self._symbol_types else ['']) |
53 |
|
54 |
return editor if editor else super(SymbolMappingDelegate, self).createEditor(parent, option, index) |
55 |
|
56 |
|
57 |
class ExcludeLayersDelegate(QStyledItemDelegate): |
58 |
def editorEvent(self, event, model, option, index): |
59 |
checked = index.data(Qt.CheckStateRole) |
60 |
ret = QStyledItemDelegate.editorEvent(self, event, model, option, index)
|
61 |
if checked != index.data(Qt.CheckStateRole):
|
62 |
self.parent().checked.emit(index)
|
63 |
|
64 |
return ret
|
65 |
|
66 |
|
67 |
class LineTypeMappingModel(QStandardItemModel): |
68 |
"""This is LineTypeMapping Model class"""
|
69 |
def __init__(self): |
70 |
from LineTypeConditions import LineTypeConditions |
71 |
|
72 |
QStandardItemModel.__init__(self)
|
73 |
|
74 |
app_doc_data = AppDocData.instance() |
75 |
configs = app_doc_data.getConfigs(section='Line Type Mapping')
|
76 |
|
77 |
for condition in LineTypeConditions.items(): |
78 |
items = [QStandardItem(condition.name), QStandardItem(''), QStandardItem('')] |
79 |
items[0].setEditable(False) |
80 |
self.appendRow(items)
|
81 |
|
82 |
matches = [config for config in configs if config.key == condition.name] |
83 |
for match in matches: |
84 |
line_types = match.value.split(',')
|
85 |
for line_type in line_types: |
86 |
childs = [QStandardItem(''), QStandardItem(line_type), QStandardItem('')] |
87 |
childs[0].setData(condition.name, Qt.UserRole)
|
88 |
for child in childs: |
89 |
child.setEditable(False)
|
90 |
items[0].appendRow(childs)
|
91 |
|
92 |
headers = [QStandardItem("ID2 Line Type"), QStandardItem("AutoCAD Line Layer"), QStandardItem('')] |
93 |
for idx, header in enumerate(headers): |
94 |
header.setTextAlignment(Qt.AlignCenter) |
95 |
self.setHorizontalHeaderItem(idx, header)
|
96 |
|
97 |
|
98 |
class SymbolMappingModel(QStandardItemModel): |
99 |
"""This is SymbolMapping Model class"""
|
100 |
def __init__(self): |
101 |
"""constructor"""
|
102 |
QStandardItemModel.__init__(self)
|
103 |
|
104 |
self._autocad_symbols = [] # holder for autocad symbol |
105 |
|
106 |
project = AppDocData.instance().getCurrentProject() |
107 |
if project is not None: |
108 |
self.clear()
|
109 |
self.load_symbol_info()
|
110 |
|
111 |
# load and display symbol mapping
|
112 |
app_doc_data = AppDocData.instance() |
113 |
configs = app_doc_data.getConfigs(section='Symbol Mapping')
|
114 |
|
115 |
for row in range(self.rowCount()): |
116 |
category_index = self.index(row, 0) |
117 |
|
118 |
child_count = self.rowCount(category_index)
|
119 |
for child_row in range(child_count): |
120 |
child_index = self.index(child_row, 0, category_index) |
121 |
id2_symbol_item = self.itemFromIndex(child_index)
|
122 |
id2_symbol_uid = id2_symbol_item.data(Qt.UserRole) |
123 |
|
124 |
matches = [config for config in configs if config.key == str(id2_symbol_uid)] |
125 |
for match in matches: |
126 |
symbols = match.value.split(',')
|
127 |
for symbol in symbols: |
128 |
if symbol not in self._autocad_symbols: |
129 |
self._autocad_symbols.append(symbol)
|
130 |
|
131 |
childs = [QStandardItem(''), QStandardItem(symbol), QStandardItem('')] |
132 |
childs[0].setData(id2_symbol_uid, Qt.UserRole)
|
133 |
for child in childs: |
134 |
child.setEditable(False)
|
135 |
id2_symbol_item.appendRow(childs) |
136 |
|
137 |
headers = [QStandardItem("ID2 Symbol"), QStandardItem("AutoCAD Symbol"), QStandardItem('')] |
138 |
for idx, header in enumerate(headers): |
139 |
header.setTextAlignment(Qt.AlignCenter) |
140 |
self.setHorizontalHeaderItem(idx, header)
|
141 |
|
142 |
def load_symbol_info(self): |
143 |
"""load symbol information and display it on tree view"""
|
144 |
try:
|
145 |
app_doc_data = AppDocData.instance() |
146 |
|
147 |
symbolTypeList = app_doc_data.getSymbolTypeList() |
148 |
for row, symbolType in enumerate(symbolTypeList): |
149 |
items = [QStandardItem(symbolType[2]), QStandardItem(''), QStandardItem('')] |
150 |
items[0].setData(symbolType, Qt.UserRole)
|
151 |
items[0].setEditable(False) |
152 |
items[0].setSelectable(False) |
153 |
items[1].setEditable(False) |
154 |
items[1].setSelectable(False) |
155 |
items[2].setEditable(False) |
156 |
items[2].setSelectable(False) |
157 |
|
158 |
symbolList = app_doc_data.getSymbolListByType('UID', symbolType[0]) |
159 |
for symbol in symbolList: |
160 |
childs = [QStandardItem(symbol.getName()), QStandardItem(''), QStandardItem('')] |
161 |
childs[0].setData(symbol.getUid(), Qt.UserRole)
|
162 |
childs[0].setEditable(False) |
163 |
|
164 |
_, svg = app_doc_data.read_symbol_shape(symbol.sName) |
165 |
if svg:
|
166 |
symbol.pixmap = QPixmap() |
167 |
symbol.pixmap.loadFromData(svg if isinstance(svg, bytes) else svg.encode()) |
168 |
icon = QIcon(symbol.pixmap) |
169 |
childs[0].setIcon(icon)
|
170 |
childs[0].svgFilePath = None # save svg file path |
171 |
else:
|
172 |
svgPath = symbol.getSvgFileFullPath() |
173 |
symbol.pixmap = QPixmap(svgPath) |
174 |
icon = QIcon(symbol.pixmap) |
175 |
childs[0].setIcon(icon)
|
176 |
childs[0].svgFilePath = svgPath # save svg file path |
177 |
|
178 |
items[0].appendRow(childs)
|
179 |
|
180 |
items[0].sortChildren(0, Qt.AscendingOrder) |
181 |
self.appendRow(items)
|
182 |
except Exception as ex: |
183 |
from App import App |
184 |
from AppDocData import MessageType |
185 |
|
186 |
message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
|
187 |
f'{sys.exc_info()[-1].tb_lineno}'
|
188 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
189 |
|
190 |
@property
|
191 |
def autocad_symbols(self): |
192 |
"""property of autocad symbol"""
|
193 |
return self._autocad_symbols |
194 |
|
195 |
|
196 |
class ExcludeLayersModel(QStandardItemModel): |
197 |
def __init__(self, parent): |
198 |
"""
|
199 |
constructor
|
200 |
:param parent:
|
201 |
"""
|
202 |
import csv |
203 |
|
204 |
"""constructor"""
|
205 |
QStandardItemModel.__init__(self, parent=parent)
|
206 |
|
207 |
self._autocad_symbols = [] # holder for autocad symbol |
208 |
|
209 |
project = AppDocData.instance().getCurrentProject() |
210 |
if project is not None: |
211 |
self.clear()
|
212 |
|
213 |
# load and display exclude layers mapping
|
214 |
app_doc_data = AppDocData.instance() |
215 |
configs = app_doc_data.getConfigs(section='Exclude Layers Mapping')
|
216 |
if configs and configs[0]: |
217 |
values = list(csv.reader([configs[0].value], delimiter=',', escapechar='^'))[0] |
218 |
for value in values: |
219 |
item = QStandardItem(value) |
220 |
item.setCheckable(True)
|
221 |
item.setCheckState(Qt.Checked) |
222 |
self.appendRow(item)
|
223 |
|
224 |
def append_layers(self, layers: list) -> None: |
225 |
"""
|
226 |
add layers to listview
|
227 |
:param layers:
|
228 |
:return:
|
229 |
"""
|
230 |
|
231 |
for layer in layers: |
232 |
items = self.findItems(layer)
|
233 |
if not items: |
234 |
item = QStandardItem(layer) |
235 |
item.setCheckable(True)
|
236 |
item.setCheckState(Qt.Unchecked) |
237 |
self.appendRow(item)
|
238 |
|
239 |
|
240 |
class QImportTextFromCADDialog(QDialog): |
241 |
def __init__(self, parent): |
242 |
"""constructor"""
|
243 |
QDialog.__init__(self, parent)
|
244 |
|
245 |
self.ui = ImportTextFromCAD_UI.Ui_ImportTextFromCADDialog()
|
246 |
self.ui.setupUi(self) |
247 |
|
248 |
self._dwgs = []
|
249 |
self._layer_names, self._line_types = [], [] |
250 |
self._symbol_types = []
|
251 |
self.on_load_line_type_mapping()
|
252 |
self.on_load_symbol_mapping()
|
253 |
self.on_load_exclude_layers_mapping()
|
254 |
|
255 |
app_doc_data = AppDocData.instance() |
256 |
#self.drawing_height = app_doc_data.activeDrawing.image.shape[1]
|
257 |
|
258 |
configs = app_doc_data.getConfigs('Cad Offset', 'X') |
259 |
self.ui.spinBoxX.setValue(int(configs[0].value)) if 1 == len(configs) else \ |
260 |
self.ui.spinBoxX.setValue(0) |
261 |
configs = app_doc_data.getConfigs('Cad Offset', 'Y') |
262 |
self.ui.spinBoxY.setValue(int(configs[0].value)) if 1 == len(configs) else \ |
263 |
self.ui.spinBoxY.setValue(0) |
264 |
configs = app_doc_data.getConfigs('Cad Offset', 'Text X') |
265 |
self.ui.spinBoxTextX.setValue(int(configs[0].value)) if 1 == len(configs) else \ |
266 |
self.ui.spinBoxTextX.setValue(0) |
267 |
configs = app_doc_data.getConfigs('Cad Offset', 'Text Y') |
268 |
self.ui.spinBoxTextY.setValue(int(configs[0].value)) if 1 == len(configs) else \ |
269 |
self.ui.spinBoxTextY.setValue(0) |
270 |
configs = app_doc_data.getConfigs('Cad Offset', 'Scale') |
271 |
self.ui.doubleSpinBoxScale.setValue(float(configs[0].value)) if 1 == len(configs) else \ |
272 |
self.ui.doubleSpinBoxScale.setValue(0.5) |
273 |
configs = app_doc_data.getConfigs('Cad Offset', 'X Scale') |
274 |
self.ui.doubleSpinBox.setValue(float(configs[0].value)) if 1 == len(configs) else \ |
275 |
self.ui.doubleSpinBoxScale.setValue(0.5) |
276 |
configs = app_doc_data.getConfigs('Cad Offset', 'Y Scale') |
277 |
self.ui.doubleSpinBox_2.setValue(float(configs[0].value)) if 1 == len(configs) else \ |
278 |
self.ui.doubleSpinBoxScale.setValue(0.5) |
279 |
configs = app_doc_data.getConfigs('Cad State', 'Line') |
280 |
self.ui.checkBoxLine.setChecked(bool(int(configs[0].value))) if 1 == len(configs) else \ |
281 |
self.ui.checkBoxLine.setChecked(False) |
282 |
configs = app_doc_data.getConfigs('Cad State', 'Text') |
283 |
self.ui.checkBoxText.setChecked(bool(int(configs[0].value))) if 1 == len(configs) else \ |
284 |
self.ui.checkBoxText.setChecked(True) |
285 |
configs = app_doc_data.getConfigs('Cad State', 'Symbol') |
286 |
self.ui.checkBoxSymbol.setChecked(bool(int(configs[0].value))) if 1 == len(configs) else \ |
287 |
self.ui.checkBoxSymbol.setChecked(False) |
288 |
|
289 |
self.text_scale = None |
290 |
self.id2_bbox = None |
291 |
self.scales = None |
292 |
self.offsets = None |
293 |
|
294 |
self.isAccepted = False |
295 |
|
296 |
self.ui.toolButtonCAD.clicked.connect(self.on_add_cad_click) |
297 |
self.ui.pushButtonSave.clicked.connect(self.on_save_mappings) |
298 |
self.ui.pushButtonImport.clicked.connect(self.importClicked) |
299 |
self.ui.pushButtonClose.clicked.connect(self.close) |
300 |
self.ui.pushButtonAuto.clicked.connect(self.autoCalOffset) |
301 |
self.ui.checkBoxAuto.stateChanged.connect(self.autoStateChanged) |
302 |
self.ui.checkBoxLegend.stateChanged.connect(self.legendStateChanged) |
303 |
self.ui.checkBoxAuto.stateChanged.connect(self.autoStateChanged) |
304 |
self.ui.pushButtonAutoMapping.clicked.connect(self.autoMapping) |
305 |
|
306 |
configs = app_doc_data.getConfigs('Cad State', 'Auto') |
307 |
self.ui.checkBoxAuto.setChecked(bool(int((configs[0].value)))) if 1 == len(configs) else \ |
308 |
self.ui.checkBoxAuto.setChecked(True) |
309 |
|
310 |
def importClicked(self): |
311 |
if self.ui.checkBoxLegend.isChecked(): |
312 |
self.on_import_legend()
|
313 |
else:
|
314 |
self.on_import_autocad()
|
315 |
|
316 |
def legendStateChanged(self, checkState): |
317 |
if checkState is int(Qt.Checked): |
318 |
self.ui.checkBoxLine.setEnabled(False) |
319 |
self.ui.checkBoxSymbol.setEnabled(False) |
320 |
self.ui.checkBoxText.setEnabled(False) |
321 |
elif checkState is int(Qt.Unchecked): |
322 |
self.ui.checkBoxLine.setEnabled(True) |
323 |
self.ui.checkBoxSymbol.setEnabled(True) |
324 |
self.ui.checkBoxText.setEnabled(True) |
325 |
|
326 |
def autoStateChanged(self, checkState): |
327 |
if checkState is int(Qt.Checked): |
328 |
self.ui.spinBoxX.setEnabled(False) |
329 |
self.ui.spinBoxY.setEnabled(False) |
330 |
self.ui.spinBoxTextX.setEnabled(False) |
331 |
self.ui.spinBoxTextY.setEnabled(False) |
332 |
self.ui.spinBoxSymbolX.setEnabled(False) |
333 |
self.ui.spinBoxSymbolY.setEnabled(False) |
334 |
self.ui.doubleSpinBoxScale.setEnabled(False) |
335 |
self.ui.doubleSpinBox.setEnabled(False) |
336 |
self.ui.doubleSpinBox_2.setEnabled(False) |
337 |
self.ui.lineEdit.setEnabled(False) |
338 |
self.ui.lineEdit_2.setEnabled(False) |
339 |
elif checkState is int(Qt.Unchecked): |
340 |
self.ui.spinBoxX.setEnabled(True) |
341 |
self.ui.spinBoxY.setEnabled(True) |
342 |
self.ui.spinBoxTextX.setEnabled(True) |
343 |
self.ui.spinBoxTextY.setEnabled(True) |
344 |
self.ui.spinBoxSymbolX.setEnabled(True) |
345 |
self.ui.spinBoxSymbolY.setEnabled(True) |
346 |
self.ui.doubleSpinBoxScale.setEnabled(True) |
347 |
self.ui.doubleSpinBox.setEnabled(True) |
348 |
self.ui.doubleSpinBox_2.setEnabled(True) |
349 |
self.ui.lineEdit.setEnabled(True) |
350 |
self.ui.lineEdit_2.setEnabled(True) |
351 |
|
352 |
def autoMapping(self): |
353 |
if not self._dwgs: |
354 |
QMessageBox.information(self, self.tr('Information'), self.tr('There is no selected file(s)')) |
355 |
return
|
356 |
|
357 |
model = self.ui.treeViewSymbolMapping.model()
|
358 |
row_index = [] |
359 |
for row in range(model.rowCount()): |
360 |
category_index = model.index(row, 0)
|
361 |
|
362 |
child_count = model.rowCount(category_index) |
363 |
for child_row in range(child_count): |
364 |
child_index = model.index(child_row, 0, category_index)
|
365 |
id2_symbol_item = model.itemFromIndex(child_index) |
366 |
id2_symbol_uid = id2_symbol_item.data(Qt.UserRole) |
367 |
cad_symbol_list = [(symbol if '+' not in symbol else symbol.split('+')[1], symbol) for symbol in self._symbol_types] |
368 |
matches = [cad_symbol for cad_symbol in cad_symbol_list if cad_symbol[0].upper() == id2_symbol_item.text().upper()] |
369 |
if matches:
|
370 |
row_index.insert(0, [row, child_row, matches[0][1], id2_symbol_uid, id2_symbol_item]) |
371 |
|
372 |
for categoty, child, symbol, uid, item in row_index: |
373 |
category_index = model.index(categoty, 0)
|
374 |
child_index = model.index(child, 0, category_index)
|
375 |
if symbol not in model._autocad_symbols: |
376 |
model._autocad_symbols.append(symbol) |
377 |
childs = [QStandardItem(''), QStandardItem(symbol), QStandardItem('')] |
378 |
childs[0].setData(uid, Qt.UserRole)
|
379 |
for _child in childs: |
380 |
_child.setEditable(False)
|
381 |
item.appendRow(childs) |
382 |
|
383 |
button = QPushButton(icon=QIcon(":/newPrefix/Remove.svg"))
|
384 |
button.setMaximumWidth(20)
|
385 |
_index = model.index(model.rowCount(child_index) - 1, 2, child_index) |
386 |
button.clicked.connect(self.on_remove_symbol_mapping_item)
|
387 |
self.ui.treeViewSymbolMapping.setIndexWidget(_index, button)
|
388 |
|
389 |
def autoCalOffset(self): |
390 |
""" auto calculate offset """
|
391 |
from App import App |
392 |
from EngineeringTextItem import QEngineeringTextItem |
393 |
|
394 |
if not self._dwgs: |
395 |
QMessageBox.information(self, self.tr('Information'), self.tr('There is no selected file(s)')) |
396 |
return
|
397 |
|
398 |
# find ID2 Text Item
|
399 |
find_text_1 = self.ui.lineEdit.text()
|
400 |
find_text_2 = self.ui.lineEdit_2.text()
|
401 |
|
402 |
matches_1 = [item for item in App.mainWnd().graphicsView.items() if issubclass(type(item), QEngineeringTextItem) and item.text() == find_text_1] |
403 |
matches_2 = [item for item in App.mainWnd().graphicsView.items() if issubclass(type(item), QEngineeringTextItem) and item.text() == find_text_2] |
404 |
if not matches_1 or not matches_2: |
405 |
QMessageBox.information(self, self.tr('Information'), self.tr('There is no search text items.')) |
406 |
return
|
407 |
|
408 |
text_item_1 = matches_1[0]
|
409 |
text_loc_1 = text_item_1.loc |
410 |
text_item_2 = matches_2[0]
|
411 |
text_loc_2 = text_item_2.loc |
412 |
|
413 |
cad_item_loc_1 = None
|
414 |
cad_item_loc_2 = None
|
415 |
# up to here
|
416 |
|
417 |
app_doc_data = AppDocData.instance() |
418 |
project = app_doc_data.getCurrentProject() |
419 |
|
420 |
temp_path = project.getTempPath() |
421 |
id2_xml_files = [f for f in os.listdir(temp_path) if os.path.isfile(os.path.join(temp_path, f)) and |
422 |
(os.path.splitext(f)[1].upper() == '.XML')] |
423 |
|
424 |
_file = self._dwgs[0] |
425 |
file_name = os.path.splitext(os.path.basename(_file))[0]
|
426 |
autocad_xml_path = os.path.join(os.path.dirname(_file), os.path.splitext(os.path.basename(_file))[0] + '.xml') |
427 |
matches = [id2_xml_file for id2_xml_file in id2_xml_files if id2_xml_file.replace(file_name, '').upper() == '.XML'] |
428 |
|
429 |
if matches:
|
430 |
try:
|
431 |
id2_xml_path = os.path.join(temp_path, matches[0])
|
432 |
id2_xml = parse(id2_xml_path) |
433 |
id2_xml_root = id2_xml.getroot() |
434 |
|
435 |
autocad_xml = parse(autocad_xml_path) |
436 |
autocad_xml_root = autocad_xml.getroot() |
437 |
|
438 |
find_1 = False
|
439 |
find_2 = False
|
440 |
for blk_tbl_record in autocad_xml_root.iter('AcDbBlockTableRecord'): |
441 |
if find_1 and find_2: |
442 |
break
|
443 |
|
444 |
if blk_tbl_record.attrib['Name'].upper() != '*Model_Space'.upper(): |
445 |
continue
|
446 |
'''
|
447 |
min_values = [float(token) for token in
|
448 |
blk_tbl_record.attrib['MinExtents'].strip('(').strip(')').split(',')]
|
449 |
max_values = [float(token) for token in
|
450 |
blk_tbl_record.attrib['MaxExtents'].strip('(').strip(')').split(',')]
|
451 |
autocad_bbox = [min_values[0], min_values[1],
|
452 |
max_values[0] - min_values[0], max_values[1] - min_values[1]]
|
453 |
'''
|
454 |
for text_node in blk_tbl_record.iter('AcDbText'): |
455 |
if find_text_1 != text_node.text and find_text_2 != text_node.text: |
456 |
continue
|
457 |
elif find_text_1 == text_node.text:
|
458 |
x = float(text_node.attrib['X']) |
459 |
y = float(text_node.attrib['Y']) |
460 |
h = float(text_node.attrib['Height']) |
461 |
cad_item_loc_1 = [x, y, h] |
462 |
find_1 = True
|
463 |
elif find_text_2 == text_node.text:
|
464 |
x = float(text_node.attrib['X']) |
465 |
y = float(text_node.attrib['Y']) |
466 |
h = float(text_node.attrib['Height']) |
467 |
cad_item_loc_2 = [x, y, h] |
468 |
find_2 = True
|
469 |
|
470 |
if not find_1 or not find_2: |
471 |
for blk_ref in blk_tbl_record.iter('AcDbBlockReference'): |
472 |
if find_1 and find_2: |
473 |
break
|
474 |
|
475 |
for text_node in blk_ref.iter('AcDbAttribute'): |
476 |
if find_text_1 != text_node.text and find_text_2 != text_node.text: |
477 |
continue
|
478 |
elif find_text_1 == text_node.text:
|
479 |
x = float(text_node.attrib['X']) |
480 |
y = float(text_node.attrib['Y']) |
481 |
h = float(text_node.attrib['Height']) |
482 |
cad_item_loc_1 = [x, y, h] |
483 |
find_1 = True
|
484 |
elif find_text_2 == text_node.text:
|
485 |
x = float(text_node.attrib['X']) |
486 |
y = float(text_node.attrib['Y']) |
487 |
h = float(text_node.attrib['Height']) |
488 |
cad_item_loc_2 = [x, y, h] |
489 |
find_2 = True
|
490 |
|
491 |
if find_1 and find_2: |
492 |
dx_1 = abs(text_loc_1[0] - text_loc_2[0]) |
493 |
dx_2 = abs(cad_item_loc_1[0] - cad_item_loc_2[0]) |
494 |
scale_x = dx_1 / dx_2 |
495 |
|
496 |
dy_1 = abs(text_loc_1[1] - text_loc_2[1]) |
497 |
dy_2 = abs(cad_item_loc_1[1] - cad_item_loc_2[1]) |
498 |
scale_y = dy_1 / dy_2 |
499 |
|
500 |
offset_x = text_loc_1[0] - cad_item_loc_1[0] * scale_x |
501 |
drawing_height = int(id2_xml_root.find('SIZE').text.split(',')[1]) |
502 |
offset_y = text_loc_1[1] - (drawing_height - cad_item_loc_1[1] * scale_y) + cad_item_loc_1[2] * scale_y |
503 |
|
504 |
self.ui.spinBoxTextX.setValue(offset_x)
|
505 |
self.ui.spinBoxX.setValue(offset_x)
|
506 |
self.ui.spinBoxSymbolX.setValue(offset_x)
|
507 |
self.ui.spinBoxTextY.setValue(offset_y)
|
508 |
self.ui.spinBoxY.setValue(offset_y)
|
509 |
self.ui.spinBoxSymbolY.setValue(offset_y)
|
510 |
self.ui.doubleSpinBox.setValue(scale_x)
|
511 |
self.ui.doubleSpinBox_2.setValue(scale_y)
|
512 |
|
513 |
except Exception as ex: |
514 |
from App import App |
515 |
from AppDocData import MessageType |
516 |
|
517 |
message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
|
518 |
f'{sys.exc_info()[-1].tb_lineno}'
|
519 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
520 |
|
521 |
def on_load_line_type_mapping(self): |
522 |
"""load ID2-AutoCAD """
|
523 |
def on_remove_treeview_item(): |
524 |
indices = self.ui.treeViewLineType.selectionModel().selectedRows()
|
525 |
for index in sorted(indices): |
526 |
self.ui.treeViewLineType.model().removeRow(index.row(), index.parent())
|
527 |
|
528 |
def on_add_line_type_item(index: QModelIndex): |
529 |
"""add AutoCAD line type corresponding to ID2 line type"""
|
530 |
|
531 |
try:
|
532 |
_index = self.ui.treeViewLineType.model().index(index.row(), 1) |
533 |
autocad_line_type_item = self.ui.treeViewLineType.model().itemFromIndex(_index)
|
534 |
if autocad_line_type_item and autocad_line_type_item.text(): |
535 |
_index = self.ui.treeViewLineType.model().index(index.row(), 0, index.parent()) |
536 |
id2_line_type_item = self.ui.treeViewLineType.model().itemFromIndex(_index)
|
537 |
items = [QStandardItem(''), QStandardItem(autocad_line_type_item.text()), QStandardItem('')] |
538 |
items[0].setData(id2_line_type_item.text(), Qt.UserRole)
|
539 |
for item in items: |
540 |
item.setEditable(False)
|
541 |
id2_line_type_item.appendRow(items) |
542 |
|
543 |
## add remove button
|
544 |
child_count = self.ui.treeViewLineType.model().rowCount(id2_line_type_item.index())
|
545 |
button = QPushButton(icon=QIcon(":/newPrefix/Remove.svg"))
|
546 |
button.setMaximumWidth(20)
|
547 |
button.clicked.connect(on_remove_treeview_item) |
548 |
_index = self.ui.treeViewLineType.model().index(child_count - 1, 2, id2_line_type_item.index()) |
549 |
self.ui.treeViewLineType.setIndexWidget(_index, button)
|
550 |
|
551 |
self.ui.treeViewLineType.expandAll()
|
552 |
except Exception as ex: |
553 |
from App import App |
554 |
from AppDocData import MessageType |
555 |
|
556 |
message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
|
557 |
f'{sys.exc_info()[-1].tb_lineno}'
|
558 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
559 |
|
560 |
model = LineTypeMappingModel() |
561 |
model.invisibleRootItem() |
562 |
self.ui.treeViewLineType.setModel(model)
|
563 |
self.ui.treeViewLineType.setItemDelegate(LineTypeMappingDelegate(self._layer_names, self.ui.treeViewLineType)) |
564 |
|
565 |
for row in range(model.rowCount()): |
566 |
button = QPushButton(icon=QIcon(":/newPrefix/Add.svg"))
|
567 |
button.setMaximumWidth(20)
|
568 |
index = self.ui.treeViewLineType.model().index(row, 2) |
569 |
button.clicked.connect(partial(on_add_line_type_item, index)) |
570 |
self.ui.treeViewLineType.setIndexWidget(index, button)
|
571 |
|
572 |
parent_index = model.index(row, 0)
|
573 |
child_count = model.rowCount(parent_index) |
574 |
for child_row in range(child_count): |
575 |
button = QPushButton(icon=QIcon(":/newPrefix/Remove.svg"))
|
576 |
button.setMaximumWidth(20)
|
577 |
_index = self.ui.treeViewLineType.model().index(child_row, 2, parent_index) |
578 |
button.clicked.connect(on_remove_treeview_item) |
579 |
self.ui.treeViewLineType.setIndexWidget(_index, button)
|
580 |
|
581 |
self.ui.treeViewLineType.resizeColumnToContents(0) |
582 |
self.ui.treeViewLineType.resizeColumnToContents(1) |
583 |
self.ui.treeViewLineType.resizeColumnToContents(2) |
584 |
self.ui.treeViewLineType.expandAll()
|
585 |
|
586 |
self.ui.label.setHidden(True) |
587 |
self.ui.spinBoxX.setHidden(True) |
588 |
self.ui.spinBoxY.setHidden(True) |
589 |
self.ui.label_8.setHidden(True) |
590 |
self.ui.spinBoxSymbolX.setHidden(True) |
591 |
self.ui.spinBoxSymbolY.setHidden(True) |
592 |
self.ui.label_3.setText('Offset(x, y, text scale) : ') |
593 |
|
594 |
def on_remove_symbol_mapping_item(self): |
595 |
"""remove selected items"""
|
596 |
indices = self.ui.treeViewSymbolMapping.selectionModel().selectedRows()
|
597 |
for index in sorted(indices): |
598 |
_index = self.ui.treeViewSymbolMapping.model().index(index.row(), 1, index.parent()) |
599 |
id2_symbol_item = self.ui.treeViewSymbolMapping.model().itemFromIndex(_index)
|
600 |
self.ui.treeViewSymbolMapping.model()._autocad_symbols.remove(id2_symbol_item.text())
|
601 |
|
602 |
self.ui.treeViewSymbolMapping.model().removeRow(index.row(), index.parent())
|
603 |
|
604 |
def on_add_symbol_type_item(self, index: QModelIndex): |
605 |
"""map AutoCAD symbol and ID2 symbol"""
|
606 |
|
607 |
try:
|
608 |
_index = self.ui.treeViewSymbolMapping.model().index(index.row(), 1, index.parent()) |
609 |
autocad_symbol_item = self.ui.treeViewSymbolMapping.model().itemFromIndex(_index)
|
610 |
if autocad_symbol_item and autocad_symbol_item.text(): |
611 |
_index = self.ui.treeViewSymbolMapping.model().index(index.row(), 0, index.parent()) |
612 |
id2_symbol_item = self.ui.treeViewSymbolMapping.model().itemFromIndex(_index)
|
613 |
items = [QStandardItem(''), QStandardItem(autocad_symbol_item.text()), QStandardItem('')] |
614 |
items[0].setData(id2_symbol_item.data(Qt.UserRole), Qt.UserRole)
|
615 |
for item in items: |
616 |
item.setEditable(False)
|
617 |
id2_symbol_item.appendRow(items) |
618 |
|
619 |
self.ui.treeViewSymbolMapping.model()._autocad_symbols.append(id2_symbol_item.text())
|
620 |
|
621 |
## add remove button
|
622 |
child_count = self.ui.treeViewSymbolMapping.model().rowCount(id2_symbol_item.index())
|
623 |
button = QPushButton(icon=QIcon(":/newPrefix/Remove.svg"))
|
624 |
button.setMaximumWidth(20)
|
625 |
button.clicked.connect(self.on_remove_symbol_mapping_item)
|
626 |
_index = self.ui.treeViewSymbolMapping.model().index(child_count - 1, 2, id2_symbol_item.index()) |
627 |
self.ui.treeViewSymbolMapping.setIndexWidget(_index, button)
|
628 |
|
629 |
self.ui.treeViewSymbolMapping.expandAll()
|
630 |
except Exception as ex: |
631 |
from App import App |
632 |
from AppDocData import MessageType |
633 |
|
634 |
message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
|
635 |
f'{sys.exc_info()[-1].tb_lineno}'
|
636 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
637 |
|
638 |
def on_load_symbol_mapping(self): |
639 |
"""
|
640 |
load symbol mapping setting
|
641 |
"""
|
642 |
|
643 |
model = SymbolMappingModel() |
644 |
model.invisibleRootItem() |
645 |
self.ui.treeViewSymbolMapping.setModel(model)
|
646 |
|
647 |
for row in range(model.rowCount()): |
648 |
parent_index = model.index(row, 0)
|
649 |
child_count = model.rowCount(parent_index) |
650 |
for child_row in range(child_count): |
651 |
button = QPushButton(icon=QIcon(":/newPrefix/Add.svg"))
|
652 |
button.setMaximumWidth(20)
|
653 |
index = model.index(child_row, 2, parent_index)
|
654 |
button.clicked.connect(partial(self.on_add_symbol_type_item, index))
|
655 |
self.ui.treeViewSymbolMapping.setIndexWidget(index, button)
|
656 |
|
657 |
"""add autocad symbol item"""
|
658 |
id2_symbol_index = model.index(child_row, 0, parent_index)
|
659 |
acad_symbol_count = model.rowCount(id2_symbol_index) |
660 |
for acad_symbol in range(acad_symbol_count): |
661 |
button = QPushButton(icon=QIcon(":/newPrefix/Remove.svg"))
|
662 |
button.setMaximumWidth(20)
|
663 |
_index = model.index(acad_symbol, 2, id2_symbol_index)
|
664 |
button.clicked.connect(self.on_remove_symbol_mapping_item)
|
665 |
self.ui.treeViewSymbolMapping.setIndexWidget(_index, button)
|
666 |
|
667 |
self.ui.treeViewSymbolMapping.resizeColumnToContents(0) |
668 |
self.ui.treeViewSymbolMapping.resizeColumnToContents(1) |
669 |
self.ui.treeViewSymbolMapping.resizeColumnToContents(2) |
670 |
self.ui.treeViewSymbolMapping.expandAll()
|
671 |
|
672 |
self._symbol_types = self._symbol_types + model.autocad_symbols[:] |
673 |
self.ui.treeViewSymbolMapping.setItemDelegate(SymbolMappingDelegate(self._symbol_types, |
674 |
self.ui.treeViewSymbolMapping))
|
675 |
|
676 |
def on_load_exclude_layers_mapping(self) -> None: |
677 |
"""
|
678 |
load exclude layers mapping
|
679 |
:return:
|
680 |
"""
|
681 |
model = ExcludeLayersModel(self)
|
682 |
self.ui.listViewExcludeLayers.setModel(model)
|
683 |
|
684 |
def on_add_cad_click(self): |
685 |
"""
|
686 |
extract information from select autocad files
|
687 |
:return:
|
688 |
"""
|
689 |
project = AppDocData.instance().getCurrentProject() |
690 |
drawing_path = project.getDrawingFilePath() |
691 |
|
692 |
options = QFileDialog.Options() |
693 |
options |= QFileDialog.DontUseNativeDialog |
694 |
files, _ = QFileDialog.getOpenFileNames(self, self.tr('Import', "Select AutoCAD File"), |
695 |
os.path.join(drawing_path, 'Native'),
|
696 |
"dwg files (*.dwg)", options=options)
|
697 |
if files:
|
698 |
self.ui.lineEditCAD.setText(files[0]) if len(files) == 1 else \ |
699 |
self.ui.lineEditCAD.setText(str(len(files)) + ' files') |
700 |
|
701 |
self._dwgs.clear()
|
702 |
self._line_types.clear()
|
703 |
self._symbol_types.clear()
|
704 |
self._layer_names.clear()
|
705 |
for _file in files: |
706 |
if os.path.exists(_file):
|
707 |
try:
|
708 |
file = os.path.normpath(_file) |
709 |
drawing_name = os.path.splitext(os.path.basename(file))[0] |
710 |
executable = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'OdReadExMgd',
|
711 |
'OdReadExMgd.exe')
|
712 |
args = [executable, file, '0', '0', '1', '1' if int(self.ui.checkBoxGenDrawing.checkState()) is int(Qt.Checked) else '0'] |
713 |
CREATE_NO_WINDOW = 0x08000000
|
714 |
p = subprocess.Popen( |
715 |
args, |
716 |
stdin=subprocess.PIPE, |
717 |
stdout=subprocess.PIPE, |
718 |
stderr=subprocess.PIPE, |
719 |
creationflags=CREATE_NO_WINDOW |
720 |
) |
721 |
|
722 |
stdout, stderr = p.communicate() |
723 |
if len(stderr) != 0 or ('eFileSharingViolation' in str(stdout) or 300 > len(stdout)): |
724 |
#raise RuntimeError('OdReadExMgd threw error:\n' + stderr.decode('utf-8'))
|
725 |
raise RuntimeError('OdReadExMgd threw error:\n' + str(stderr)) if len(stderr) != 0 else \ |
726 |
RuntimeError('OdReadExMgd threw error:\n' + str(stdout)) |
727 |
|
728 |
"""load image for graphic"""
|
729 |
drawing_file_path = os.path.join(drawing_path, drawing_name + '.PNG')
|
730 |
if not os.path.exists(drawing_file_path): |
731 |
continue
|
732 |
drawing = Drawing(str(uuid.uuid4()), drawing_name + ".PNG", None) |
733 |
_image = drawing.image |
734 |
bytesPerLine = _image.shape[1]
|
735 |
image = QImage(_image.data, _image.shape[1], _image.shape[0], bytesPerLine, QImage.Format_Indexed8) |
736 |
id2_bbox = self.get_contents_size_from_image(drawing_file_path)
|
737 |
"""up to here"""
|
738 |
|
739 |
"""parse layer, line type and symbol"""
|
740 |
autocad_xml_path = os.path.join(os.path.dirname(file), drawing_name + '.xml') |
741 |
autocad_xml = parse(autocad_xml_path) |
742 |
autocad_xml_root = autocad_xml.getroot() |
743 |
|
744 |
for layer_tbl_record in autocad_xml_root.iter('AcDbLayerTableRecord'): |
745 |
layer_name = layer_tbl_record.attrib['Name']
|
746 |
if layer_name in self._layer_names: |
747 |
continue
|
748 |
|
749 |
self._layer_names.append(layer_name)
|
750 |
|
751 |
for line_type_tbl_record in autocad_xml_root.iter('AcDbLinetypeTableRecord'): |
752 |
line_type_name = line_type_tbl_record.attrib['Name']
|
753 |
if line_type_name.upper() in ['ByBlock'.upper(), 'ByLayer'.upper()] or line_type_name in self._line_types: |
754 |
continue
|
755 |
|
756 |
self._line_types.append(line_type_tbl_record.attrib['Name']) |
757 |
|
758 |
for blk_tbl_record in autocad_xml_root.iter('AcDbBlockTableRecord'): |
759 |
if blk_tbl_record.attrib['Name'].upper() != '*Model_Space'.upper(): |
760 |
continue
|
761 |
|
762 |
min_values = [float(token) for token in |
763 |
blk_tbl_record.attrib['MinExtents'].strip('()').split(',')] |
764 |
max_values = [float(token) for token in |
765 |
blk_tbl_record.attrib['MaxExtents'].strip('()').split(',')] |
766 |
autocad_bbox = [min_values[0], min_values[1], |
767 |
max_values[0] - min_values[0], max_values[1] - min_values[1]] |
768 |
|
769 |
if self.ui.checkBoxAuto.isChecked(): |
770 |
scale_x = id2_bbox[2] / autocad_bbox[2] |
771 |
scale_y = id2_bbox[3] / autocad_bbox[3] |
772 |
self.scales = [scale_x, scale_y]
|
773 |
offsets = [id2_bbox[0] - autocad_bbox[0] * scale_x, id2_bbox[3] + id2_bbox[1]] |
774 |
self.offsets = offsets + [autocad_bbox[1]] |
775 |
else:
|
776 |
self.scales = [self.ui.doubleSpinBox.value(), self.ui.doubleSpinBox_2.value()] |
777 |
self.offsets = [self.ui.spinBoxTextX.value(), self.ui.spinBoxTextY.value(), id2_bbox[5]] |
778 |
|
779 |
for block_ref_record in autocad_xml_root.iter('AcDbBlockReference'): |
780 |
block_name = block_ref_record.attrib['Name']
|
781 |
if block_name in self._symbol_types: |
782 |
continue
|
783 |
|
784 |
self._symbol_types.append(block_name)
|
785 |
|
786 |
'''save graphic'''
|
787 |
#node = self.symbol_info(block_ref_record)
|
788 |
#if node and block_name.split('+')[0] == 'Graphic':
|
789 |
# symbolImage = image.copy(round(node[2][0]), round(node[2][1]), math.ceil(node[3] + 2), math.ceil(node[4] + 1))
|
790 |
# file_name = drawing_name + '++' + block_name + '++' + str(round(node[2][0])) + '++' + str(round(node[2][1]))
|
791 |
# image_file_path = os.path.join(project.getGraphicFilePath(), file_name + '.PNG')
|
792 |
# symbolImage.save(image_file_path, 'PNG')
|
793 |
'''up to here'''
|
794 |
"""up to here"""
|
795 |
|
796 |
self._dwgs.append(file) |
797 |
except Exception as ex: |
798 |
from App import App |
799 |
from AppDocData import MessageType |
800 |
|
801 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
|
802 |
f"{sys.exc_info()[-1].tb_lineno}"
|
803 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
804 |
|
805 |
self.ui.listViewExcludeLayers.model().append_layers(self._layer_names) |
806 |
|
807 |
return self._symbol_types |
808 |
|
809 |
def on_save_mappings(self): |
810 |
"""save line type and symbol mappings"""
|
811 |
import io |
812 |
import csv |
813 |
from AppDocData import Config |
814 |
|
815 |
configs = [] |
816 |
configs.append(Config('Cad Offset', 'X', self.ui.spinBoxX.value())) |
817 |
configs.append(Config('Cad Offset', 'Y', self.ui.spinBoxY.value())) |
818 |
configs.append(Config('Cad Offset', 'Text X', self.ui.spinBoxTextX.value())) |
819 |
configs.append(Config('Cad Offset', 'Text Y', self.ui.spinBoxTextY.value())) |
820 |
configs.append(Config('Cad Offset', 'Scale', self.ui.doubleSpinBoxScale.value())) |
821 |
configs.append(Config('Cad Offset', 'X Scale', self.ui.doubleSpinBox.value())) |
822 |
configs.append(Config('Cad Offset', 'Y Scale', self.ui.doubleSpinBox_2.value())) |
823 |
configs.append(Config('Cad State', 'Auto', int(self.ui.checkBoxAuto.isChecked()))) |
824 |
configs.append(Config('Cad State', 'Line', int(self.ui.checkBoxLine.isChecked()))) |
825 |
configs.append(Config('Cad State', 'Text', int(self.ui.checkBoxText.isChecked()))) |
826 |
configs.append(Config('Cad State', 'Symbol', int(self.ui.checkBoxSymbol.isChecked()))) |
827 |
|
828 |
model = self.ui.treeViewLineType.model()
|
829 |
for row in range(model.rowCount()): |
830 |
parent_index = model.index(row, 0)
|
831 |
id2_line_type = model.itemFromIndex(parent_index).text() |
832 |
|
833 |
autocad_line_types = [] |
834 |
child_count = model.rowCount(parent_index) |
835 |
for child_row in range(child_count): |
836 |
child_index = model.index(child_row, 1, parent_index)
|
837 |
autocad_line_types.append(model.itemFromIndex(child_index).text()) |
838 |
|
839 |
if autocad_line_types:
|
840 |
configs.append(Config('Line Type Mapping', id2_line_type, ','.join(autocad_line_types))) |
841 |
|
842 |
# save symbol mappings
|
843 |
model = self.ui.treeViewSymbolMapping.model()
|
844 |
for row in range(model.rowCount()): |
845 |
category_index = model.index(row, 0)
|
846 |
|
847 |
child_count = model.rowCount(category_index) |
848 |
for child_row in range(child_count): |
849 |
autocad_symbols = [] |
850 |
child_index = model.index(child_row, 0, category_index)
|
851 |
id2_symbol_item = model.itemFromIndex(child_index) |
852 |
id2_symbol_uid = id2_symbol_item.data(Qt.UserRole) |
853 |
id2_symbol = id2_symbol_item.text() |
854 |
mapping_count = model.rowCount(child_index) |
855 |
for mapping_row in range(mapping_count): |
856 |
mapping_index = model.index(mapping_row, 1, child_index)
|
857 |
autocad_symbols.append(model.itemFromIndex(mapping_index).text()) |
858 |
|
859 |
if autocad_symbols:
|
860 |
configs.append(Config('Symbol Mapping', id2_symbol_uid, ','.join(autocad_symbols))) |
861 |
|
862 |
# save exclude layers mappings
|
863 |
model = self.ui.listViewExcludeLayers.model()
|
864 |
exclude_layers = [] |
865 |
for row in range(model.rowCount()): |
866 |
item = model.itemFromIndex(model.index(row, 0))
|
867 |
if item.checkState() == Qt.Checked:
|
868 |
exclude_layers.append(item.text()) |
869 |
|
870 |
if exclude_layers:
|
871 |
stream = io.StringIO() |
872 |
csv.writer(stream, delimiter=',', escapechar='^', quoting=csv.QUOTE_NONE).writerow(exclude_layers) |
873 |
configuration = stream.getvalue() |
874 |
|
875 |
configs.append(Config('Exclude Layers Mapping', 'All', configuration)) |
876 |
|
877 |
app_doc_data = AppDocData.instance() |
878 |
"""delete line type mapping and symbol mapping"""
|
879 |
app_doc_data.deleteConfigs(section='Line Type Mapping')
|
880 |
app_doc_data.deleteConfigs(section='Symbol Mapping')
|
881 |
app_doc_data.deleteConfigs(section='Exclude Layers Mapping')
|
882 |
|
883 |
app_doc_data.saveConfigs(configs) |
884 |
|
885 |
QMessageBox.information(self, self.tr('Information'), self.tr('Successfully saved.')) |
886 |
"""up to here"""
|
887 |
|
888 |
def on_import_legend(self): |
889 |
import XmlGenerator as xg |
890 |
from App import App |
891 |
|
892 |
if not self._dwgs: |
893 |
QMessageBox.information(self, self.tr('Information'), self.tr('There is no selected file')) |
894 |
return
|
895 |
|
896 |
app_doc_data = AppDocData.instance() |
897 |
project = app_doc_data.getCurrentProject() |
898 |
|
899 |
temp_path, drawing_path = project.getTempPath(), project.getDrawingFilePath() |
900 |
id2_xml_files = [f for f in os.listdir(temp_path) if os.path.isfile(os.path.join(temp_path, f)) and |
901 |
(os.path.splitext(f)[1].upper() == '.XML')] |
902 |
|
903 |
for _file in self._dwgs: |
904 |
file_name = os.path.splitext(os.path.basename(_file))[0]
|
905 |
id2_image_file = os.path.join(drawing_path, file_name + '.png')
|
906 |
autocad_xml_path = os.path.join(os.path.dirname(_file), os.path.splitext(os.path.basename(_file))[0] + '.xml') |
907 |
matches = [id2_xml_file for id2_xml_file in id2_xml_files if id2_xml_file.replace(file_name, '').upper() == '.XML'] |
908 |
|
909 |
if not matches: |
910 |
path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
|
911 |
img = AppDocData.my_imread(file_path=id2_image_file) |
912 |
_width = img.shape[1]
|
913 |
_height = img.shape[0]
|
914 |
xml, result = xg.write_to_xml(path, _width, _height, [], []) |
915 |
if xml:
|
916 |
from xml.etree import ElementTree |
917 |
ElementTree.ElementTree(xml).write(path) |
918 |
matches = [file_name + '.xml']
|
919 |
|
920 |
if matches and os.path.exists(id2_image_file): |
921 |
try:
|
922 |
symbols = {} |
923 |
|
924 |
drawing = Drawing(str(uuid.uuid4()), file_name + ".PNG", None) |
925 |
_image = drawing.image#QImage(id2_image_file, "PNG")
|
926 |
bytesPerLine = _image.shape[1]
|
927 |
image = QImage(_image.data, _image.shape[1], _image.shape[0], bytesPerLine, QImage.Format_Indexed8) |
928 |
autocad_xml = parse(autocad_xml_path) |
929 |
|
930 |
autocad_xml_root = autocad_xml.getroot() |
931 |
|
932 |
id2_bbox = self.get_contents_size_from_image(id2_image_file)
|
933 |
|
934 |
for blk_tbl_record in autocad_xml_root.iter('AcDbBlockTableRecord'): |
935 |
if blk_tbl_record.attrib['Name'].upper() != '*Model_Space'.upper(): |
936 |
continue
|
937 |
|
938 |
min_values = [float(token) for token in |
939 |
blk_tbl_record.attrib['MinExtents'].strip('()').split(',')] |
940 |
max_values = [float(token) for token in |
941 |
blk_tbl_record.attrib['MaxExtents'].strip('()').split(',')] |
942 |
autocad_bbox = [min_values[0], min_values[1], |
943 |
max_values[0] - min_values[0], max_values[1] - min_values[1]] |
944 |
|
945 |
if self.ui.checkBoxAuto.isChecked(): |
946 |
scale_x = id2_bbox[2] / autocad_bbox[2] |
947 |
scale_y = id2_bbox[3] / autocad_bbox[3] |
948 |
self.scales = [scale_x, scale_y]
|
949 |
offsets = [id2_bbox[0] - autocad_bbox[0] * scale_x, id2_bbox[3] + id2_bbox[1]] |
950 |
self.offsets = offsets + [autocad_bbox[1]] |
951 |
else:
|
952 |
self.scales = [self.ui.doubleSpinBox.value(), self.ui.doubleSpinBox_2.value()] |
953 |
self.offsets = [self.ui.spinBoxTextX.value(), self.ui.spinBoxTextY.value(), id2_bbox[5]] |
954 |
|
955 |
for blk_ref in blk_tbl_record.iter('AcDbBlockReference'): |
956 |
node = self.symbol_info(blk_ref)
|
957 |
if node[0] not in symbols: |
958 |
symbols[node[0]] = node
|
959 |
|
960 |
dialog = QSymbolRegiDataListDialog(self, image, symbols)
|
961 |
create = dialog.showDialog() |
962 |
if create:
|
963 |
App.mainWnd().symbolTreeWidget.initSymbolTreeView() |
964 |
|
965 |
'''
|
966 |
for key, value in symbols.items():
|
967 |
symbolEditorDialog = QSymbolEditorDialog(self, image.copy(math.floor(value[2][0]), math.floor(value[2][1]), \
|
968 |
math.ceil(value[3] + 1), math.ceil(value[4] + 1)), \
|
969 |
AppDocData.instance().getCurrentProject(), value[1], False)
|
970 |
(isAccepted, _, _, _, _) = symbolEditorDialog.showDialog()
|
971 |
|
972 |
if not isAccepted:
|
973 |
reply = QMessageBox.question(self, self.tr('Stop?'), self.tr('Do you want to stop registering symbols?'), QMessageBox.Yes, QMessageBox.Cancel)
|
974 |
if reply == QMessageBox.Yes:
|
975 |
break
|
976 |
'''
|
977 |
|
978 |
except Exception as ex: |
979 |
from App import App |
980 |
from AppDocData import MessageType |
981 |
|
982 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
|
983 |
f"{sys.exc_info()[-1].tb_lineno}"
|
984 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
985 |
else:
|
986 |
from App import App |
987 |
from AppDocData import MessageType |
988 |
|
989 |
message = 'There is no xml file'
|
990 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
991 |
|
992 |
def get_contents_size_from_image(self, img_file_path: str) -> list: |
993 |
"""get actual size of image from image file"""
|
994 |
from AppDocData import AppDocData |
995 |
import cv2 |
996 |
|
997 |
min_x, min_y, max_x, max_y, width, height = None, None, None, None, None, None |
998 |
|
999 |
img = AppDocData.my_imread(file_path=img_file_path) |
1000 |
_width = img.shape[1]
|
1001 |
_height = img.shape[0]
|
1002 |
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
1003 |
img = cv2.bitwise_not(img) # background should be 'BLACK'
|
1004 |
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
1005 |
for cnt in contours: |
1006 |
x, y, width, height = cv2.boundingRect(cnt) |
1007 |
min_x = x if not min_x else min(x, min_x) |
1008 |
min_y = y if not min_y else min(y, min_y) |
1009 |
max_x = x + width if not max_x else max(x + width, max_x) |
1010 |
max_y = y + height if not max_y else max(y + height, max_y) |
1011 |
|
1012 |
del img
|
1013 |
|
1014 |
return min_x, min_y, max_x - min_x, max_y - min_y, _width, _height
|
1015 |
|
1016 |
def on_import_autocad(self): |
1017 |
"""
|
1018 |
import line, text and symbol from autocad
|
1019 |
@return: None
|
1020 |
"""
|
1021 |
|
1022 |
import XmlGenerator as xg |
1023 |
|
1024 |
if not self._dwgs: |
1025 |
QMessageBox.information(self, self.tr('Information'), self.tr('There is no selected file(s)')) |
1026 |
return
|
1027 |
|
1028 |
app_doc_data = AppDocData.instance() |
1029 |
project = app_doc_data.getCurrentProject() |
1030 |
|
1031 |
temp_path, drawing_path = project.getTempPath(), project.getDrawingFilePath() |
1032 |
id2_xml_files = [f for f in os.listdir(temp_path) if os.path.isfile(os.path.join(temp_path, f)) and |
1033 |
(os.path.splitext(f)[1].upper() == '.XML')] |
1034 |
|
1035 |
self.text_scale = self.ui.doubleSpinBoxScale.value() |
1036 |
|
1037 |
"""get exclude layers mapping"""
|
1038 |
exclude_layers = [] |
1039 |
model = self.ui.listViewExcludeLayers.model()
|
1040 |
for row in range(model.rowCount()): |
1041 |
item = model.itemFromIndex(model.index(row, 0))
|
1042 |
if item.checkState() == Qt.Checked:
|
1043 |
exclude_layers.append(item.text()) |
1044 |
|
1045 |
"""get items to be converted"""
|
1046 |
will_be_converted_items = [] |
1047 |
if self.ui.checkBoxLine.checkState() == Qt.Checked: |
1048 |
will_be_converted_items.append('Line')
|
1049 |
if self.ui.checkBoxText.checkState() == Qt.Checked: |
1050 |
will_be_converted_items.append('Text')
|
1051 |
if self.ui.checkBoxSymbol.checkState() == Qt.Checked: |
1052 |
will_be_converted_items.append('Symbol')
|
1053 |
|
1054 |
mapping_configs = app_doc_data.getConfigs(section='Symbol Mapping')
|
1055 |
|
1056 |
for _file in self._dwgs: |
1057 |
file_name = os.path.splitext(os.path.basename(_file))[0]
|
1058 |
id2_image_file = os.path.join(drawing_path, file_name + '.png')
|
1059 |
autocad_xml_path = os.path.join(os.path.dirname(_file), os.path.splitext(os.path.basename(_file))[0] + '.xml') |
1060 |
matches = [id2_xml_file for id2_xml_file in id2_xml_files if id2_xml_file.replace(file_name, '').upper() == '.XML'] |
1061 |
|
1062 |
if not matches: |
1063 |
path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
|
1064 |
img = AppDocData.my_imread(file_path=id2_image_file) |
1065 |
_width = img.shape[1]
|
1066 |
_height = img.shape[0]
|
1067 |
xml, result = xg.write_to_xml(path, _width, _height, [], []) |
1068 |
if xml:
|
1069 |
from xml.etree import ElementTree |
1070 |
ElementTree.ElementTree(xml).write(path) |
1071 |
matches = [file_name + '.xml']
|
1072 |
|
1073 |
if matches and os.path.exists(id2_image_file): |
1074 |
try:
|
1075 |
layers, line_types, symbols = [], [], [] |
1076 |
autocad_xml = parse(autocad_xml_path) |
1077 |
|
1078 |
"""parse layer, line type and symbol"""
|
1079 |
autocad_xml_root = autocad_xml.getroot() |
1080 |
for layer_tbl_record in autocad_xml_root.iter('AcDbLayerTableRecord'): |
1081 |
layer_name = layer_tbl_record.attrib['Name']
|
1082 |
line_type_oid = layer_tbl_record.attrib['LinetypeObjectId']
|
1083 |
layers.append([layer_name, line_type_oid]) |
1084 |
|
1085 |
for line_type_tbl_record in autocad_xml_root.iter('AcDbLinetypeTableRecord'): |
1086 |
line_type_oid = line_type_tbl_record.attrib['ObjectId']
|
1087 |
line_type_name = line_type_tbl_record.attrib['Name']
|
1088 |
line_types.append([line_type_oid, line_type_name]) |
1089 |
|
1090 |
'''
|
1091 |
for blk_ref_record in autocad_xml_root.iter('AcDbBlockReference'):
|
1092 |
blk_ref_handle = blk_ref_record.attrib['Handle']
|
1093 |
blk_ref_name = blk_ref_record.attrib['Name']
|
1094 |
symbols.append([blk_ref_handle, blk_ref_name])
|
1095 |
'''
|
1096 |
"""up to here"""
|
1097 |
|
1098 |
id2_xml_path = os.path.join(temp_path, matches[0])
|
1099 |
id2_xml = parse(id2_xml_path) |
1100 |
id2_xml_root = id2_xml.getroot() |
1101 |
|
1102 |
#id2_bbox = [0, 0, 9600, 6781]
|
1103 |
id2_bbox = self.get_contents_size_from_image(id2_image_file)
|
1104 |
|
1105 |
if 'Symbol' in will_be_converted_items: |
1106 |
symbols_node = id2_xml_root.find(xg.SYMBOL_LIST_NODE_NAME) |
1107 |
if symbols_node:
|
1108 |
symbols = symbols_node.findall('SYMBOL')
|
1109 |
# remove only converted symbol nodes
|
1110 |
for symbol in symbols: |
1111 |
if 'Converted' in symbol.attrib and symbol.attrib['Converted'] == str(True): |
1112 |
symbols_node.remove(symbol) |
1113 |
graphics_node = id2_xml_root.find(xg.GRAPHIC_NODE_NAME) |
1114 |
graphics_node.clear() |
1115 |
|
1116 |
if 'Text' in will_be_converted_items: |
1117 |
"""remove texts from id2 xml file"""
|
1118 |
textInfo = id2_xml_root.find(xg.TEXT_INFO_LIST_NODE_NAME) |
1119 |
textInfo.clear() |
1120 |
|
1121 |
noteInfo = id2_xml_root.find(xg.NOTE_TEXT_INFO_LIST_NOTE_NAME) |
1122 |
noteInfo.clear() |
1123 |
|
1124 |
lineNoInfo = id2_xml_root.find(xg.LINE_NOS_NODE_NAME) |
1125 |
lineNoInfo.clear() |
1126 |
"""up to here"""
|
1127 |
|
1128 |
if 'Line' in will_be_converted_items: |
1129 |
"""remove lines from id2 xml file"""
|
1130 |
line_infos = id2_xml_root.find(xg.LINE_INFOS_NODE_NAME) |
1131 |
line_infos.clear() |
1132 |
"""up to here"""
|
1133 |
|
1134 |
"""remove unknowns from id2 xml file"""
|
1135 |
unknowns = id2_xml_root.find(xg.UNKNOWNS_NODE_NAME) |
1136 |
unknowns.clear() |
1137 |
"""up to here"""
|
1138 |
|
1139 |
"""add text, line and symbol from autocad file to id2 xml file"""
|
1140 |
for blk_tbl_record in autocad_xml_root.iter('AcDbBlockTableRecord'): |
1141 |
if blk_tbl_record.attrib['Name'].upper() != '*Model_Space'.upper(): |
1142 |
continue
|
1143 |
|
1144 |
min_values = [float(token) for token in |
1145 |
blk_tbl_record.attrib['MinExtents'].strip('()').split(',')] |
1146 |
max_values = [float(token) for token in |
1147 |
blk_tbl_record.attrib['MaxExtents'].strip('()').split(',')] |
1148 |
autocad_bbox = [min_values[0], min_values[1], |
1149 |
max_values[0] - min_values[0], max_values[1] - min_values[1]] |
1150 |
|
1151 |
if self.ui.checkBoxAuto.isChecked(): |
1152 |
scale_x = id2_bbox[2] / autocad_bbox[2] |
1153 |
scale_y = id2_bbox[3] / autocad_bbox[3] |
1154 |
self.scales = [scale_x, scale_y]
|
1155 |
offsets = [id2_bbox[0] - autocad_bbox[0] * scale_x, id2_bbox[3] + id2_bbox[1]] |
1156 |
self.offsets = offsets + [autocad_bbox[1]] |
1157 |
else:
|
1158 |
self.scales = [self.ui.doubleSpinBox.value(), self.ui.doubleSpinBox_2.value()] |
1159 |
self.offsets = [self.ui.spinBoxTextX.value(), self.ui.spinBoxTextY.value(), id2_bbox[5]] |
1160 |
|
1161 |
if 'Text' in will_be_converted_items: |
1162 |
for record in blk_tbl_record.iter('AcDbText'): |
1163 |
if record.attrib['Layer'] not in exclude_layers: |
1164 |
node = self.text_to_xml(record)
|
1165 |
if node:
|
1166 |
textInfo.append(node) |
1167 |
|
1168 |
for blk_ref in blk_tbl_record.iter('AcDbBlockReference'): |
1169 |
if 'Symbol' in will_be_converted_items: |
1170 |
if blk_ref.attrib['Layer'] not in exclude_layers: |
1171 |
node = None
|
1172 |
block_name = blk_ref.attrib['Name']
|
1173 |
if block_name.split('+')[0] == 'Graphic': |
1174 |
node = self.graphic_to_xml(blk_ref)
|
1175 |
if node:
|
1176 |
graphics_node.append(node) |
1177 |
else:
|
1178 |
node = self.symbol_to_xml(blk_ref, mapping_configs)
|
1179 |
if node:
|
1180 |
symbols_node.append(node) |
1181 |
|
1182 |
if 'Text' in will_be_converted_items: |
1183 |
#angle = round(float(blk_ref.attrib['Angle']), 2)
|
1184 |
for record in blk_ref.iter('AcDbAttribute'): |
1185 |
node = self.text_to_xml(record)
|
1186 |
if node:
|
1187 |
textInfo.append(node) |
1188 |
|
1189 |
if 'Line' in will_be_converted_items: |
1190 |
for record in blk_tbl_record.iter('AcDbLine'): |
1191 |
if record.attrib['Layer'] not in exclude_layers: |
1192 |
nodes = self.lines_to_xml(layers, line_types, record)
|
1193 |
if nodes:
|
1194 |
for node in nodes: |
1195 |
line_infos.append(node) |
1196 |
|
1197 |
for record in blk_tbl_record.iter('AcDbArc'): |
1198 |
if record.attrib['Layer'] not in exclude_layers: |
1199 |
nodes = self.lines_to_xml(layers, line_types, record)
|
1200 |
if nodes:
|
1201 |
for node in nodes: |
1202 |
line_infos.append(node) |
1203 |
|
1204 |
for record in blk_tbl_record.iter('AcDbPolyline'): |
1205 |
if record.attrib['Layer'] not in exclude_layers: |
1206 |
nodes = self.lines_to_xml(layers, line_types, record)
|
1207 |
if nodes:
|
1208 |
for node in nodes: |
1209 |
line_infos.append(node) |
1210 |
|
1211 |
id2_xml.write(id2_xml_path, encoding="utf-8", xml_declaration=True) |
1212 |
"""up to here"""
|
1213 |
|
1214 |
except Exception as ex: |
1215 |
from App import App |
1216 |
from AppDocData import MessageType |
1217 |
|
1218 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
|
1219 |
f"{sys.exc_info()[-1].tb_lineno}"
|
1220 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1221 |
else:
|
1222 |
from App import App |
1223 |
from AppDocData import MessageType |
1224 |
|
1225 |
message = 'There is no xml file'
|
1226 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1227 |
|
1228 |
QMessageBox.information(self, self.tr('Information'), self.tr('Importing finished!'), |
1229 |
QMessageBox.Close) |
1230 |
|
1231 |
def symbol_info(self, blk_ref_node): |
1232 |
"""try to convert block reference element to id2 xml"""
|
1233 |
import symbol |
1234 |
|
1235 |
try:
|
1236 |
symbolTypes = [symbolType[2] for symbolType in AppDocData.instance().getSymbolTypeList()] |
1237 |
_name = blk_ref_node.attrib['Name']
|
1238 |
if '+' in _name and _name.split('+')[0] in symbolTypes: |
1239 |
name = _name.split('+')[1] |
1240 |
type = _name.split('+')[0] |
1241 |
elif '+' in _name: |
1242 |
name = _name.split('+')[1] |
1243 |
type = 'Valves' if _name.split('+')[0] != 'Equipment' else 'Vessels' |
1244 |
else:
|
1245 |
name = _name |
1246 |
type = 'Valves'
|
1247 |
_origin = self.convert_to_image_coords([float(blk_ref_node.attrib['X']), float(blk_ref_node.attrib['Y'])]) |
1248 |
|
1249 |
"""check if maxtents or minextents attribute exists"""
|
1250 |
if 'MaxExtents' not in blk_ref_node.attrib or 'MinExtents' not in blk_ref_node.attrib: |
1251 |
return None |
1252 |
|
1253 |
min_extents, max_extents = None, None |
1254 |
tokens = blk_ref_node.attrib['MaxExtents'].strip('()').split(',') |
1255 |
if 3 == len(tokens): |
1256 |
max_extents = self.convert_to_image_coords([float(tokens[0]), float(tokens[1])]) |
1257 |
|
1258 |
tokens = blk_ref_node.attrib['MinExtents'].strip('()').split(',') |
1259 |
if 3 == len(tokens): |
1260 |
min_extents = self.convert_to_image_coords([float(tokens[0]), float(tokens[1])]) |
1261 |
|
1262 |
_height = math.ceil(abs(max_extents[1] - min_extents[1])) |
1263 |
_width = math.ceil(abs(max_extents[0] - min_extents[0])) |
1264 |
|
1265 |
loc = [min(min_extents[0], max_extents[0]), min(min_extents[1], max_extents[1])] |
1266 |
|
1267 |
origin = [math.ceil(_origin[0] - loc[0]), math.ceil(_origin[1] - loc[1])] |
1268 |
origin[0] = 0 if origin[0] <= 0 else (_width if origin[0] > _width else origin[0]) |
1269 |
origin[1] = 0 if origin[1] <= 0 else (_height if origin[1] > _height else origin[1]) |
1270 |
|
1271 |
points = [] |
1272 |
if blk_ref_node.attrib['Nodes']: |
1273 |
_points = blk_ref_node.attrib['Nodes'].replace('(', '').replace(')', '').split('/') |
1274 |
if _points:
|
1275 |
for _point in _points: |
1276 |
_point = _point.split(',')
|
1277 |
point = self.convert_to_image_coords([float(_point[0]), float(_point[1])]) |
1278 |
point[0] = 0 if math.ceil(point[0] - loc[0]) <= 0 else (_width if math.ceil(point[0] - loc[0]) > _width else math.ceil(point[0] - loc[0])) |
1279 |
point[1] = 0 if math.ceil(point[1] - loc[1]) <= 0 else (_height if math.ceil(point[1] - loc[1]) > _height else math.ceil(point[1] - loc[1])) |
1280 |
points.append(point) |
1281 |
|
1282 |
strPoints = [] |
1283 |
for point in points: |
1284 |
strPoint = 'AUTO,' + str(point[0]) + ',' + str(point[1]) + ',0,None,X,Secondary' |
1285 |
strPoints.append(strPoint) |
1286 |
|
1287 |
ret = symbol.SymbolBase(name, type, 0.75, 0, 1, 0, 0, 0, \ |
1288 |
"{},{}".format(origin[0], origin[1]), \ |
1289 |
'/'.join(strPoints), \
|
1290 |
'None', '', 0, 0, -1, \ |
1291 |
iType=-2, detectFlip=0, text_area='') |
1292 |
|
1293 |
#symbolEditorDialog = QSymbolEditorDialog(self, image.copy(math.floor(loc[0]), math.floor(int(loc[1])), math.ceil(_width + 1), math.ceil(_height + 1)), \
|
1294 |
# AppDocData.instance().getCurrentProject(), ret, False)
|
1295 |
#(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
|
1296 |
|
1297 |
return [_name, ret, loc, _width, _height]
|
1298 |
except Exception as ex: |
1299 |
from App import App |
1300 |
from AppDocData import MessageType |
1301 |
|
1302 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
|
1303 |
f"{sys.exc_info()[-1].tb_lineno}"
|
1304 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1305 |
|
1306 |
return None |
1307 |
|
1308 |
def convert_to_image_coords(self, pt): |
1309 |
"""convert autocad coordinates to image coordinates"""
|
1310 |
if self.ui.checkBoxAuto.isChecked(): |
1311 |
return [pt[0] * self.scales[0] + self.offsets[0], (self.offsets[2] - pt[1]) * self.scales[1] + self.offsets[1]] |
1312 |
else:
|
1313 |
return [pt[0] * self.scales[0] + self.offsets[0], self.offsets[2] - pt[1] * self.scales[1] + self.offsets[1]] |
1314 |
|
1315 |
def graphic_to_xml(self, blk_ref_node): |
1316 |
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree |
1317 |
|
1318 |
try:
|
1319 |
node = Element('GRAPHIC')
|
1320 |
uidNode = Element('UID')
|
1321 |
uidNode.text = str(uuid.uuid4())
|
1322 |
node.append(uidNode) |
1323 |
|
1324 |
nameNode = Element('NAME')
|
1325 |
nameNode.text = blk_ref_node.attrib['Name']
|
1326 |
node.append(nameNode) |
1327 |
|
1328 |
min_extents, max_extents = None, None |
1329 |
tokens = blk_ref_node.attrib['MaxExtents'].strip('()').split(',') |
1330 |
if 3 == len(tokens): |
1331 |
max_extents = self.convert_to_image_coords([float(tokens[0]), float(tokens[1])]) |
1332 |
|
1333 |
tokens = blk_ref_node.attrib['MinExtents'].strip('()').split(',') |
1334 |
if 3 == len(tokens): |
1335 |
min_extents = self.convert_to_image_coords([float(tokens[0]), float(tokens[1])]) |
1336 |
|
1337 |
locNode1 = Element('LOCATION1')
|
1338 |
locNode1.text = '{},{}'.format(min_extents[0], min_extents[1]) |
1339 |
node.append(locNode1) |
1340 |
|
1341 |
locNode2 = Element('LOCATION2')
|
1342 |
locNode2.text = '{},{}'.format(max_extents[0], max_extents[1]) |
1343 |
node.append(locNode2) |
1344 |
|
1345 |
except Exception as ex: |
1346 |
from App import App |
1347 |
from AppDocData import MessageType |
1348 |
|
1349 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
1350 |
sys.exc_info()[-1].tb_lineno)
|
1351 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1352 |
|
1353 |
return None |
1354 |
|
1355 |
return node
|
1356 |
|
1357 |
def symbol_to_xml(self, blk_ref_node, mapping_configs: list) -> str: |
1358 |
"""try to convert block reference element to id2 xml"""
|
1359 |
from SymbolSvgItem import SymbolSvgItem |
1360 |
|
1361 |
try:
|
1362 |
name = blk_ref_node.attrib['Name']
|
1363 |
origin = self.convert_to_image_coords([float(blk_ref_node.attrib['X']), float(blk_ref_node.attrib['Y'])]) |
1364 |
flip = float(blk_ref_node.attrib['ScaleFactors'].replace('(', '').replace(')', '').split(',')[0]) |
1365 |
flip = 1 if flip < 0 else 0 |
1366 |
if flip == 0: |
1367 |
angle = round(2 * math.pi - float(blk_ref_node.attrib['Angle']), 2) |
1368 |
else:
|
1369 |
angle = round(float(blk_ref_node.attrib['Angle']), 2) |
1370 |
|
1371 |
if angle > 6.28: |
1372 |
angle = angle - 2 * math.pi
|
1373 |
elif angle == 6.28: |
1374 |
angle = 0.0
|
1375 |
|
1376 |
"""check if maxtents or minextents attribute exists"""
|
1377 |
if 'MaxExtents' not in blk_ref_node.attrib or 'MinExtents' not in blk_ref_node.attrib: |
1378 |
return None |
1379 |
|
1380 |
min_extents, max_extents = None, None |
1381 |
tokens = blk_ref_node.attrib['MaxExtents'].strip('()').split(',') |
1382 |
if 3 == len(tokens): |
1383 |
max_extents = self.convert_to_image_coords([float(tokens[0]), float(tokens[1])]) |
1384 |
|
1385 |
tokens = blk_ref_node.attrib['MinExtents'].strip('()').split(',') |
1386 |
if 3 == len(tokens): |
1387 |
min_extents = self.convert_to_image_coords([float(tokens[0]), float(tokens[1])]) |
1388 |
|
1389 |
_height = abs(max_extents[1] - min_extents[1]) |
1390 |
_width = abs(max_extents[0] - min_extents[0]) |
1391 |
|
1392 |
'''
|
1393 |
allowed_error = 0.01
|
1394 |
if abs(angle - 1.57) < allowed_error:
|
1395 |
_height, _width = _width, _height
|
1396 |
#origin[0], origin[1] = origin[0] - _width, origin[1] - _height + _width
|
1397 |
elif abs(angle - 4.71) < allowed_error:
|
1398 |
_height, _width = _width, _height
|
1399 |
#origin[0], origin[1] = origin[0] - _width, origin[1] + _height - _width
|
1400 |
'''
|
1401 |
|
1402 |
uid = None
|
1403 |
for config in mapping_configs: |
1404 |
if name in config.value.split(','): |
1405 |
uid = config.key |
1406 |
break
|
1407 |
if uid:
|
1408 |
app_doc_data = AppDocData.instance() |
1409 |
symbol = app_doc_data.getSymbolByQuery('UID', uid)
|
1410 |
svg_file_path = os.path.join(app_doc_data.getCurrentProject().getSvgFilePath(), symbol.getType(), |
1411 |
symbol.getName() + '.svg')
|
1412 |
|
1413 |
item = SymbolSvgItem.createItem(symbol.getType(), symbol.getName(), path=svg_file_path) |
1414 |
loc = [min(min_extents[0], max_extents[0]), min(min_extents[1], max_extents[1])] |
1415 |
item.buildItem(name, symbol.getType(), angle, loc, (_width, _height), origin, |
1416 |
connPts=symbol.parse_connection_pts(origin), parentSymbol=None, childSymbol=None, |
1417 |
hasInstrumentLabel=False, dbUid=uid)
|
1418 |
item.converted = True
|
1419 |
item.flip = flip |
1420 |
|
1421 |
app_doc_data = AppDocData.instance() |
1422 |
for area in app_doc_data.getAreaList(): |
1423 |
if area.contains([origin[0], origin[1]]): |
1424 |
item.area = area.name |
1425 |
break
|
1426 |
|
1427 |
return item.toXml()
|
1428 |
except Exception as ex: |
1429 |
from App import App |
1430 |
from AppDocData import MessageType |
1431 |
|
1432 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
|
1433 |
f"{sys.exc_info()[-1].tb_lineno}"
|
1434 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1435 |
|
1436 |
return None |
1437 |
|
1438 |
def text_to_xml(self, text_node): |
1439 |
"""
|
1440 |
try to convert text element to id2 xml
|
1441 |
@param text_node:
|
1442 |
@param id2_bbox:
|
1443 |
@param autocad_bbox:
|
1444 |
@return:
|
1445 |
"""
|
1446 |
import math |
1447 |
from EngineeringTextItem import QEngineeringTextItem |
1448 |
|
1449 |
try:
|
1450 |
loc = self.convert_to_image_coords([float(text_node.attrib['X']), float(text_node.attrib['Y'])]) |
1451 |
|
1452 |
text = text_node.text |
1453 |
angle = round(float(text_node.attrib['Angle']), 2) |
1454 |
if 'IsMirroredInX' in text_node.attrib and text_node.attrib['IsMirroredInX'] == 'True': |
1455 |
if abs(math.pi * 0.5 - angle) < 0.01 or abs(math.pi * 1.5 - angle) < 0.01: |
1456 |
angle += math.pi |
1457 |
angle = angle - math.pi * 2 if angle > math.pi * 2 else angle |
1458 |
|
1459 |
if 'IsMirroredInY' in text_node.attrib and text_node.attrib['IsMirroredInY'] == 'True': |
1460 |
if abs(angle) < 0.01 or abs(math.pi - angle) < 0.01: |
1461 |
angle += math.pi |
1462 |
angle = angle - math.pi * 2 if angle > math.pi * 2 else angle |
1463 |
|
1464 |
_height = round(float(text_node.attrib['Height']) * self.scales[1]) |
1465 |
loc[1] -= _height
|
1466 |
_width = round(_height * len(text) * self.text_scale) |
1467 |
#_width = round(float(text_node.attrib['Width']))
|
1468 |
|
1469 |
allowed_error = 0.01
|
1470 |
if abs(angle - 1.57) < allowed_error: |
1471 |
_height, _width = _width, _height |
1472 |
loc[0], loc[1] = loc[0] - _width, loc[1] - _height + _width |
1473 |
elif abs(angle - 4.71) < allowed_error: |
1474 |
_height, _width = _width, _height |
1475 |
loc[0], loc[1] = loc[0] - _width, loc[1] + _height - _width |
1476 |
|
1477 |
item = QEngineeringTextItem() |
1478 |
item.setPlainText(text) |
1479 |
item.loc = loc |
1480 |
item.size = (_width, _height) |
1481 |
item.angle = angle |
1482 |
|
1483 |
app_doc_data = AppDocData.instance() |
1484 |
for area in app_doc_data.getAreaList(): |
1485 |
if area.contains([loc[0], loc[1]]): |
1486 |
item.area = area.name |
1487 |
break
|
1488 |
|
1489 |
node = item.toXml() |
1490 |
|
1491 |
return node
|
1492 |
except Exception as ex: |
1493 |
from App import App |
1494 |
from AppDocData import MessageType |
1495 |
|
1496 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
|
1497 |
f"{sys.exc_info()[-1].tb_lineno}"
|
1498 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1499 |
|
1500 |
def lines_to_xml(self, layers: list, line_types: list, line_node) -> list: |
1501 |
"""try to convert line element to id2 xml"""
|
1502 |
from LineTypeConditions import LineTypeConditions |
1503 |
from EngineeringLineItem import QEngineeringLineItem |
1504 |
|
1505 |
def get_line_type(layers: list, line_types: list, layer_name: str, line_type: str) -> str: |
1506 |
"""return line type"""
|
1507 |
|
1508 |
'''
|
1509 |
res = line_type
|
1510 |
if line_type.upper() == 'ByLayer'.upper():
|
1511 |
matches = [layer for layer in layers if layer[0] == layer_name]
|
1512 |
if matches:
|
1513 |
line_type_oid = matches[0][1]
|
1514 |
matches = [line_node for line_node in line_types if line_node[0] == line_type_oid]
|
1515 |
if matches:
|
1516 |
res = matches[0][1]
|
1517 |
'''
|
1518 |
res = layer_name |
1519 |
|
1520 |
return res
|
1521 |
|
1522 |
try:
|
1523 |
pts = [] |
1524 |
for vertex in line_node.iter('Vertex'): |
1525 |
pts.append(self.convert_to_image_coords([float(vertex.attrib['X']), float(vertex.attrib['Y'])])) |
1526 |
|
1527 |
# append first point if 'Closed' attribute is True
|
1528 |
if 'Closed' in line_node.attrib and line_node.attrib['Closed'].upper() == 'True'.upper(): |
1529 |
pts.append(pts[0])
|
1530 |
|
1531 |
"""get id2 line type uid"""
|
1532 |
line_type, line_type_cond = get_line_type(layers, line_types, line_node.attrib['Layer'],
|
1533 |
line_node.attrib['Linetype']), None |
1534 |
model = self.ui.treeViewLineType.model()
|
1535 |
for row in range(model.rowCount()): |
1536 |
parent_index = model.index(row, 0)
|
1537 |
id2_line_type = model.itemFromIndex(parent_index).text() |
1538 |
|
1539 |
child_count = model.rowCount(parent_index) |
1540 |
for child_row in range(child_count): |
1541 |
child_index = model.index(child_row, 1, parent_index)
|
1542 |
autocad_line_type = model.itemFromIndex(child_index).text() |
1543 |
if autocad_line_type == line_type:
|
1544 |
matches = [item for item in LineTypeConditions.items() if item.name == id2_line_type] |
1545 |
if matches:
|
1546 |
line_type_cond = matches[0]
|
1547 |
break
|
1548 |
"""up to here"""
|
1549 |
|
1550 |
nodes = [] |
1551 |
for idx in range(len(pts) - 1): |
1552 |
start, end = pts[idx], pts[idx + 1]
|
1553 |
dx, dy = end[0] - start[0], end[1] - start[1] |
1554 |
|
1555 |
"""check if length is zero"""
|
1556 |
length = dx*dx + dy*dy |
1557 |
if length == 0: |
1558 |
continue
|
1559 |
|
1560 |
item = QEngineeringLineItem(vertices=[start, end], thickness=5)
|
1561 |
|
1562 |
# import lines which is horizontal or vertical
|
1563 |
#angle = math.degrees(item.angle())
|
1564 |
#if not ((-5 < angle < 5) or (85 < angle < 95) or (175 < angle < 185) or (355 < angle < 365)):
|
1565 |
# continue
|
1566 |
|
1567 |
item.area = 'Drawing'
|
1568 |
|
1569 |
if line_type_cond:
|
1570 |
item.lineType = line_type_cond.name |
1571 |
node = item.toXml() |
1572 |
nodes.append(node) |
1573 |
|
1574 |
return nodes
|
1575 |
except Exception as ex: |
1576 |
from App import App |
1577 |
from AppDocData import MessageType |
1578 |
|
1579 |
message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
|
1580 |
f"{sys.exc_info()[-1].tb_lineno}"
|
1581 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1582 |
|
1583 |
return None |
1584 |
|
1585 |
def close(self): |
1586 |
QDialog.reject(self)
|