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