hytos / DTI_PID / DTI_PID / MainWindow.py @ d9cbc4d3
이력 | 보기 | 이력해설 | 다운로드 (30.5 KB)
1 |
# coding: utf-8
|
---|---|
2 |
|
3 |
import sys |
4 |
import os |
5 |
import cv2 |
6 |
|
7 |
from PyQt5.QtCore import * |
8 |
from PyQt5.QtGui import * |
9 |
from PyQt5.QtWidgets import * |
10 |
from PyQt5.QtSvg import * |
11 |
|
12 |
from PIL import Image |
13 |
|
14 |
import DTI_PID_UI |
15 |
import QtImageViewer |
16 |
from SingletonInstance import SingletonInstane |
17 |
|
18 |
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands') |
19 |
import CreateCommand |
20 |
import CropCommand |
21 |
import AreaOcrCommand |
22 |
import CreateSymbolCommand |
23 |
|
24 |
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Shapes') |
25 |
import QGraphicsPolylineItem |
26 |
from QEngineeringLineItem import QEngineeringLineItem |
27 |
from SymbolSvgItem import SymbolSvgItem |
28 |
from QGraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
29 |
from QEngineeringTextItem import QEngineeringTextItem |
30 |
from QEngineeringLineNoTextItem import QEngineeringLineNoTextItem |
31 |
from QEngineeringNoteItem import QEngineeringNoteItem |
32 |
from QEngineeringSizeTextItem import QEngineeringSizeTextItem |
33 |
from AppDocData import AppDocData |
34 |
import QDirTreeWidget, QPropertyTableWidget |
35 |
import QSymbolEditorDialog |
36 |
import QResultTreeWidget |
37 |
import QResultPropertyTableWidget |
38 |
from TextItemFactory import TextItemFactory |
39 |
|
40 |
class Worker(QObject): |
41 |
from PyQt5.QtCore import QThread |
42 |
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout |
43 |
import sys |
44 |
from DTI_PID import executeRecognition |
45 |
|
46 |
finished = pyqtSignal() |
47 |
intReady = pyqtSignal(int)
|
48 |
|
49 |
#pyqtSlot()
|
50 |
def procCounter(self): # A slot takes no params |
51 |
from DTI_PID import executeRecognition |
52 |
|
53 |
try:
|
54 |
self.xmlPath = executeRecognition(self.path, self.listWidget) |
55 |
self.finished.emit()
|
56 |
except Exception as ex: |
57 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
58 |
|
59 |
class MainWindow(QMainWindow, DTI_PID_UI.Ui_MainWindow, SingletonInstane): |
60 |
'''
|
61 |
@brief initialize
|
62 |
@author
|
63 |
@date
|
64 |
@history humkyung 2018.04.12 add splitter widget
|
65 |
Jeongwoo 2018.04.27 Add Signal/Slot Connection 'noteNoSingleClicked'
|
66 |
'''
|
67 |
def __init__(self): |
68 |
super(self.__class__, self).__init__() |
69 |
self.setupUi(self) |
70 |
|
71 |
project = AppDocData.instance().getCurrentProject() |
72 |
_translate = QCoreApplication.translate |
73 |
self.setWindowTitle(_translate("Digital P&ID - {}".format(project.name), "Digital P&ID - {}".format(project.name))) |
74 |
|
75 |
self.lineComboBox = QComboBox(self.toolBar) |
76 |
self.lineComboBox.addItem('Primary Line') |
77 |
self.lineComboBox.addItem('Secondary Line') |
78 |
#self.lineComboBox.addItem('Utility Line')
|
79 |
self.toolBar.insertWidget(self.actionValidate, self.lineComboBox) |
80 |
self.toolBar.insertSeparator(self.actionValidate) |
81 |
self.graphicsView = QtImageViewer.QtImageViewer()
|
82 |
self.graphicsView.setParent(self.centralwidget) |
83 |
self.graphicsView.useDefaultCommand() ##### USE DEFAULT COMMAND |
84 |
|
85 |
self.verticalLayout.addWidget(self.graphicsView) |
86 |
|
87 |
# Add Custom TreeWidget
|
88 |
self.dirTreeWidget = QDirTreeWidget.QDirTreeWidget()
|
89 |
self.dirTreeWidget.header().hide()
|
90 |
self.symbolTabVerticalLayout.addWidget(self.dirTreeWidget) |
91 |
|
92 |
# Add Custom Property TableWidget
|
93 |
self.propertyTableWidget = QPropertyTableWidget.QPropertyTableWidget()
|
94 |
self.symbolTabVerticalLayout.addWidget(self.propertyTableWidget) |
95 |
self.dirTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol) |
96 |
# add splitter widget
|
97 |
splitter = QSplitter(Qt.Vertical) |
98 |
splitter.addWidget(self.dirTreeWidget)
|
99 |
splitter.addWidget(self.propertyTableWidget)
|
100 |
self.symbolTabVerticalLayout.addWidget(splitter)
|
101 |
# up to here
|
102 |
|
103 |
# Add Custom Result Tree Widget (Symbol Explorer)
|
104 |
self.resultTreeWidget = QResultTreeWidget.QResultTreeWidget(self.graphicsView) |
105 |
self.resultTreeWidget.header().hide()
|
106 |
self.symbolExplorerVerticalLayout.addWidget(self.resultTreeWidget) |
107 |
|
108 |
# Add Empty Widget
|
109 |
self.resultPropertyTableWidget = QResultPropertyTableWidget.QResultPropertyTableWidget()
|
110 |
self.symbolExplorerVerticalLayout.addWidget(self.resultPropertyTableWidget) |
111 |
self.resultTreeWidget.singleClicked.connect(self.resultPropertyTableWidget.getClickedSymbol) |
112 |
self.resultTreeWidget.noteNoSingleClicked.connect(self.resultPropertyTableWidget.getClickedNote) |
113 |
# add splitter widget
|
114 |
splitter = QSplitter(Qt.Vertical) |
115 |
splitter.addWidget(self.resultTreeWidget)
|
116 |
splitter.addWidget(self.resultPropertyTableWidget)
|
117 |
self.symbolExplorerVerticalLayout.addWidget(splitter)
|
118 |
# up to here
|
119 |
|
120 |
# connect signals and slots
|
121 |
self.actionClose.triggered.connect(self.close) |
122 |
self.actionOpen.triggered.connect(self.openImageDrawing) |
123 |
#self.actionEqpNozzle.triggered.connect(self.connectEqpNozzle)
|
124 |
self.actionLine.triggered.connect(self.createLine) |
125 |
self.actionRecognition.triggered.connect(self.recognize) |
126 |
self.actionLineRecognition.triggered.connect(self.recognizeLine) |
127 |
self.actionArea.triggered.connect(self.areaConfiguration) |
128 |
self.actionConfiguration.triggered.connect(self.configuration) |
129 |
self.actionOCR.triggered.connect(self.areaOcr) |
130 |
self.actionGenerateOutput.triggered.connect(self.generateOutput) |
131 |
self.pushButtonCreateSymbol.clicked.connect(self.createSymbol) |
132 |
self.actionEquipment.triggered.connect(self.createEquipment) |
133 |
self.actionNozzle.triggered.connect(self.createNozzle) |
134 |
self.graphicsView.scene.changed.connect(lambda: self.resultTreeWidget.sceneChanged(self.graphicsView.scene.items())) |
135 |
|
136 |
'''
|
137 |
@brief Create Equipment
|
138 |
@author Jeongwoo
|
139 |
@date 18.05.03
|
140 |
'''
|
141 |
def createEquipment(self): |
142 |
if not self.graphicsView.hasImage(): |
143 |
self.showImageSelectionMessageBox()
|
144 |
return
|
145 |
if self.actionEquipment.isChecked(): |
146 |
self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.resultTreeWidget) |
147 |
else:
|
148 |
self.graphicsView.useDefaultCommand()
|
149 |
|
150 |
|
151 |
'''
|
152 |
@brief Create Nozzle
|
153 |
@author Jeongwoo
|
154 |
@date 18.05.03
|
155 |
'''
|
156 |
def createNozzle(self): |
157 |
if not self.graphicsView.hasImage(): |
158 |
self.showImageSelectionMessageBox()
|
159 |
return
|
160 |
if self.actionNozzle.isChecked(): |
161 |
self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.resultTreeWidget) |
162 |
else:
|
163 |
self.graphicsView.useDefaultCommand()
|
164 |
|
165 |
'''
|
166 |
@brief Area OCR
|
167 |
@author Jeongwoo
|
168 |
@date 18.04.18
|
169 |
@history 2018.05.02 Jeongwoo Change graphicsView.command by actionOCR checked state
|
170 |
Show MessageBox when imageviewer doesn't have image
|
171 |
'''
|
172 |
def areaOcr(self): |
173 |
if not self.graphicsView.hasImage(): |
174 |
self.showImageSelectionMessageBox()
|
175 |
return
|
176 |
|
177 |
if self.actionOCR.isChecked(): |
178 |
self.graphicsView.command = AreaOcrCommand.AreaOcrCommand(self.graphicsView) |
179 |
else:
|
180 |
self.graphicsView.useDefaultCommand()
|
181 |
|
182 |
'''
|
183 |
@brief area configuration
|
184 |
'''
|
185 |
def areaConfiguration(self): |
186 |
from QAreaConfigurationDialog import QAreaConfigurationDialog |
187 |
|
188 |
self.dlgAreaConfiguration = QAreaConfigurationDialog(self) |
189 |
self.dlgAreaConfiguration.show()
|
190 |
self.dlgAreaConfiguration.exec_()
|
191 |
|
192 |
'''
|
193 |
@brief configuration
|
194 |
'''
|
195 |
def configuration(self): |
196 |
from QConfigurationDialog import QConfigurationDialog |
197 |
|
198 |
self.dlgConfiguration = QConfigurationDialog(self) |
199 |
self.dlgConfiguration.show()
|
200 |
self.dlgConfiguration.exec_()
|
201 |
|
202 |
'''
|
203 |
@brief Show Image Selection Guide MessageBox
|
204 |
@author Jeongwoo
|
205 |
@date 2018.05.02
|
206 |
'''
|
207 |
def showImageSelectionMessageBox(self): |
208 |
QMessageBox.about(self.graphicsView, "알림", "이미지를 선택하신 후 시도해주세요.") |
209 |
|
210 |
'''
|
211 |
@brief Open image drawing file and then display it
|
212 |
@author humkyung
|
213 |
@date 2018.??.??
|
214 |
@history 18.04.23 Jeongwoo Add AppDocData.instance().setCurrentPidSource
|
215 |
18.04.23 Jeongwoo Add Store Set Current Pid Image on AppDocData
|
216 |
18.05.02 Jeongwoo Add useDefaultCommand()
|
217 |
'''
|
218 |
def openImageDrawing(self, MainWindow): |
219 |
import random |
220 |
|
221 |
try:
|
222 |
self.graphicsView.clearImage()
|
223 |
self.graphicsView.scene.clear()
|
224 |
self.graphicsView.useDefaultCommand()
|
225 |
self.path = self.graphicsView.loadImageFromFile() |
226 |
if os.path.isfile(self.path): |
227 |
baseName = os.path.basename(self.path)
|
228 |
AppDocData.instance().setCurrentPidSource(Image.open(self.path))
|
229 |
self.resultTreeWidget.setCurrentPID(baseName)
|
230 |
|
231 |
# DEBUG
|
232 |
'''
|
233 |
if __debug__:
|
234 |
from LineDetector import LineDetector
|
235 |
from LineNoTracer import LineNoTracer
|
236 |
self.loadRecognitionResult('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/output/UY1-K-2005G_P1_300dpi_black.xml')
|
237 |
|
238 |
# detect line
|
239 |
connectedLines = []
|
240 |
|
241 |
img = cv2.cvtColor(cv2.imread(self.path), cv2.COLOR_BGR2GRAY)
|
242 |
detector = LineDetector(img)
|
243 |
symbols = []
|
244 |
for item in self.graphicsView.scene.items():
|
245 |
if type(item) is SymbolSvgItem:
|
246 |
symbols.append(item)
|
247 |
color = QColor(random.randrange(0,255), random.randrange(0,255), random.randrange(0,255))
|
248 |
res = detector.detectConnectedLine(item, 0, 0)
|
249 |
if res is not None:
|
250 |
for line in res: connectedLines.append(line)
|
251 |
|
252 |
texts = []
|
253 |
for item in self.graphicsView.scene.items():
|
254 |
if (type(item) is QEngineeringTextItem): texts.append(item)
|
255 |
|
256 |
if len(connectedLines) > 1:
|
257 |
detector.mergeLines(connectedLines, toler=20)
|
258 |
# connect line to symbol
|
259 |
try:
|
260 |
for line in connectedLines:
|
261 |
matches = [symbol for symbol in symbols if symbol.isConnectable(line, (0,0), toler=40)]
|
262 |
for symbol in matches:
|
263 |
detector.connectLineToSymbol(line, (0,0), symbol)
|
264 |
except Exception as ex:
|
265 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
|
266 |
# up to here
|
267 |
|
268 |
# connect line to line
|
269 |
try:
|
270 |
for line in connectedLines[:]:
|
271 |
matches = [it for it in connectedLines if (line != it) and (not detector.isParallel(line, it))]
|
272 |
for match in matches:
|
273 |
detector.connectLineToLine(match, line)
|
274 |
except Exception as ex:
|
275 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
|
276 |
# up to here
|
277 |
|
278 |
lines = []
|
279 |
for pts in connectedLines:
|
280 |
processLine = QEngineeringLineItem()
|
281 |
lines.append(processLine)
|
282 |
for pt in pts:
|
283 |
processLine._pol.append(QPointF(pt[0], pt[1]))
|
284 |
processLine._path.addPolygon(processLine._pol)
|
285 |
processLine.setPath(processLine._path)
|
286 |
processLine.setPen(QPen(color, 5, Qt.SolidLine))
|
287 |
self.graphicsView.scene.addItem(processLine)
|
288 |
detector.saveImage()
|
289 |
|
290 |
# trace line no
|
291 |
tracer = LineNoTracer(symbols, lines, texts)
|
292 |
tracer.execute()
|
293 |
# up to here
|
294 |
|
295 |
# construct line no item
|
296 |
docData = AppDocData.instance()
|
297 |
for text in docData.lineNos:
|
298 |
item = self.resultTreeWidget.addTreeItem(self.resultTreeWidget.root, text)
|
299 |
|
300 |
if 1 == len(text.conns):
|
301 |
# iterate connected items
|
302 |
pool = []
|
303 |
visited = []
|
304 |
pool.append(text.conns[0])
|
305 |
while len(pool) > 0:
|
306 |
it = pool.pop()
|
307 |
if type(it) is SymbolSvgItem: self.resultTreeWidget.addTreeItem(item, it)
|
308 |
visited.append(it)
|
309 |
for conn in it.conns:
|
310 |
if (conn is not None) and (conn not in visited): pool.append(conn)
|
311 |
# up to here
|
312 |
|
313 |
# up to here
|
314 |
# up to here
|
315 |
'''
|
316 |
except Exception as ex: |
317 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
318 |
|
319 |
return self.path |
320 |
|
321 |
'''
|
322 |
@brief create a symbol
|
323 |
@history 2018.05.02 Jeongwoo Change return value of QSymbolEditorDialog (Single variable → Tuple)
|
324 |
Add SymbolSvgItem
|
325 |
2018.05.03 Jeongwoo Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
|
326 |
Change method to make svg and image path
|
327 |
'''
|
328 |
def createSymbol(self): |
329 |
image = self.graphicsView.image()
|
330 |
if image is not None: |
331 |
symbolEditorDialog = QSymbolEditorDialog.QSymbolEditorDialog(self, image, AppDocData.instance().getCurrentProject())
|
332 |
(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog() |
333 |
self.dirTreeWidget.initDirTreeWidget()
|
334 |
if isAccepted:
|
335 |
if isImmediateInsert:
|
336 |
svgPath = newSym.getSvgFileFullPath() |
337 |
img = cv2.imread(newSym.getImageFileFullPath(), 1)
|
338 |
w, h = (0, 0) |
339 |
if len(img.shape[::-1]) == 2: |
340 |
w, h = img.shape[::-1]
|
341 |
else:
|
342 |
_chan, w, h = img.shape[::-1]
|
343 |
svg = SymbolSvgItem(svgPath) |
344 |
svg.buildItem(newSym.getName(), newSym.getType(), 0, [offsetX, offsetY], [w, h], [float(x) for x in newSym.getOriginalPoint().split(',')], [(float(x.split(',')[0]), float(x.split(',')[1])) for x in newSym.getConnectionPoint().split('/')]) |
345 |
|
346 |
#### lambda param=svg : bind 'svg' object to lambda('param')
|
347 |
#### If case of 'lambda svg=svg:', function uses the 'svg' value bound to lambda
|
348 |
svg.clicked.connect(lambda param=svg: self.resultTreeWidget.findItem(param)) |
349 |
svg.removed.connect(self.resultTreeWidget.itemRemoved)
|
350 |
svg.addSvgItemToScene(self.graphicsView.scene)
|
351 |
for connector in svg.connectors: |
352 |
self.graphicsView.scene.addItem(connector)
|
353 |
|
354 |
#'''
|
355 |
# @brief connect equipment and nozzle
|
356 |
#'''
|
357 |
#def connectEqpNozzle(self):
|
358 |
# self.graphicsView.command = None
|
359 |
|
360 |
'''
|
361 |
@brief create a line
|
362 |
@author humkyung
|
363 |
'''
|
364 |
def createLine(self): |
365 |
# set imageviewer's command
|
366 |
self.graphicsView.command = CreateCommand.CreateCommand(self.graphicsView, QEngineeringLineItem()) |
367 |
# up to here
|
368 |
|
369 |
'''
|
370 |
@brief recognize symbol and text
|
371 |
@author humkyung
|
372 |
@date 2018.04.??
|
373 |
@history 2018.04.16 humkyung execute line no tracing
|
374 |
2018.05.02 Jeongwoo Show MessageBox when imageviewer doesn't have image
|
375 |
'''
|
376 |
def recognize(self, MainWindow): |
377 |
from QRecognitionDialog import QRecognitionDialog |
378 |
|
379 |
if not self.graphicsView.hasImage(): |
380 |
self.showImageSelectionMessageBox()
|
381 |
return
|
382 |
|
383 |
try:
|
384 |
self.dlg = QRecognitionDialog(self) |
385 |
self.startThread()
|
386 |
self.dlg.show()
|
387 |
self.dlg.exec_()
|
388 |
if self.dlg.isAccepted == True: |
389 |
self.loadRecognitionResult(self.xmlPath[0]) |
390 |
except Exception as ex: |
391 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
392 |
|
393 |
'''
|
394 |
@brief remove small objects from given image
|
395 |
@author humkyung
|
396 |
@date 2018.04.26
|
397 |
'''
|
398 |
def removeSmallObjects(self, image): |
399 |
try:
|
400 |
docData = AppDocData.instance() |
401 |
configs = docData.getConfigs('Small Object Size', 'Min Area') |
402 |
minArea = int(configs[0].value) if 1 == len(configs) else 20 |
403 |
configs = docData.getConfigs('Small Object Size', 'Max Area') |
404 |
maxArea = int(configs[0].value) if 1 == len(configs) else 50 |
405 |
|
406 |
#path = os.path.join(AppDocData.instance().getCurrentProject().getTempPath(), 'before_contours.png')
|
407 |
#cv2.imwrite(path, image)
|
408 |
|
409 |
_,contours,_ = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE); |
410 |
selectedContours=[] |
411 |
for contour in contours: |
412 |
#if cv2.isContourConvex(contour):
|
413 |
#approx = cv2.approxPolyDP(contour, 0.2*cv2.arcLength(contour, True), True)
|
414 |
area = cv2.contourArea(contour) |
415 |
if area > minArea and area < maxArea: selectedContours.append(contour) |
416 |
contourImage = cv2.drawContours(image, selectedContours, -1, (255,255,255), -1); |
417 |
#path = os.path.join(AppDocData.instance().getCurrentProject().getTempPath(), 'contours.png')
|
418 |
#cv2.imwrite(path, contourImage)
|
419 |
except Exception as ex: |
420 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
421 |
|
422 |
return contourImage
|
423 |
|
424 |
'''
|
425 |
@brief recognize line
|
426 |
@author humkyung
|
427 |
@date 2018.04.19
|
428 |
@history 2018.04.26 Jeongwoo Variable name changed (texts → lineNos)
|
429 |
TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem)
|
430 |
@history 2018.04.26 humkyung remove small objects before recognizing line
|
431 |
2018.05.02 Jeongwoo Show MessageBox when imageviewer doesn't have image
|
432 |
|
433 |
'''
|
434 |
def recognizeLine(self, MainWindow): |
435 |
from LineDetector import LineDetector |
436 |
from LineNoTracer import LineNoTracer |
437 |
|
438 |
if not self.graphicsView.hasImage(): |
439 |
self.showImageSelectionMessageBox()
|
440 |
return
|
441 |
|
442 |
try:
|
443 |
#remove already existing line item
|
444 |
items = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem] |
445 |
for item in items: |
446 |
self.graphicsView.scene.removeItem(item)
|
447 |
#up to here
|
448 |
|
449 |
# detect line
|
450 |
connectedLines = [] |
451 |
|
452 |
area = AppDocData.instance().getArea('Drawing')
|
453 |
area.img = self.removeSmallObjects(area.img)
|
454 |
detector = LineDetector(area.img) |
455 |
|
456 |
symbols = [] |
457 |
for item in self.graphicsView.scene.items(): |
458 |
if issubclass(type(item), SymbolSvgItem): |
459 |
symbols.append(item) |
460 |
res = detector.detectConnectedLine(item, round(area.x), round(area.y)) |
461 |
if res is not None: |
462 |
for line in res: connectedLines.append(line) |
463 |
|
464 |
texts = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)] |
465 |
for symbol in symbols: |
466 |
symbol.connectAttribute(texts) |
467 |
|
468 |
lineNos = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineNoTextItem] |
469 |
|
470 |
if len(connectedLines) > 1: |
471 |
detector.mergeLines(connectedLines, toler=20)
|
472 |
# connect line to symbol
|
473 |
try:
|
474 |
for line in connectedLines: |
475 |
matches = [symbol for symbol in symbols if symbol.isConnectable(line, (round(area.x), round(area.y)), toler=20)] |
476 |
for symbol in matches: |
477 |
detector.connectLineToSymbol(line, (round(area.x), round(area.y)), symbol) |
478 |
except Exception as ex: |
479 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
480 |
# up to here
|
481 |
|
482 |
# connect line to line
|
483 |
try:
|
484 |
for line in connectedLines[:]: |
485 |
matches = [it for it in connectedLines if (line != it) and (not detector.isParallel(line, it))] |
486 |
for match in matches: |
487 |
detector.connectLineToLine(match, line) |
488 |
except Exception as ex: |
489 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
490 |
# up to here
|
491 |
|
492 |
lines = [] |
493 |
for pts in connectedLines: |
494 |
processLine = QEngineeringLineItem() |
495 |
lines.append(processLine) |
496 |
for pt in pts: |
497 |
processLine._pol.append(QPointF(pt[0] + round(area.x), pt[1] + round(area.y))) |
498 |
processLine.buildItem() |
499 |
processLine.setPen(QPen(Qt.blue, 5, Qt.SolidLine))
|
500 |
self.graphicsView.scene.addItem(processLine)
|
501 |
|
502 |
# trace line no
|
503 |
tracer = LineNoTracer(symbols, lines, lineNos) |
504 |
tracer.execute() |
505 |
# up to here
|
506 |
|
507 |
# construct line no item
|
508 |
docData = AppDocData.instance() |
509 |
for text in docData.lineNos: |
510 |
item = self.resultTreeWidget.addTreeItem(self.resultTreeWidget.root, text) |
511 |
connectedItems = text.getConnectedItems() |
512 |
for connectedItem in connectedItems: |
513 |
if issubclass(type(connectedItem), SymbolSvgItem): self.resultTreeWidget.addTreeItem(item, connectedItem) |
514 |
# up to here
|
515 |
except Exception as ex: |
516 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
517 |
|
518 |
'''
|
519 |
@brief load recognition result
|
520 |
@author humkyung
|
521 |
@date 2018.04.??
|
522 |
@history humkyung 2018.01.12 parse originalpoint and connectionpoint
|
523 |
Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
|
524 |
Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
|
525 |
humkyung 2018.04.23 connect item remove slot to result tree
|
526 |
Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
|
527 |
Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
|
528 |
Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
|
529 |
'''
|
530 |
def loadRecognitionResult(self, xmlPath): |
531 |
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse |
532 |
|
533 |
try:
|
534 |
project = AppDocData.instance().getCurrentProject() |
535 |
|
536 |
xml = parse(xmlPath) |
537 |
root = xml.getroot(); |
538 |
for symbol in root.iter('SYMBOL'): |
539 |
pt = [float(x) for x in symbol.find('STARTPOINT').text.split(',')] |
540 |
size = [float(x) for x in symbol.find('SIZE').text.split(',')] |
541 |
name = symbol.find('NAME').text
|
542 |
angle = float(symbol.find('ANGLE').text) |
543 |
type = symbol.find('TYPE').text
|
544 |
origin = [float(x) for x in symbol.find('ORIGINALPOINT').text.split(',')] |
545 |
connPts = [] |
546 |
if symbol.find('CONNECTIONPOINT').text is not None: |
547 |
connPts = [(float(x.split(',')[0]), float(x.split(',')[1])) for x in symbol.find('CONNECTIONPOINT').text.split('/')] |
548 |
|
549 |
svgFilePath = os.path.join(project.getSvgFilePath(), type, name + '.svg') |
550 |
if os.path.isfile(svgFilePath):
|
551 |
svg = SymbolSvgItem.createItem(type, svgFilePath)
|
552 |
svg.buildItem(name, type, angle, pt, size, origin, connPts)
|
553 |
|
554 |
#### lambda param=svg : bind 'svg' object to lambda('param')
|
555 |
#### If case of 'lambda svg=svg:', function uses the 'svg' value bound to lambda
|
556 |
svg.clicked.connect(lambda param=svg: self.resultTreeWidget.findItem(param)) |
557 |
svg.removed.connect(self.resultTreeWidget.itemRemoved)
|
558 |
svg.addSvgItemToScene(self.graphicsView.scene)
|
559 |
for connector in svg.connectors: |
560 |
self.graphicsView.scene.addItem(connector)
|
561 |
else:
|
562 |
item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1]) |
563 |
item.isSymbol = True
|
564 |
item.angle = angle |
565 |
item.setPen(QPen(Qt.red, 20, Qt.SolidLine))
|
566 |
self.graphicsView.scene.addItem(item)
|
567 |
|
568 |
docData = AppDocData.instance() |
569 |
configs = docData.getConfigs('Line No', 'Delimiter') |
570 |
delimiter = configs[0].value if 1 == len(configs) else '-' |
571 |
lineNoconfigs = docData.getConfigs('Line No', 'Configuration') |
572 |
# parse texts
|
573 |
for text in root.iter('TEXTINFO'): |
574 |
x = float(text.find('X').text) if text.find('X') is not None else 0 |
575 |
y = float(text.find('Y').text) if text.find('Y') is not None else 0 |
576 |
width = float(text.find('WIDTH').text) if text.find('WIDTH') is not None else 0 |
577 |
height = float(text.find('HEIGHT').text) if text.find('HEIGHT') is not None else 0 |
578 |
angle = float(text.find('ANGLE').text) if text.find('ANGLE') is not None else 0 |
579 |
text = text.find('TEXT').text
|
580 |
item = TextItemFactory.instance().createTextItem(text, delimiter, lineNoconfigs) |
581 |
if item is not None: |
582 |
item.loc = (x, y) |
583 |
item.size = (width, height) |
584 |
item.angle = angle |
585 |
item.setPlainText(text) |
586 |
item.setDefaultTextColor(Qt.blue) |
587 |
item.removed.connect(self.resultTreeWidget.itemRemoved)
|
588 |
item.addTextItemToScene(self.graphicsView.scene)
|
589 |
|
590 |
# parse notes
|
591 |
for note in root.iter('NOTE'): |
592 |
x = float(note.find('X').text) if note.find('X') is not None else 0 |
593 |
y = float(note.find('Y').text) if note.find('Y') is not None else 0 |
594 |
width = float(note.find('WIDTH').text) if note.find('WIDTH') is not None else 0 |
595 |
height = float(note.find('HEIGHT').text) if note.find('HEIGHT') is not None else 0 |
596 |
angle = float(note.find('ANGLE').text) if note.find('ANGLE') is not None else 0 |
597 |
text = note.find('TEXT').text
|
598 |
item = TextItemFactory.instance().createTextItem(text) |
599 |
item.loc = (x, y) |
600 |
item.size = (width, height) |
601 |
item.angle = angle |
602 |
item.setPlainText(text) |
603 |
item.setDefaultTextColor(Qt.blue) |
604 |
item.addTextItemToScene(self.graphicsView.scene)
|
605 |
|
606 |
#self.graphicsView.scene.addItem(item)
|
607 |
# up to here
|
608 |
except Exception as ex: |
609 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
610 |
|
611 |
'''
|
612 |
@brief generate output xml file
|
613 |
@author humkyung
|
614 |
@date 2018.04.23
|
615 |
@history 2018.05.02 Jeongwoo Show MessageBox when imageviewer doesn't have image
|
616 |
'''
|
617 |
def generateOutput(self): |
618 |
import XmlGenerator as xg |
619 |
|
620 |
if not self.graphicsView.hasImage(): |
621 |
self.showImageSelectionMessageBox()
|
622 |
return
|
623 |
|
624 |
try:
|
625 |
docData = AppDocData.instance() |
626 |
|
627 |
# TODO: how to check equipment
|
628 |
docData.equipments.clear() |
629 |
for item in self.graphicsView.scene.items(): |
630 |
if (type(item) is SymbolSvgItem) and item.type == 'Specialty Components': |
631 |
docData.equipments.append(item) |
632 |
# up to here
|
633 |
|
634 |
xg.writeOutputXml(docData.imgName, docData.imgWidth, docData.imgHeight) |
635 |
except Exception as ex: |
636 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
637 |
|
638 |
'''
|
639 |
@brief start thread
|
640 |
@author humkyung
|
641 |
@date 2018.04.??
|
642 |
'''
|
643 |
def startThread(self): |
644 |
self.dlg.ui.buttonBox.setDisabled(True) |
645 |
|
646 |
# 1 - create Worker and Thread inside the Form
|
647 |
self.obj = Worker() # no parent! |
648 |
self.obj.path = self.path |
649 |
self.obj.listWidget = self.dlg.ui.listWidget |
650 |
self.thread = QThread() # no parent! |
651 |
|
652 |
# 2 - Connect Worker`s Signals to Form method slots to post data.
|
653 |
#self.obj.intReady.connect(self.onIntReady)
|
654 |
|
655 |
# 3 - Move the Worker object to the Thread object
|
656 |
self.obj.moveToThread(self.thread) |
657 |
|
658 |
# 4 - Connect Worker Signals to the Thread slots
|
659 |
self.obj.finished.connect(self.thread.quit) |
660 |
|
661 |
# 5 - Connect Thread started signal to Worker operational slot method
|
662 |
self.thread.started.connect(self.obj.procCounter) |
663 |
|
664 |
# * - Thread finished signal will close the app if you want!
|
665 |
self.thread.finished.connect(self.dlgExit) |
666 |
|
667 |
# 6 - Start the thread
|
668 |
self.thread.start()
|
669 |
|
670 |
'''
|
671 |
@brief set buttonbox's enabled flag
|
672 |
'''
|
673 |
def dlgExit(self): |
674 |
self.xmlPath = self.obj.xmlPath |
675 |
self.dlg.ui.buttonBox.setEnabled(True) |
676 |
|
677 |
if __name__ == '__main__': |
678 |
import DTI_PID_UI |
679 |
from ProjectDialog import Ui_Dialog |
680 |
from App import App |
681 |
|
682 |
app = App(sys.argv) |
683 |
try:
|
684 |
dlg = Ui_Dialog() |
685 |
selectedProject = dlg.showDialog() |
686 |
if selectedProject is not None: |
687 |
AppDocData.instance().setCurrentProject(selectedProject) |
688 |
app.mainWnd = MainWindow.instance() |
689 |
app.mainWnd.show() |
690 |
except Exception as ex: |
691 |
print('에러가 발생했습니다.\n', ex)
|
692 |
|
693 |
sys.exit(app.exec_()) |