프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ d9257e5d

이력 | 보기 | 이력해설 | 다운로드 (114 KB)

1
# coding: utf-8
2
""" This is MainWindow module """
3

    
4
import sys
5
import os
6
import subprocess
7
from functools import partial
8

    
9
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
10
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands')
11
import CreateCommand
12
import CropCommand
13
import AreaOcrCommand
14
import CreateSymbolCommand
15
import AreaZoomCommand
16
import FenceCommand
17
import PlaceLineCommand
18
import PlacePolygonCommand
19

    
20
import cv2
21
import numpy as np
22

    
23
from PyQt5.QtCore import *
24
from PyQt5.QtGui import *
25
from PyQt5.QtWidgets import *
26
from PyQt5.QtSvg import *
27

    
28
from PIL import Image
29

    
30
import MainWindow_UI
31
import QtImageViewer
32
from SingletonInstance import SingletonInstane
33

    
34
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Shapes')
35
from EngineeringPolylineItem import QEngineeringPolylineItem
36
from EngineeringLineItem import QEngineeringLineItem
37
from SymbolSvgItem import SymbolSvgItem
38
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
39
from EngineeringTextItem import QEngineeringTextItem
40
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
41
from EngineeringNoteItem import QEngineeringNoteItem
42
from QEngineeringSizeTextItem import QEngineeringSizeTextItem
43
from EngineeringUnknownItem import QEngineeringUnknownItem
44
from EngineeringEquipmentItem import QEngineeringEquipmentItem
45
from EngineeringInstrumentItem import QEngineeringInstrumentItem
46
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
47
from EngineeringErrorItem import QEngineeringErrorItem
48
from EngineeringVendorItem import QEngineeringVendorItem
49
from EngineeringEndBreakItem import QEngineeringEndBreakItem
50
from AppDocData import *
51
import SymbolTreeWidget, SymbolPropertyTableWidget
52
import SymbolEditorDialog
53
import ItemTreeWidget
54
import ItemPropertyTableWidget
55
from UserInputAttribute import UserInputAttribute
56
from TextItemFactory import TextItemFactory
57
from TrainingImageListDialog import QTrainingImageListDialog
58
from TextDataListDialog import QTextDataListDialog
59
from DisplayColors import DisplayColors
60
from DisplayColors import DisplayOptions
61

    
62
class MainWindow(QMainWindow, MainWindow_UI.Ui_MainWindow, SingletonInstane):
63
    """ This is MainWindow class """
64
    addMessage = pyqtSignal(Enum, str)
65

    
66
    '''
67
        @brief      initialize
68
        @author 
69
        @date   
70
        @history    humkyung 2018.04.12 add splitter widget
71
                    Jeongwoo 2018.04.27 Add Signal/Slot Connection 'noteNoSingleClicked'
72
                    Jeongwoo 2018.05.09 Initialize Action group
73
                    Jeongwoo 2018.05.10 Add Signal/Slot Connection 'lineNoSingleClicked'
74
                                        Add QActionGroup for managing checkable action
75
                    Jeongwoo 2018.06.27 Add Action [Zoom, Fit Window] and Add new actions into ActionGroup
76
                    humkyung 2018.08.23 add labelStatus to statusbar
77
                    Euisung 2018.09.27 add OCR Training , Signal/Slot Connection 'oCRTrainingClicked'
78
                    Euisung 2018.10.05 add OCR Editor , Signal/Slot Connection 'oCRTrainingEdidorClicked'
79
                    Euisung 2018.10.22 delete Signal/Slot Connection 'oCRTrainingEdidorClicked'
80
    '''
81
    def __init__(self):
82
        from LineTypeConditions import LineTypeConditions
83

    
84
        super(self.__class__, self).__init__()
85
        self.setupUi(self)
86
        self._label_mouse = QLabel(self.statusbar)
87
        self._label_mouse.setText(self.tr('mouse pos : ({},{})'.format(0,0)))
88
        self.labelStatus = QLabel(self.statusbar)
89
        self.labelStatus.setText(self.tr('Unrecognition : '))
90
        self.labelSymbolStatus = QLabel(self.statusbar)
91
        self.labelSymbolStatus.setText(self.tr('Symbol : '))
92
        self.labelLineStatus = QLabel(self.statusbar)
93
        self.labelLineStatus.setText(self.tr('Line : '))
94
        self.labelTextStatus = QLabel(self.statusbar)
95
        self.labelTextStatus.setText(self.tr('Text : '))
96
        self.statusbar.addWidget(self._label_mouse)
97
        self.statusbar.addPermanentWidget(self.labelSymbolStatus)
98
        self.statusbar.addPermanentWidget(self.labelLineStatus)
99
        self.statusbar.addPermanentWidget(self.labelTextStatus)
100
        self.statusbar.addPermanentWidget(self.labelStatus) 
101

    
102
        docData = AppDocData.instance()
103
        project = docData.getCurrentProject()
104
        _translate = QCoreApplication.translate
105
        self.setWindowTitle(_translate("Digital P&ID - {}".format(project.name), "Digital P&ID - {}".format(project.name)))
106

    
107
        self.lineComboBox = QComboBox(self.toolBar)
108
        for condition in LineTypeConditions.items():
109
            self.lineComboBox.addItem(condition.name)
110
        self.lineComboBox.currentIndexChanged.connect(self.onLineTypeChanged)
111

    
112
        self.toolBar.insertWidget(self.actionOCR, self.lineComboBox)
113
        self.toolBar.insertSeparator(self.actionOCR)
114
        
115
        self.graphicsView = QtImageViewer.QtImageViewer(self)
116
        self.graphicsView.setParent(self.centralwidget)
117
        self.graphicsView.useDefaultCommand() ##### USE DEFAULT COMMAND
118
        self.graphicsView.setMouseTracking(True)
119
        self.graphicsView.viewport().installEventFilter(self)
120

    
121
        self._display_widget = QWidget()
122
        layout = QVBoxLayout()
123
        self._by_line_no = QRadioButton()
124
        self._by_line_no.setChecked(True)
125
        self._by_line_no.setText('By Line No')
126
        self._by_line_no.toggled.connect(self.display_colors)
127
        layout.addWidget(self._by_line_no)
128
        self._by_line_type = QRadioButton()
129
        self._by_line_type.setText('By Line Type')
130
        layout.addWidget(self._by_line_type)
131
        self._display_widget.setLayout(layout)
132
        self.EditToolbar.insertWidget(None, self._display_widget)
133
        self._by_line_no.setChecked(True) if DisplayColors.instance().option == DisplayOptions.DisplayByLineNo else self._by_line_type.setChecked(True)
134

    
135
        self.verticalLayout.addWidget(self.graphicsView)
136

    
137
        # Add Custom TreeWidget
138
        self.dirTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
139
        self.dirTreeWidget.header().hide()
140
        self.symbolTabVerticalLayout.addWidget(self.dirTreeWidget)
141

    
142
        # Add Custom Property TableWidget
143
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
144
        self.symbolTabVerticalLayout.addWidget(self.propertyTableWidget)
145
        self.dirTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
146
        # add splitter widget
147
        splitter = QSplitter(Qt.Vertical)
148
        splitter.addWidget(self.dirTreeWidget)
149
        splitter.addWidget(self.propertyTableWidget)
150
        self.symbolTabVerticalLayout.addWidget(splitter)
151
        # up to here
152

    
153
        # Add Custom Result Tree Widget (Symbol Explorer)
154
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
155
        self.itemTreeWidget.header().hide()
156
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
157

    
158
        # Add Empty Widget
159
        self.resultPropertyTableWidget = ItemPropertyTableWidget.QItemPropertyTableWidget(self)
160
        self.symbolExplorerVerticalLayout.addWidget(self.resultPropertyTableWidget)
161
        self.itemTreeWidget.singleClicked.connect(self.resultPropertyTableWidget.onSymbolClicked)
162
        self.itemTreeWidget.noteNoSingleClicked.connect(self.resultPropertyTableWidget.onNoteClicked)
163
        self.itemTreeWidget.lineNoSingleClicked.connect(self.resultPropertyTableWidget.onLineNoClicked)
164
        self.itemTreeWidget.drawingClicked.connect(self.resultPropertyTableWidget.onDrawingClicked)
165
        # add splitter widget
166
        splitter = QSplitter(Qt.Vertical)
167
        splitter.addWidget(self.itemTreeWidget)
168
        splitter.addWidget(self.resultPropertyTableWidget)
169
        self.symbolExplorerVerticalLayout.addWidget(splitter)
170
        # up to here
171

    
172
        # Initialize Action group
173
        self.actionGroup = QActionGroup(self)
174
        self.actionGroup.addAction(self.actionRecognition)
175
        self.actionGroup.addAction(self.actionLineRecognition)
176
        self.actionGroup.addAction(self.actionLine)
177
        self.actionGroup.addAction(self.actionGenerateOutput)
178
        self.actionGroup.addAction(self.actionOCR)
179
        self.actionGroup.addAction(self.actionZoom)
180
        self.actionGroup.addAction(self.actionFitWindow)
181
        self.actionGroup.addAction(self.actionSave)
182
        self.actionGroup.addAction(self.actionValidate)
183
        self.actionGroup.addAction(self.actionVendor)
184
        self.actionGroup.triggered.connect(self.actionGroupTriggered)
185

    
186
        # connect signals and slots
187
        self.actionClose.triggered.connect(self.close)
188
        self.actionOpen.triggered.connect(self.onOpenImageDrawing)
189
        self.actionLine.triggered.connect(self.onPlaceLine)
190
        self.actionRecognition.triggered.connect(self.recognize)
191
        self.pushButtonBatchRecognition.clicked.connect(self.recognizeBatch)
192
        self.pushButtonRefreshDrawings.clicked.connect(self.load_drawing_list)
193
        self.actionLineRecognition.triggered.connect(self.connect_attributes)
194
        self.actionArea.triggered.connect(self.areaConfiguration)
195
        self.actionConfiguration.triggered.connect(self.configuration)
196
        self.actionOCR.triggered.connect(self.onAreaOcr)
197
        self.actionGenerateOutput.triggered.connect(self.generateOutput)
198
        self.pushButtonCreateSymbol.clicked.connect(self.onCreateSymbolClicked)
199
        self.pushButtonClearLog.clicked.connect(self.onClearLog)
200
        self.actionHMB_DATA.triggered.connect(self.onHMBData)
201
        self.actionItem_Data_List.triggered.connect(self.showItemDataList)
202
        self.actionText_Data_List.triggered.connect(self.showTextDataList)
203
        self.actionCodeTable.triggered.connect(self.onShowCodeTable)
204
        self.actionImage_Drawing.triggered.connect(self.onViewImageDrawing)
205
        self.actionDrawing_Only.triggered.connect(self.onViewDrawingOnly)
206
        self.actionValidate.triggered.connect(self.onValidation)
207
        self.actionViewText.triggered.connect(self.onViewText)
208
        self.actionViewSymbol.triggered.connect(self.onViewSymbol)
209
        self.actionViewLine.triggered.connect(self.onViewLine)
210
        self.actionViewUnknown.triggered.connect(self.onViewUnknown)
211
        self.actionViewInconsistency.triggered.connect(self.onViewInconsistency)
212
        self.actionViewVendor_Area.triggered.connect(self.onViewVendorArea)
213
        self.actionRotate.triggered.connect(self.onRotate)
214
        self.actionZoom.triggered.connect(self.onAreaZoom)
215
        self.actionVendor.triggered.connect(self.onVendor)
216
        self.actionFitWindow.triggered.connect(self.fitWindow)
217
        self.actionpdf_to_image.triggered.connect(self.onConvertPDFToImage)
218
        #self.graphicsView.scene.changed.connect(self.onSceneChanged)
219
        self.graphicsView.scene.contents_changed.connect(self.onSceneChanged)
220
        self.graphicsView.scene.selectionChanged.connect(self.onSelectionChanged)
221
        self.actionInitialize.triggered.connect(self.onInitializeScene)
222
        self.actionSave.triggered.connect(self.actionSaveCliked)
223
        self.addMessage.connect(self.onAddMessage)
224
        self.actionFindReplaceText.triggered.connect(self.findReplaceTextClicked)
225
        self.pushButtonDetectSymbol.clicked.connect(self.onShowDetectSymbol)
226

    
227
        configs = docData.getAppConfigs('app', 'mode')
228
        if configs and 1 == len(configs) and 'advanced' == configs[0].value:
229
            self.actionOCR_Training.triggered.connect(self.oCRTrainingClicked)
230
            self.pushButtonBatchRecognition
231
        else:
232
            self.actionOCR_Training.setVisible(False)
233
            self.pushButtonBatchRecognition.setVisible(False)
234

    
235
        # removedItems
236
        self.removedItems = {}
237
        self.removedItems['LINE'] = []
238
        self.removedItems['EQUIP'] = []
239
        self.removedItems['INST'] = []
240
        self.removedItems['NOTE'] = []
241

    
242
        self.delimiter = '"'
243
    
244
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
245

    
246
        self.treeWidgetDrawingList.setHeaderHidden(False)
247
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
248
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
249
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
250
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
251
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
252
        self.load_drawing_list()
253

    
254
        # load stylesheet file list
255
        stylesheet_name = QtWidgets.qApp.stylesheet_name
256
        files = [os.path.splitext(file)[0] for file in os.listdir(os.path.dirname(os.path.realpath(__file__))) if os.path.splitext(file)[1] == '.qss']
257
        for file in files:
258
            action = self.menuTheme.addAction(file)
259
            action.setCheckable(True)
260
            action.setChecked(True) if stylesheet_name == file else action.setChecked(False)
261
            action.triggered.connect(partial(self.load_stylesheet, file))
262
        # up to here
263

    
264
        # load language files
265
        language_name = QtWidgets.qApp.language_name
266
        files = ['en_us'] # englisgh is default language
267
        files.extend([os.path.splitext(file)[0] for file in os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate')) if os.path.splitext(file)[1] == '.qm'])
268
        for file in files:
269
            action = self.menuLanguage.addAction(file)
270
            action.setCheckable(True)
271
            action.setChecked(True) if language_name.lower() == file.lower() else action.setChecked(False)
272
            action.triggered.connect(partial(self.load_language, file))
273
        # up to here
274

    
275
        # inconsistency table
276
        self.tableWidgetInconsistency.setColumnCount(2)
277
        self.tableWidgetInconsistency.setHorizontalHeaderLabels(['Owner', 'Message'])
278
        self.tableWidgetInconsistency.setEditTriggers(QAbstractItemView.NoEditTriggers)
279
        self.tableWidgetInconsistency.itemClicked.connect(self.inconsistencyItemClickEvent)
280
        self.tableWidgetInconsistency.keyPressEvent = self.inconsistencyTableKeyPressEvent
281

    
282
    def eventFilter(self, source, event):
283
        """
284
        display mouse position of graphics view
285
        """
286
        if (event.type() == QEvent.MouseMove):
287
            pos = self.graphicsView.mapToScene(event.pos())
288
            self._label_mouse.setText('mouse pos : ({},{})'.format(round(pos.x()), round(pos.y())))
289

    
290
        return QWidget.eventFilter(self, source, event)
291

    
292
    def inconsistencyTableKeyPressEvent(self, event):
293
        try:
294
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
295
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
296
            from HighlightCommand import HighlightCommand
297
            if event.key() == Qt.Key_Up:
298
                if row is not 0:
299
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
300
                    HighlightCommand(self.graphicsView).execute(errorItem)
301
            elif event.key() == Qt.Key_Down:
302
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
303
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
304
                    HighlightCommand(self.graphicsView).execute(errorItem)
305
        except Exception as ex:
306
            pass
307
        #finally:
308
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
309

    
310
    def onValidation(self):
311
        """
312
        @brief  validation check
313
        @author euisung
314
        @date   2019.04.01
315
        """
316
        if not self.graphicsView.hasImage():
317
            self.showImageSelectionMessageBox()
318
            return
319

    
320
        errors = []
321

    
322
        try:
323
            for item in self.graphicsView.scene.items():
324
                if type(item) is QEngineeringErrorItem:
325
                    item.transfer.onRemoved.emit(item)
326
                elif type(item) is QEngineeringLineItem or issubclass(type(item), SymbolSvgItem):
327
                    for error in item.validate():
328
                        errors.append(error)
329

    
330
            for error in errors:
331
                error.transfer.onRemoved.connect(self.itemRemoved)
332
                self.graphicsView.scene.addItem(error)
333

    
334
            self.tableWidgetInconsistency.clearContents()
335
            self.tableWidgetInconsistency.setRowCount(len(errors))
336
            for index in range(len(errors)):
337
                items = self.makeInconsistencyTableRow(errors[index])
338
                self.tableWidgetInconsistency.setItem(index, 0, items[0])
339
                self.tableWidgetInconsistency.setItem(index, 1, items[1])
340
        except Exception as ex:
341
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
342
            self.addMessage.emit(MessageType.Error, message)
343

    
344
    def makeInconsistencyTableRow(self, errorItem):
345
        '''
346
            @brief  make row data for inconsistency widget
347
            @author euisung
348
            @date   2019.04.16
349
        '''
350
        items = []
351
        owner = ''
352
        if type(errorItem.parent) is QEngineeringLineItem:
353
            item = QTableWidgetItem('line')
354
            #item.setFlags(Qt.ItemIsEnabled)
355
        elif issubclass(type(errorItem.parent), SymbolSvgItem):
356
            item = QTableWidgetItem('symbol')
357
            #item.setFlags(Qt.ItemIsEnabled)
358
        #elif
359
        item.tag = errorItem
360
        items.append(item)
361

    
362
        item = QTableWidgetItem(errorItem.msg)
363
        #item.setFlags(Qt.ItemIsEnabled)
364
        item.tag = errorItem
365
        items.append(item)
366

    
367
        return items
368

    
369
    def inconsistencyItemClickEvent(self, item):
370
        """
371
        @brief  inconsistency table item clicked
372
        @author euisung
373
        @date   2019.04.02
374
        """
375
        from HighlightCommand import HighlightCommand
376

    
377
        HighlightCommand(self.graphicsView).execute(item.tag)
378

    
379
    def load_stylesheet(self, file):
380
        """
381
        @brief  load stylesheets
382
        @author humkyung
383
        @date   2018.10.29
384
        """
385

    
386
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
387

    
388
        app_doc_data = AppDocData.instance()
389
        configs = [Config('app', 'stylesheet', file)]
390
        app_doc_data.saveAppConfigs(configs)
391
        
392
        for action in self.menuTheme.actions():
393
            if action.text() == file: continue
394
            action.setChecked(False)
395

    
396
    def load_language(self, file):
397
        """
398
        load language file and then apply selected language 
399
        """
400
        try:
401
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
402
            QtWidgets.qApp.load_language(qm_file)
403

    
404
            app_doc_data = AppDocData.instance()
405
            configs = [Config('app', 'language', file)]
406
            app_doc_data.saveAppConfigs(configs)
407
            
408
            for action in self.menuLanguage.actions():
409
                if action.text().lower() == file.lower(): continue
410
                action.setChecked(False)
411
        finally:
412
            self.retranslateUi(self)
413
            self.propertyTableWidget.retranslateUi()
414

    
415
    '''
416
        @brief      Clear TreeWidget and Set Current PID
417
        @author     Jeongwoo
418
        @date       18.04.11
419
        @history    2018.04.26  Jeongwoo    Add Child [SYMBOLS, NOTES] into root item
420
                    2018.05.09  Jeongwoo    Change method to add default tree items
421
                    humkyung 2018.06.10 add tree item for Line No and Unknown Item
422
    '''
423
    def load_drawing_list(self):
424
        """
425
        @brief      load p&id drawing list
426
        @author     humkyung
427
        @date       18.11.02
428
        """
429

    
430
        try:
431
            appDocData = AppDocData.instance()
432
            drawings = appDocData.getDrawings()
433

    
434
            self.treeWidgetDrawingList.clear()
435
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList, [self.tr('P&ID Drawings'), ''])
436
            self.treeWidgetDrawingList.root.setFlags(self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
437
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
438
            files = appDocData.getDrawingFileList()
439
            for file in files:
440
                drawing = [drawing for drawing in drawings if drawing[1] == file]
441
                if not drawing or not drawing[0]:
442
                    drawings.append([None, file, None])
443

    
444
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing[0][2] if drawing and drawing[0] else ''])
445
                item.setIcon(0, QIcon(':newPrefix/image.png'))
446
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
447
                item.setCheckState(0, Qt.Unchecked)
448
            
449
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings')+'({})'.format(self.treeWidgetDrawingList.root.childCount()))
450
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
451
            self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
452
            self.treeWidgetDrawingList.resizeColumnToContents(0)
453

    
454
            appDocData.saveDrawings(drawings)
455
        except Exception as ex:
456
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
457
            self.addMessage.emit(MessageType.Error, message)
458

    
459
    def open_selected_drawing(self, item, column):
460
        """
461
        @brief      open selected p&id drawing
462
        @author     humkyung
463
        @date       18.11.02
464
        """
465
        appDocData = AppDocData.instance()
466
        drawing = os.path.join(appDocData.getCurrentProject().getDrawingFilePath(), item.text(column))
467
        self.onOpenImageDrawing(drawing)
468

    
469
    def onShowDetectSymbol(self):
470
        from DetectSymbolDialog import QDetectSymbolDialog
471

    
472
        dlgDetectSymbol = QDetectSymbolDialog(self)
473
        dlgDetectSymbol.show()
474
        dlgDetectSymbol.exec_()
475
        
476
    '''
477
        @brief      OCR Editor
478
        @author     euisung
479
        @date       2018.10.05
480
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
481
    '''
482
    def oCRTrainingEdidorClicked(self):
483
        from TrainingEditorDialog import QTrainingEditorDialog
484

    
485
        try:
486
            dialog = QTrainingEditorDialog(self)
487
            dialog.exec_()
488
        except Exception as ex:
489
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
490
            self.addMessage.emit(MessageType.Error, message)
491
            
492
        return
493

    
494
    '''
495
        @brief      OCR Training
496
        @author     euisung
497
        @date       2018.09.27
498
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
499
    '''
500
    def oCRTrainingClicked(self):
501
        try:
502
            dialog = QTrainingImageListDialog(self)
503
            dialog.exec_()
504
        except Exception as ex:
505
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
506
            self.addMessage.emit(MessageType.Error, message)
507

    
508
    '''
509
        @brief      show unknownitem's count
510
        @author     kyouho
511
        @date       2018.08.27
512
    '''
513
    def findReplaceTextClicked(self):
514
        if not self.graphicsView.hasImage():
515
            self.showImageSelectionMessageBox()
516
            return
517

    
518
        from TextItemEditDialog import QTextItemEditDialog
519

    
520
        self.dlgTextItemEdit = QTextItemEditDialog(self)
521
        self.dlgTextItemEdit.show()
522
        self.dlgTextItemEdit.exec_()
523

    
524
    '''
525
        @brief      show unknownitem's count
526
        @author     humkyung
527
        @date       2018.08.23
528
        @history    humkyung 2018.08.30 display count of symbol, line, text
529
    '''
530
    def onSceneChanged(self):
531
        items = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringUnknownItem]
532
        if len(items) > 0:
533
            self.labelStatus.setText("<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
534
        else:
535
            self.labelStatus.setText("<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
536

    
537
        items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem]
538
        self.labelSymbolStatus.setText("<font color='blue'>" + self.tr('Symbol') + " : {}</font>".format(len(items)))
539

    
540
        items = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem]
541
        self.labelLineStatus.setText("<font color='blue'>" + self.tr('Line') + " : {}</font>".format(len(items)))
542

    
543
        items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
544
        self.labelTextStatus.setText("<font color='blue'>" + self.tr('Text') + " : {}</font>".format(len(items)))
545

    
546
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene.items())
547

    
548
    def dbUpdate(self):
549
        '''
550
            @brief      db update when save or recognition
551
            @author     euisung
552
            @date       2018.11.12
553
            @history    2018.11.02      euisung     remove scene dependency
554
        '''
555
        from AppDocData import AppDocData
556

    
557
        try:
558
            appDocData = AppDocData.instance()
559

    
560
            titleBlockProps = appDocData.getTitleBlockProperties()
561
            #items = self.graphicsView.scene.items()
562
            items = appDocData.allItems
563
            titleBlockItems = []
564
            for item in items:
565
                #if type(item) is QEngineeringLineNoTextItem:
566
                #    item.saveLineData()
567
                if type(item) is QEngineeringTextItem:
568
                    for titleBlockProp in titleBlockProps:
569
                        if item.area == titleBlockProp[0]:
570
                            titleBlockItems.append(item)
571

    
572
            dbItems = [item for item in items if type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or\
573
            type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(item) is QEngineeringLineNoTextItem or type(item) is QEngineeringVendorItem] + titleBlockItems
574
            appDocData.saveToDatabase(dbItems)
575
        except Exception as ex:
576
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
577
            self.addMessage.emit(MessageType.Error, message)
578

    
579
    '''
580
        @brief      action save click event
581
        @author     kyouho
582
        @date       2018.08.09
583
        @history    2018.11.02      euisung     add line data list db update
584
                    humkyung save saved time to database
585
                    2018.11.05      euisung     add note data list db update
586
                    2018.11.05      euisung     add db delete process before save
587
                    2018.11.12      euisung     db part move new method to dbUpdate
588
    '''
589
    def actionSaveCliked(self):
590
        from datetime import datetime
591
        from AppDocData import AppDocData
592
        from EngineeringAbstractItem import QEngineeringAbstractItem
593
        from SaveWorkCommand import SaveWorkCommand 
594

    
595
        try:
596
            appDocData = AppDocData.instance()
597
            if appDocData.imgName is None:
598
                self.showImageSelectionMessageBox()
599
                return
600

    
601
            appDocData.clearItemList(False)
602

    
603
            items = self.graphicsView.scene.items()
604
            for item in items:
605
                if issubclass(type(item), QEngineeringAbstractItem):
606
                    appDocData.allItems.append(item)
607
                    if issubclass(type(item), QEngineeringTextItem):
608
                        appDocData.texts.append(item)
609
            ##
610

    
611
            itemTypes = []
612
            for item in items:
613
                typeExist = False
614
                for itemType in itemTypes:
615
                    if type(item) is itemType:
616
                        typeExist = True
617
                        break
618
                if not typeExist:
619
                    itemTypes.append(type(item))
620
            ##
621

    
622
            self._save_work_cmd = SaveWorkCommand()
623
            self._save_work_cmd.display_message.connect(self.onAddMessage)
624
            self._save_work_cmd.finished.connect(self.save_finished)
625

    
626
            """ show spinner gif animation """
627
            self.label_spinner.setWindowFlags(Qt.WindowStaysOnTopHint)
628
            if not hasattr(self, '_movie'):
629
                self._movie = QMovie(':/newPrefix/spinner.gif')
630
                self.label_spinner.setMovie(self._movie)
631
            self.label_spinner.show()
632
            self._movie.start()
633

    
634
            self._save_work_cmd.start()
635
        except Exception as ex:
636
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
637
            self.addMessage.emit(MessageType.Error, message)
638

    
639
    def save_finished(self):
640
        """ stop movie and hide label after finishing save """
641
        self._movie.stop()
642
        self.label_spinner.hide()
643
        QMessageBox.about(self.graphicsView, self.tr('Notice'), self._save_work_cmd.resultStr)
644

    
645
    '''
646
        @brief      refresh resultPropertyTableWidget
647
        @author     kyouho
648
        @date       2018.07.19
649
    '''
650
    def refreshResultPropertyTableWidget(self):
651
        items = self.graphicsView.scene.selectedItems()
652
        if len(items) == 1:
653
            self.resultPropertyTableWidget.show_item_property(items[0])
654
    
655
    '''
656
        @brief  add message listwidget
657
        @author humkyung
658
        @date   2018.07.31
659
    '''
660
    def onAddMessage(self, messageType, message):
661
        from AppDocData import MessageType
662

    
663
        try:
664
            current = QDateTime.currentDateTime()
665

    
666
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
667
            if messageType == MessageType.Error:
668
                item.setBackground(Qt.red)
669

    
670
            self.listWidgetLog.insertItem(0, item)
671
        except Exception as ex:
672
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
673

    
674
    '''
675
        @brief      clear log
676
        @author     humkyung
677
        @date       2018.08.01
678
    '''
679
    def onClearLog(self):
680
        self.listWidgetLog.clear()
681

    
682
    '''
683
        @brief      rotate selected symbol
684
        @author     humkyung
685
        @date       2018.08.15
686
    '''
687
    def onRotate(self, action):
688
        selected = [item for item in self.graphicsView.scene.selectedItems() if issubclass(type(item), SymbolSvgItem)]
689
        if len(selected) == 1:
690
            selected[0].rotateSymbol()
691

    
692
    '''
693
        @brief      Area Zoom
694
        @author     Jeongwoo
695
        @date       2018.06.27
696
        @history    connect command's rejected signal
697
    '''
698
    def onAreaZoom(self, action):
699
        if self.actionZoom.isChecked():
700
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
701
            cmd.onRejected.connect(self.onCommandRejected)
702
            self.graphicsView.command = cmd
703

    
704
    def onVendor(self, action):
705
        '''
706
            @brief      make vendor package area
707
            @author     euisung
708
            @date       2019.04.29
709
        '''
710
        if not self.graphicsView.hasImage():
711
            self.actionVendor.setChecked(False)
712
            self.showImageSelectionMessageBox()
713
            return
714

    
715
        self.actionVendor.setChecked(True)
716
        if not hasattr(self.actionVendor, 'tag'):
717
            self.actionVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
718
            self.actionVendor.tag.onSuccess.connect(self.onVendorCreated)
719
            self.actionVendor.tag.onRejected.connect(self.onCommandRejected)
720

    
721
        self.graphicsView.command = self.actionVendor.tag
722

    
723
    def onVendorCreated(self):
724
        '''
725
            @brief      add created vendor polygon area to scene
726
            @author     euisung
727
            @date       2019.04.29
728
        '''
729
        try:
730
            count = len(self.actionVendor.tag._polyline._vertices)
731
            if count > 2:
732
                qPoints = []
733
                points = []
734
                for point in self.actionVendor.tag._polyline._vertices:
735
                    points.append([round(point[0]), round(point[1])])
736
                    qPoints.append(QPoint(round(point[0]), round(point[1])))
737
                vendorArea = QPolygonF(qPoints)
738
                vendorItem = QEngineeringVendorItem(vendorArea, points)
739
                vendorItem.area = 'Drawing'
740
                vendorItem.transfer.onRemoved.connect(self.itemRemoved)
741
                self.graphicsView.scene.addItem(vendorItem)
742
        finally:
743
            self.graphicsView.scene.removeItem(self.actionVendor.tag._polyline)
744
            self.actionVendor.tag.reset()
745

    
746
    '''
747
        @brief      Fit Window
748
        @author     Jeongwoo
749
        @date       2018.06.27
750
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
751
    '''
752
    def fitWindow(self, action):
753
        self.graphicsView.useDefaultCommand()
754
        self.graphicsView.zoomImageInit()
755

    
756
    def onConvertPDFToImage(self):
757
        """
758
        @brief      convert to selected pdf to image
759
        @author     humkyung 
760
        @date       2018.07.09
761
        @history    Euisung 2018.10.11 hide shell
762
        """
763
        try: 
764
            filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)) , 'bin64', 'PDF_TO_IMAGE.exe')
765
            subprocess.call(filePath, shell = False)
766
        except Exception as ex:
767
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
768

    
769
    '''
770
        @brief      selection changed
771
        @author     humkyung
772
        @date       2018.06.27
773
        @history    humkung 2018.07.08 call tree widget's findItem
774
    '''
775
    def onSelectionChanged(self):
776
        items = [item for item in self.graphicsView.scene.selectedItems() if issubclass(type(item), SymbolSvgItem) or \
777
            type(item) is QEngineeringLineItem or type(item) is QEngineeringLineNoTextItem or type(item) is QEngineeringNoteItem or type(item) is QEngineeringUnknownItem]
778
        if items:
779
            item = items[-1]
780
            self.itemTreeWidget.findItem(item)
781
            self.resultPropertyTableWidget.show_item_property(item)
782
            if type(item) is QEngineeringErrorItem:
783
                for index in range(self.tableWidgetInconsistency.rowCount()):
784
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
785
                        self.tableWidgetInconsistency.selectRow(index)
786
                        break
787
        else:
788
            self.resultPropertyTableWidget.show_item_property(None)
789
        
790
    '''
791
        @brief      Initialize scene and itemTreeWidget
792
        @author     Jeongwoo
793
        @date       2018.06.14
794
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
795
    '''
796
    def onInitializeScene(self, action):
797
        if not self.graphicsView.hasImage():
798
            self.actionEquipment.setChecked(False)
799
            self.showImageSelectionMessageBox()
800

    
801
            return
802

    
803
        msg = QMessageBox()
804
        msg.setIcon(QMessageBox.Critical)
805
        msg.setText(self.tr('선택한 인식한 항목들을 삭제하시겠습니까?\n삭제된 항목들은 복구할 수 없습니다.'))
806
        msg.setWindowTitle(self.tr("항목 삭제"))
807
        msg.setStandardButtons(QMessageBox.Ok|QMessageBox.Cancel)
808
        if QMessageBox.Ok == msg.exec_():
809

    
810
            appDocData = AppDocData.instance()
811
            appDocData.clearItemList(True)
812

    
813
            items = self.graphicsView.scene.items()
814
            for item in items:
815
                if type(item) is not QGraphicsPixmapItem:
816
                    self.graphicsView.scene.removeItem(item)
817

    
818
                    if type(item) is QEngineeringLineNoTextItem:
819
                        self.removedItems['LINE'].append(str(item.uid))
820
                    elif type(item) is QEngineeringInstrumentItem:
821
                        self.removedItems['INST'].append(str(item.uid))
822
                    elif type(item) is QEngineeringEquipmentItem:
823
                        self.removedItems['EQUIP'].append(str(item.uid))
824
                    elif type(item) is QEngineeringNoteItem:
825
                        self.removedItems['NOTE'].append(str(item.uid))
826
                    
827
            if self.path is not None:
828
                baseName = os.path.basename(self.path)
829
                self.itemTreeWidget.setCurrentPID(baseName)
830

    
831
    '''
832
        @brief      Manage Checkable Action statement
833
        @author     Jeongwoo
834
        @date       2018.05.10
835
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
836
    '''
837
    def actionGroupTriggered(self, action):
838
        if self.graphicsView.command is not None:
839
            self.graphicsView.useDefaultCommand()
840

    
841
        for _action in self.actionGroup.actions():
842
            _action.setChecked(False)
843

    
844
        action.setChecked(True)
845

    
846
    '''
847
        @brief      Create Equipment
848
        @author     Jeongwoo
849
        @date       18.05.03
850
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
851
    '''
852
    def createEquipment(self):
853
        if not self.graphicsView.hasImage():
854
            self.actionEquipment.setChecked(False)
855
            self.showImageSelectionMessageBox()
856
            return
857
        if self.actionEquipment.isChecked():
858
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget, self.dirTreeWidget)
859
        else:
860
            self.graphicsView.useDefaultCommand()
861

    
862

    
863
    '''
864
        @brief      Create Nozzle
865
        @author     Jeongwoo
866
        @date       2018.05.03
867
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
868
    '''
869
    def createNozzle(self):
870
        if not self.graphicsView.hasImage():
871
            self.actionNozzle.setChecked(False)
872
            self.showImageSelectionMessageBox()
873
            return
874
        if self.actionNozzle.isChecked():
875
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget, self.dirTreeWidget)
876
        else:
877
            self.graphicsView.useDefaultCommand()
878

    
879
    '''
880
        @brief      Area OCR
881
        @author     Jeongwoo
882
        @date       18.04.18
883
        @history    2018.05.02  Jeongwoo    Change graphicsView.command by actionOCR checked state
884
                                            Show MessageBox when imageviewer doesn't have image
885
    '''
886
    def onAreaOcr(self):
887
        if not self.graphicsView.hasImage():
888
            self.actionOCR.setChecked(False)
889
            self.showImageSelectionMessageBox()
890
            return
891

    
892
        if self.actionOCR.isChecked():
893
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
894
            cmd.onSuccess.connect(self.onRecognizeText)
895
            cmd.onRejected.connect(self.onCommandRejected)
896
            self.graphicsView.command = cmd
897
        else:
898
            self.graphicsView.useDefaultCommand()
899
    
900
    '''
901
        @brief      show text recognition dialog
902
        @author     humkyung
903
        @date       2018.08.08
904
    '''
905
    def onRecognizeText(self, x, y, width, height):
906
        from OcrResultDialog import QOcrResultDialog
907

    
908
        try:
909
            image = self.graphicsView.image().copy(x, y, width, height)
910
            dialog = QOcrResultDialog(self.graphicsView, image, QRectF(x, y, width, height))
911
            (isAccept, textInfoList) = dialog.showDialog()
912
            if isAccept:
913
                if textInfoList is not None and len(textInfoList) > 0:
914
                    docData = AppDocData.instance()
915
                    for textInfo in textInfoList:
916
                        x = textInfo.getX()
917
                        y = textInfo.getY()
918
                        angle = textInfo.getAngle()
919
                        text = textInfo.getText()
920
                        width = textInfo.getW()
921
                        height = textInfo.getH()
922
                        item = TextItemFactory.instance().createTextItem(textInfo)
923
                        if item is not None:
924
                            item.loc = (x, y)
925
                            item.size = (width, height)
926
                            item.angle = angle
927
                            item.setDefaultTextColor(Qt.blue)
928
                            item.addTextItemToScene(self.graphicsView.scene)
929
                            item.transfer.onRemoved.connect(self.itemRemoved)
930
                        else:
931
                            message = 'error occured({}) in {}:{}'.format('텍스트 생성에 실패했습니다.', sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
932
                            self.addMessage.emit(MessageType.Normal, message)
933
                else:
934
                    QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
935
        except Exception as ex:
936
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
937
            self.addMessage.emit(MessageType.Error, message)
938

    
939
    '''
940
        @brief  area configuration
941
    '''
942
    def areaConfiguration(self):
943
        from ConfigurationAreaDialog import QConfigurationAreaDialog
944
        if not self.graphicsView.hasImage():
945
            self.showImageSelectionMessageBox()
946
            return
947
        self.dlgConfigurationArea = QConfigurationAreaDialog(self)
948
        self.dlgConfigurationArea.show()
949
        self.dlgConfigurationArea.exec_()
950
        self.graphicsView.useDefaultCommand()
951

    
952
    '''
953
        @brief  configuration
954
    '''
955
    def configuration(self):
956
        from ConfigurationDialog import QConfigurationDialog
957

    
958
        self.dlgConfiguration = QConfigurationDialog(self)
959
        self.dlgConfiguration.show()
960
        if QDialog.Accepted == self.dlgConfiguration.exec_():
961
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
962
            QEngineeringInstrumentItem.INST_COLOR = None
963

    
964
    '''
965
        @brief  show nominal diameter dialog 
966
        @author humkyung
967
        @date   2018.06.28
968
    '''
969
    def onShowCodeTable(self):
970
        from CodeTableDialog import QCodeTableDialog
971

    
972
        dlg = QCodeTableDialog(self)
973
        dlg.exec_()
974

    
975
    '''
976
        @brief  show HMB data
977
        @author humkyung
978
        @date   2018.07.11
979
    '''
980
    def onHMBData(self):
981
        from HMBDialog import QHMBDialog
982

    
983
        dlg = QHMBDialog(self)
984
        dlg.show()
985
        dlg.exec_()
986

    
987
    '''
988
        @brief  show line data list 
989
        @author humkyung
990
        @date   2018.05.03
991
    '''
992
    def showItemDataList(self):
993
        from ItemDataExportDialog import QItemDataExportDialog
994

    
995
        self.dlgLineDataList = QItemDataExportDialog(self)
996
        self.dlgLineDataList.exec_()
997

    
998
    def showTextDataList(self):
999
        '''
1000
            @brief      show all text item in scene
1001
            @author     euisung
1002
            @date       2019.04.18
1003
        '''
1004
        try:
1005
            if not self.graphicsView.hasImage():
1006
                self.showImageSelectionMessageBox()
1007
                return
1008

    
1009
            dialog = QTextDataListDialog(self)
1010
            dialog.exec_()
1011
        except Exception as ex:
1012
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1013
            self.addMessage.emit(MessageType.Error, message)
1014

    
1015
    '''
1016
        @brief  Show Image Selection Guide MessageBox
1017
        @author Jeongwoo
1018
        @date   2018.05.02
1019
    '''
1020
    def showImageSelectionMessageBox(self):
1021
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1022
        
1023
    '''
1024
        @brief  change selected lines' type by selected line type
1025
        @author humkyung
1026
        @date   2018.06.27
1027
    '''
1028
    def onLineTypeChanged(self, param):
1029
        lineType = self.lineComboBox.itemText(param)
1030
        selected = [item for item in self.graphicsView.scene.selectedItems() if type(item) is QEngineeringLineItem]
1031
        if selected:
1032
            for item in selected:
1033
                item.lineType = lineType
1034

    
1035
    def display_colors(self, value):
1036
        """ display colors """
1037
        from DisplayColors import DisplayColors
1038
        from DisplayColors import DisplayOptions
1039

    
1040
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value == True else DisplayOptions.DisplayByLineType
1041
        if hasattr(self, 'graphicsView'):
1042
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1043
            DisplayColors.instance().save_data()
1044

    
1045
    '''
1046
        @brief      Open image drawing file and then display it
1047
        @author     humkyung
1048
        @date       2018.??.??
1049
        @history    18.04.23 Jeongwoo    Add AppDocData.instance().setCurrentPidSource
1050
                    18.04.23 Jeongwoo    Add Store Set Current Pid Image on AppDocData
1051
                    18.05.02 Jeongwoo    Add useDefaultCommand()
1052
                    humkyung 2018.05.24 load recognition result file if exists
1053
                    Jeongwoo 2018.05.29 load data on xml if xml file exist
1054
                    humkyung 2018.08.22 clear scene before loading xml file
1055
    '''
1056
    def onOpenImageDrawing(self, path=None):
1057
        from Drawing import Drawing
1058
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
1059

    
1060
        try:
1061
            appDocData = AppDocData.instance()
1062
            project = appDocData.getCurrentProject()
1063
            
1064
            for item in self.graphicsView.scene.items():
1065
                self.graphicsView.scene.removeItem(item)
1066

    
1067
            self.path = self.graphicsView.loadImageFromFile(project.getDrawingFilePath(), path if type(path) is str else '')
1068
            if os.path.isfile(self.path):
1069
                appDocData.clear()
1070
                self.graphicsView.useDefaultCommand()
1071

    
1072
                appDocData.setImgFilePath(self.path)
1073
                appDocData.activeDrawing = Drawing(appDocData.imgName)
1074
                appDocData.setCurrentPidSource(Image.open(self.path))
1075
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
1076

    
1077
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1078
                for childIdex in range(drawingList.childCount()):
1079
                    drawingList.child(childIdex).setCheckState(0, Qt.Unchecked)
1080
                for childIdex in range(drawingList.childCount()):
1081
                    child = drawingList.child(childIdex)
1082
                    if child.text(0).replace('.png', '') == appDocData.activeDrawing.name:
1083
                        child.setCheckState(0, Qt.Checked)
1084
                        break
1085

    
1086
                ## Load data on xml
1087
                path = os.path.join(appDocData.getCurrentProject().getTempPath(), appDocData.imgName + '.xml')
1088
                count = 0
1089
                if os.path.isfile(path):
1090
                    for child in parse(path).getroot().getchildren():
1091
                        count = count + len(child.getchildren())
1092
                if count > 0:
1093
                    try:
1094
                        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100, self) if not hasattr(self, 'progress') else self.progress
1095
                        self.progress.setWindowModality(Qt.WindowModal)
1096
                        self.progress.setAutoReset(True)
1097
                        self.progress.setAutoClose(True)
1098
                        self.progress.setMinimum(0)
1099
                        self.progress.resize(600,100)
1100
                        self.progress.setWindowTitle(self.tr("Reading file..."))
1101
                        self.progress.show()
1102

    
1103
                        self.loadRecognitionResultFromXml(path)
1104
                        #self.checkAttribute()
1105
                    finally:
1106
                        self.progress.setValue(self.progress.maximum())
1107
                        self.progress.hide()
1108
                self.changeViewCheckedState(True)
1109
        except Exception as ex:
1110
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1111
            self.addMessage.emit(MessageType.Error, message)
1112

    
1113
        return self.path
1114

    
1115
    def changeViewCheckedState(self, checked, clear=True):
1116
        '''
1117
            @brief      change view checked state
1118
            @author     euisung
1119
            @date       2019.03.06
1120
        '''
1121
        #self.actionImage_Drawing.setChecked(checked)
1122
        self.actionViewText.setChecked(checked)
1123
        self.actionViewSymbol.setChecked(checked)
1124
        self.actionViewLine.setChecked(checked)
1125
        self.actionViewUnknown.setChecked(checked)
1126
        self.actionViewInconsistency.setChecked(checked)
1127
        self.actionViewVendor_Area.setChecked(not checked)
1128
        self.actionDrawing_Only.setChecked(not checked)
1129
        if clear:
1130
            self.tableWidgetInconsistency.clearContents()
1131
            self.tableWidgetInconsistency.setRowCount(0)
1132

    
1133
    def onViewDrawingOnly(self, isChecked):
1134
        '''
1135
            @brief  visible/invisible except image drawing
1136
            @author euisung
1137
            @date   2019.04.22
1138
        '''
1139
        self.changeViewCheckedState(not isChecked, False)
1140
        for item in self.graphicsView.scene.items():
1141
            if type(item) is not QGraphicsPixmapItem:
1142
                item.setVisible(not isChecked)
1143

    
1144
    '''
1145
        @brief  visible/invisible image drawing
1146
        @author humkyung
1147
        @date   2018.06.25
1148
    '''
1149
    def onViewImageDrawing(self, isChecked):
1150
        for item in self.graphicsView.scene.items():
1151
            if type(item) is QGraphicsPixmapItem:
1152
                item.setVisible(isChecked)
1153
                break
1154

    
1155
    '''
1156
        @brief  visible/invisible Text 
1157
        @author humkyung
1158
        @date   2018.06.28
1159
    '''
1160
    def onViewText(self, isChecked):
1161
        selected = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
1162
        for item in selected:
1163
            item.setVisible(isChecked)
1164

    
1165
    '''
1166
        @brief  visible/invisible Symbol 
1167
        @author humkyung
1168
        @date   2018.06.28
1169
    '''
1170
    def onViewSymbol(self, isChecked):
1171
        selected = [item for item in self.graphicsView.scene.items() if (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1172
        for item in selected:
1173
            item.setVisible(isChecked)
1174

    
1175
    '''
1176
        @brief  visible/invisible Line
1177
        @author humkyung
1178
        @date   2018.06.28
1179
    '''
1180
    def onViewLine(self, isChecked):
1181
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem]
1182
        for item in selected:
1183
            item.setVisible(isChecked)
1184

    
1185
    def onViewInconsistency(self, isChecked):
1186
        '''
1187
            @brief  visible/invisible Inconsistency
1188
            @author euisung
1189
            @date   2019.04.03
1190
        '''
1191
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringErrorItem]
1192
        for item in selected:
1193
            item.setVisible(isChecked)
1194

    
1195
    '''
1196
        @brief  visible/invisible Unknown 
1197
        @author humkyung
1198
        @date   2018.06.28
1199
    '''
1200
    def onViewUnknown(self, isChecked):
1201
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringUnknownItem]
1202
        for item in selected:
1203
            item.setVisible(isChecked)
1204

    
1205
    def onViewVendorArea(self, isChecked):
1206
        '''
1207
            @brief  visible/invisible Vendor Area
1208
            @author euisung
1209
            @date   2019.04.29
1210
        '''
1211
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringVendorItem]
1212
        for item in selected:
1213
            item.setVisible(isChecked)
1214

    
1215

    
1216
    '''
1217
        @brief  create a symbol
1218
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1219
                                            Add SymbolSvgItem
1220
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1221
                                            Change method to make svg and image path
1222
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1223
    '''
1224
    def onCreateSymbolClicked(self):
1225
        cmd = FenceCommand.FenceCommand(self.graphicsView)
1226
        cmd.onSuccess.connect(self.onAreaSelected)
1227
        self.graphicsView.command = cmd
1228
        QApplication.setOverrideCursor(Qt.CrossCursor)
1229

    
1230
    '''
1231
        @brief      show SymbolEditorDialog with image selected by user
1232
        @author     humkyung
1233
        @date       2018.07.20
1234
    '''
1235
    def onAreaSelected(self, x, y, width, height):
1236
        try:
1237
            image = self.graphicsView.image()
1238
            if image is not None:
1239
                symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height), AppDocData.instance().getCurrentProject())
1240
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1241
                self.dirTreeWidget.initDirTreeWidget()
1242
                if isAccepted:
1243
                    if isImmediateInsert:
1244
                        svgPath = newSym.getSvgFileFullPath()
1245
                        img = cv2.imread(newSym.getImageFileFullPath(), 1)
1246
                        w, h = (0, 0)
1247
                        if len(img.shape[::-1]) == 2:
1248
                            w, h = img.shape[::-1]
1249
                        else:
1250
                            _chan, w, h = img.shape[::-1]
1251
                        svg = SymbolSvgItem(svgPath)
1252
                        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('/')], newSym.getBaseSymbol(), newSym.getAdditionalSymbol(), newSym.getHasInstrumentLabel)
1253

    
1254
                        svg.transfer.onRemoved.connect(self.itemTreeWidget.itemRemoved)
1255
                        svg.addSvgItemToScene(self.graphicsView.scene)
1256
                        for connector in svg.connectors:
1257
                            self.graphicsView.scene.addItem(connector)
1258
        finally:
1259
            self.graphicsView.useDefaultCommand()
1260
            QApplication.restoreOverrideCursor()
1261
    
1262
    '''
1263
        @brief      create a line
1264
        @author     humkyung
1265
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
1266
    '''
1267
    def onPlaceLine(self):        
1268
        if not self.graphicsView.hasImage():
1269
            self.actionLine.setChecked(False)
1270
            self.showImageSelectionMessageBox()
1271
            return
1272

    
1273
        self.actionLine.setChecked(True)
1274
        if not hasattr(self.actionLine, 'tag'):
1275
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
1276
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
1277
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
1278

    
1279
        self.graphicsView.command = self.actionLine.tag
1280

    
1281
    '''
1282
        @brief      add created lines to scene
1283
        @author     humkyung
1284
        @date       2018.07.23
1285
    '''
1286
    def onLineCreated(self):
1287
        from EngineeringConnectorItem import QEngineeringConnectorItem
1288

    
1289
        try:
1290
            count = len(self.actionLine.tag._polyline._vertices)
1291
            if count > 1:
1292
                items = []
1293

    
1294
                lineType = self.lineComboBox.currentText()
1295
                for index in range(count - 1):
1296
                    start = self.actionLine.tag._polyline._vertices[index]
1297
                    end  = self.actionLine.tag._polyline._vertices[index + 1]
1298
                    
1299
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1300
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1301
                    lineItem.lineType = lineType
1302
                    if items:
1303
                        lineItem.connect_if_possible(items[-1], 5)
1304
                    else:
1305
                        pt = lineItem.startPoint()
1306
                        selected = [item for item in self.graphicsView.scene.items(QPointF(pt[0], pt[1])) if type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
1307
                        if selected:
1308
                            lineItem.connect_if_possible(selected[0].parent if type(selected[0]) is QEngineeringConnectorItem else selected[0], 5)
1309
                    
1310
                    items.append(lineItem)
1311
                    self.graphicsView.scene.addItem(lineItem)
1312

    
1313
                pt = items[-1].endPoint()
1314
                selected = [item for item in self.graphicsView.scene.items(QPointF(pt[0], pt[1])) if type(item) is QEngineeringConnectorItem and item.parent is not items[-1]]
1315
                if selected:
1316
                    items[-1].connect_if_possible(selected[0].parent, 5)
1317
        finally:
1318
            self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1319
            self.actionLine.tag.reset()
1320

    
1321
    '''
1322
        @brief      refresh scene
1323
        @author     humkyung
1324
        @date       2018.07.23
1325
    '''
1326
    def onCommandRejected(self, cmd):
1327
        try:
1328
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
1329
                self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1330
                self.graphicsView.scene.update()
1331
                self.actionLine.tag.reset()
1332

    
1333
                self.actionLine.setChecked(False)
1334
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
1335
                self.actionZoom.setChecked(False)
1336
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
1337
                self.actionOCR.setChecked(False)
1338
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
1339
                self.actionVendor.setChecked(False)
1340
        finally:
1341
            self.graphicsView.useDefaultCommand()
1342
     
1343
    '''
1344
        @brief      restore to default command when user press Escape key
1345
        @author     humkyung 
1346
        @date       2018.08.09
1347
        
1348
    '''
1349
    def keyPressEvent(self, event):
1350
        try:
1351
            if event.key() == Qt.Key_Escape:
1352
                checked = self.actionGroup.checkedAction()
1353
                if checked:
1354
                    checked.setChecked(False)
1355
                    self.graphicsView.useDefaultCommand()
1356
            elif event.key() == Qt.Key_1:
1357
                if self.actionImage_Drawing.isChecked():
1358
                    self.onViewImageDrawing(False)
1359
                    self.actionImage_Drawing.setChecked(False)
1360
                else:
1361
                    self.onViewImageDrawing(True)
1362
                    self.actionImage_Drawing.setChecked(True)
1363
            elif event.key() == Qt.Key_2:
1364
                if self.actionViewText.isChecked():
1365
                    self.onViewText(False)
1366
                    self.actionViewText.setChecked(False)
1367
                else:
1368
                    self.onViewText(True)
1369
                    self.actionViewText.setChecked(True)
1370
            elif event.key() == Qt.Key_3:
1371
                if self.actionViewSymbol.isChecked():
1372
                    self.onViewSymbol(False)
1373
                    self.actionViewSymbol.setChecked(False)
1374
                else:
1375
                    self.onViewSymbol(True)
1376
                    self.actionViewSymbol.setChecked(True)
1377
            elif event.key() == Qt.Key_4:
1378
                if self.actionViewLine.isChecked():
1379
                    self.onViewLine(False)
1380
                    self.actionViewLine.setChecked(False)
1381
                else:
1382
                    self.onViewLine(True)
1383
                    self.actionViewLine.setChecked(True)
1384
            elif event.key() == Qt.Key_5:
1385
                if self.actionViewUnknown.isChecked():
1386
                    self.onViewUnknown(False)
1387
                    self.actionViewUnknown.setChecked(False)
1388
                else:
1389
                    self.onViewUnknown(True)
1390
                    self.actionViewUnknown.setChecked(True)
1391
            elif event.key() == Qt.Key_6:
1392
                if self.actionViewInconsistency.isChecked():
1393
                    self.onViewInconsistency(False)
1394
                    self.actionViewInconsistency.setChecked(False)
1395
                else:
1396
                    self.onViewInconsistency(True)
1397
                    self.actionViewInconsistency.setChecked(True)
1398
            elif event.key() == Qt.Key_7:
1399
                if self.actionViewVendor_Area.isChecked():
1400
                    self.onViewVendorArea(False)
1401
                    self.actionViewVendor_Area.setChecked(False)
1402
                else:
1403
                    self.onViewVendorArea(True)
1404
                    self.actionViewVendor_Area.setChecked(True)
1405
            elif event.key() == 96: # '`' key
1406
                if self.actionDrawing_Only.isChecked():
1407
                    self.onViewDrawingOnly(False)
1408
                    self.actionDrawing_Only.setChecked(False)
1409
                else:
1410
                    self.onViewDrawingOnly(True)
1411
                    self.actionDrawing_Only.setChecked(True)
1412
                    
1413
            QMainWindow.keyPressEvent(self, event)
1414
        except Exception as ex:
1415
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1416
            self.addMessage.emit(MessageType.Error, message)
1417
    
1418
    def recognizeBatch(self, MainWindow):
1419
        '''
1420
            @brief      batch recognize symbol, text and line
1421
            @author     euisung
1422
            @date       2018.11.23
1423
        
1424
        '''
1425
        from datetime import datetime
1426
        from RecognitionDialog import QRecognitionDialog
1427

    
1428
        appDocData = AppDocData.instance()
1429
        project = appDocData.getCurrentProject()
1430
        appDocData.needReOpening = None
1431
        currentPid = None
1432
        
1433
        if self.graphicsView.hasImage():
1434
            currentPid = appDocData.activeDrawing.name
1435

    
1436
        drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1437
        drawingCount = drawingTop.childCount()
1438
        checkedTreeItems = []
1439
        checkedDrawingPath = []
1440
        for drawing in range(drawingCount):
1441
            drawingChild = drawingTop.child(drawing)
1442
            if drawingChild.checkState(0) == 2:
1443
                checkedTreeItems.append(drawingChild)
1444
                checkedDrawingPath.append(os.path.join(project.getDrawingFilePath(), drawingChild.data(0, 0)))
1445
                if currentPid is not None and drawingChild.data(0, 0).find(currentPid) is 0:
1446
                    appDocData.needReOpening = False # later check need reopening at drawUnknownItems()
1447
                    currentPid = drawingChild.data(0, 0)
1448

    
1449
        if len(checkedDrawingPath) == 0:
1450
            self.showImageSelectionMessageBox()
1451
            return
1452

    
1453
        try:
1454
            self.onClearLog()
1455
            self.dlg = QRecognitionDialog(self, checkedDrawingPath, True)
1456
            self.dlg.exec_()
1457
            if self.dlg.isAccepted == True:
1458
                pass
1459

    
1460
            if appDocData.needReOpening == True:
1461
                drawing = os.path.join(appDocData.getCurrentProject().getDrawingFilePath(), currentPid)
1462
                self.onOpenImageDrawing(drawing)
1463

    
1464
            # save working date-time
1465
            drawings = appDocData.getDrawings()
1466
            checkedDrawings = []
1467
            for checkedTreeItem in checkedTreeItems:
1468
                for drawing in drawings:
1469
                    if checkedTreeItem.data(0, 0) == drawing[1]:
1470
                        if drawing[0]:
1471
                            drawing[2] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1472
                            checkedDrawings.append(drawing)
1473
                            checkedTreeItem.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1474
            appDocData.saveDrawings(checkedDrawings)
1475
            self.changeViewCheckedState(True)
1476
            # up to here
1477
        except Exception as ex:
1478
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1479
            self.addMessage.emit(MessageType.Error, message)
1480

    
1481
    '''
1482
        @brief      recognize symbol and text
1483
        @author     humkyung
1484
        @date       2018.04.??
1485
        @history    2018.04.16  humkyung    execute line no tracing
1486
                    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
1487
                    2018.05.25  Jeongwoo    Add parameter on QRecognitionDialog.__init__() and Move thread to QRecognitionDialog
1488
                                            Remove codes below if self.dlg.isAccepted == True
1489
                    2018.05.29  Jeongwoo    Remove connects and comments
1490
                    humkyung 2018.11.05 save working date-time
1491
    '''
1492
    def recognize(self, MainWindow):
1493
        from datetime import datetime
1494
        from RecognitionDialog import QRecognitionDialog
1495

    
1496
        if not self.graphicsView.hasImage():
1497
            self.showImageSelectionMessageBox()
1498
            return
1499

    
1500
        try:
1501
            self.removedItems['LINE'] = []
1502
            self.removedItems['EQUIP'] = []
1503
            self.removedItems['INST'] = []
1504
            self.removedItems['NOTE'] = []
1505

    
1506
            appDocData = AppDocData.instance()
1507

    
1508
            self.onClearLog()
1509
            appDocData.needReOpening = False
1510
            drawingList = []
1511
            drawingList.append(self.path)
1512
            self.dlg = QRecognitionDialog(self, drawingList, False)
1513
            self.dlg.exec_()
1514

    
1515
            if appDocData.needReOpening == True:
1516
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
1517
                self.drawDetectedItemsToScene()
1518
                
1519
                # save working date-time
1520
                drawings = appDocData.getDrawings()
1521
                drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing[1])[0]]
1522
                if drawing[0]:
1523
                    drawing[0][2] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1524
                    appDocData.saveDrawings(drawing)
1525

    
1526
                currentPid = appDocData.activeDrawing.name
1527

    
1528
                drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1529
                drawingCount = drawingTop.childCount()
1530
                
1531
                for drawing in range(drawingCount):
1532
                    drawingChild = drawingTop.child(drawing)
1533
                    if drawingChild.data(0, 0).find(currentPid) is 0:
1534
                        drawingChild.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1535
                self.changeViewCheckedState(True)
1536
                # up to here
1537
        except Exception as ex:
1538
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1539
            self.addMessage.emit(MessageType.Error, message)
1540

    
1541
    '''
1542
        @brief      remove item from tree widget and then remove from scene
1543
        @date       2018.05.25
1544
        @author     Jeongwoo
1545
    '''
1546
    def itemRemoved(self, item):
1547
        try:
1548
            self.itemTreeWidget.itemRemoved(item)
1549

    
1550
            '''
1551
            if type(item) is QEngineeringLineNoTextItem:
1552
                self.removedItems['LINE'].append(str(item.uid))
1553
            elif type(item) is QEngineeringInstrumentItem:
1554
                self.removedItems['INST'].append(str(item.uid))
1555
            elif type(item) is QEngineeringEquipmentItem:
1556
                self.removedItems['EQUIP'].append(str(item.uid))
1557
            elif type(item) is QEngineeringNoteItem:
1558
                self.removedItems['NOTE'].append(str(item.uid))
1559
            '''
1560

    
1561
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'connectors') and [connector for connector in _item.connectors if connector.connectedItem is item]]
1562
            for match in matches:
1563
                for connector in match.connectors:
1564
                    if connector.connectedItem is item: connector.connectedItem = None
1565

    
1566
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'remove_assoc_item')]
1567
            for _item in matches:
1568
                _item.remove_assoc_item(item)
1569

    
1570
            matches = [_item for _item in self.graphicsView.scene.items() if type(_item) is QEngineeringLineNoTextItem]
1571
            for match in matches:
1572
                if item is match.prop('From'):
1573
                    match.set_property('From', None)
1574
                elif item is match.prop('To'):
1575
                    match.set_property('To', None)
1576

    
1577
                for run in match.runs:
1578
                    if item in run.items:
1579
                        index = run.items.index(item)
1580
                        run.items.pop(index)
1581
            """
1582
            if hasattr(item, 'connectors'):
1583
                for sceneItem in self.graphicsView.scene.items():
1584
                    if hasattr(sceneItem, 'connectors'):
1585
                        for sceneConnector in sceneItem.connectors:
1586
                            if sceneConnector.connectedItem is not None and item.uid == sceneConnector.connectedItem.uid:
1587
                                sceneConnector.connectedItem = None
1588
            """
1589

    
1590
            if item.scene() is not None: item.scene().removeItem(item)
1591
        except Exception as ex:
1592
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1593
            self.addMessage.emit(MessageType.Error, message)
1594

    
1595
    '''
1596
        @brief      recognize line
1597
        @author     humkyung
1598
        @date       2018.04.19
1599
        @history    Jeongwoo 2018.04.26 Variable name changed (texts → lineNos)
1600
                                        TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem)
1601
                    humkyung 2018.04.26 remove small objects before recognizing line
1602
                    Jeongwoo 2018.05.02 Show MessageBox when imageviewer doesn't have image
1603
                    Jeongwoo 2018.05.25 Move codes about LineDetector
1604
                    humkyung 2018.06.17 show progress dialog
1605
    '''
1606
    def connect_attributes(self, MainWindow):
1607
        from LineNoTracer import LineNoTracer
1608
        from ConnectAttrDialog import QConnectAttrDialog
1609

    
1610
        if not self.graphicsView.hasImage():
1611
            self.showImageSelectionMessageBox()
1612
            return
1613

    
1614
        try:
1615
            self.dlgConnectAttr = QConnectAttrDialog(self, self.graphicsView)
1616
            if QDialog.Accepted == self.dlgConnectAttr.exec_():
1617
                self.itemTreeWidget.InitLineNoItems()
1618

    
1619
                # construct line no item
1620
                line_nos = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineNoTextItem]
1621
                for line_no in line_nos:
1622
                    item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1623
                    connectedItems = line_no.getConnectedItems()
1624
                    for connectedItem in connectedItems:
1625
                        if issubclass(type(connectedItem), SymbolSvgItem): 
1626
                            self.itemTreeWidget.addTreeItem(item, connectedItem)
1627
                # up to here
1628

    
1629
                self.graphicsView.invalidateScene()
1630
        except Exception as ex:
1631
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1632
            self.addMessage.emit(MessageType.Error, message)
1633

    
1634
    '''
1635
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
1636
                                            SvgItem and TextItem Connect with method in this class
1637
                                            Change method to add GraphicsItem
1638
                    2018.05.28  Jeongwoo    Make QGraphicsItem by symbol, text object. Not xml
1639
                    2018.05.29  Jeongwoo    Change method name and Moved from QRecognitionDialog
1640
                    2018.05.30  Jeongwoo    Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol)
1641
                                            Change Method name and seperate each item
1642
                    humkyung 2018.06.11     display difference between original and recognized image
1643
                    Jeongwoo 2018.06.18     Update Scene after all item added
1644
                    2018.11.05  euisung     add save note item because of dependency
1645
                    2018.11.05  euisung     add db delete process before save
1646
                    2018.11.12  euisung     add title block properties
1647
                    2018.11.12  euisung     db part move new method to dbUpdate
1648
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1649
                    2018.11.29  euisung     change name drawDetectedItems() -> createDetectedItems
1650
    '''
1651
    def createDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList):
1652
        try:
1653
            appDocData = AppDocData.instance()
1654

    
1655
            QApplication.processEvents()
1656
            self.createDetectedSymbolItem(symbolList)
1657
            QApplication.processEvents()
1658
            self.createDetectedTextItem(textInfoList)
1659
            QApplication.processEvents()
1660
            self.createDetectedOtherTextItem(otherTextInfoList)
1661
            QApplication.processEvents()
1662
            self.createDetectedTitleBlockTextItem(titleBlockTextInfoList)
1663

    
1664
            self.dbUpdate()
1665

    
1666
            # update scene
1667
            #self.graphicsView.scene.update(self.graphicsView.sceneRect())
1668
        except Exception as ex:
1669
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1670
            self.addMessage.emit(MessageType.Error, message)
1671

    
1672
    def drawDetectedItemsToScene(self):
1673
        '''
1674
            @brief  add detected items to scene
1675
            @author euisung
1676
            @date   2018.11.26
1677
        '''
1678
        appDocData = AppDocData.instance()
1679

    
1680
        try:
1681
            for symbol in appDocData.symbols:
1682
                if issubclass(type(symbol), SymbolSvgItem):
1683
                    self.addSvgItemToScene(symbol)
1684
                else:
1685
                    self.graphicsView.scene.addItem(symbol)
1686

    
1687
            for text in appDocData.texts:
1688
                self.addTextItemToScene(text)
1689

    
1690
            for line in appDocData.lines:
1691
                self.graphicsView.scene.addItem(line)
1692
                line.transfer.onRemoved.connect(self.itemRemoved)
1693
                #for conn in line.connectors:
1694
                #    conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
1695

    
1696
            for unknown in appDocData.unknowns + appDocData.lineIndicators:
1697
                self.graphicsView.scene.addItem(unknown)
1698
        finally:
1699
            # update scene
1700
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1701

    
1702
    def postDetectLineProcess(self):
1703
        '''
1704
            @brief  check allowables among undetected items
1705
            @author euisung
1706
            @date   2018.11.15
1707
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
1708
        '''
1709
        from AppDocData import AppDocData
1710
        from TextItemFactory import TextItemFactory
1711

    
1712
        appDocData = AppDocData.instance()
1713

    
1714
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
1715
        tableDatas = []
1716
        for tableName in tableNames:
1717
            tableNameFormat = tableName.replace(' ','').replace('&&', 'n')
1718
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
1719

    
1720
        items = self.graphicsView.scene.items()
1721
        for item in items:
1722
            if type(item) is not QEngineeringTextItem:
1723
                continue
1724
            text = item.text()
1725
            for tableData in tableDatas:
1726
                for data in tableData:
1727
                    if data[3] == '':
1728
                        continue
1729
                    else:
1730
                        allows = data[3].split(',')
1731
                        for allow in allows:
1732
                            text = text.replace(allow, data[1])
1733

    
1734
            lineItem = TextItemFactory.instance().createTextItem(text)
1735
            if type(lineItem) is QEngineeringLineNoTextItem:
1736
                lineItem.loc = item.loc
1737
                lineItem.size = item.size
1738
                lineItem.angle = item.angle
1739
                lineItem.area = item.area
1740
                #lineItem.addTextItemToScene(self.graphicsView.scene)
1741
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
1742
                item.transfer.onRemoved.emit(item)
1743
                appDocData.lineNos.append(lineItem)
1744
                
1745
    def createDetectedTitleBlockTextItem(self, textInfoList):
1746
        '''
1747
            @brief  draw title block
1748
            @author euisung
1749
            @date   2018.11.12
1750
            @history    2018.11.26  euisung     remove scene dependency
1751
                        2018.11.29  euisung     change name drawDetectedTitleBlockTextItem() -> createDetectedTitleBlockTextItem
1752
        '''
1753
        from TextItemFactory import TextItemFactory
1754
        import math
1755

    
1756
        try:
1757
            appDocData = AppDocData.instance()
1758

    
1759
            # parse texts
1760
            for textInfo in textInfoList:
1761
                if len(textInfo[1]) is 0:
1762
                    continue
1763
                x = textInfo[1][0].getX()
1764
                y = textInfo[1][0].getY()
1765
                width = textInfo[1][0].getW()
1766
                height = textInfo[1][0].getH()
1767
                angle = round(math.radians(textInfo[1][0].getAngle()), 2)
1768
                text = textInfo[1][0].getText()
1769
                item = TextItemFactory.instance().createTextItem(textInfo)
1770

    
1771
                if item is not None:
1772
                    item.loc = (x, y)
1773
                    item.size = (width, height)
1774
                    item.angle = angle
1775
                    item.area = textInfo[0]
1776
                    #self.addTextItemToScene(item)
1777
                    appDocData.texts.append(item)
1778
                    appDocData.allItems.append(item)
1779
        except Exception as ex:
1780
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1781
            self.addMessage.emit(MessageType.Error, message)
1782

    
1783
    '''
1784
        @brief      
1785
        @author     humkyung
1786
        @date       2018.08.23
1787
        @history    2018.11.26  euisung     remove scene dependency
1788
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1789
                    2018.11.    euisung     no more used
1790
                    2018.11.29  euisung     change name drawDetectedLines() -> createDetectedLines
1791
    '''
1792
    def createDetectedLines(self, lineList, worker):
1793
        appDocData = AppDocData.instance()
1794
        area = appDocData.getArea('Drawing')
1795

    
1796
        for pts in lineList:
1797
            processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts])
1798
            processLine.area = 'Drawing'
1799
            #self.graphicsView.scene.addItem(processLine)
1800
            appDocData.lines.append(processLine)
1801
            appDocData.allItems.append(processLine)
1802

    
1803
            if processLine.length() > 100: # TODO: check critical length
1804
                processLine.addFlowArrow()
1805
        
1806
        # re-order process line's start,end according to flow mark
1807
        #worker.arrangeLinePosition(lines, symbols, listWidget)
1808
        # up to here
1809

    
1810
    '''
1811
        history     2018.06.09  humkyung    check length of original and connection point is 2 while parsing
1812
                    2018.11.26  euisung     remove scene dependency
1813
                    2018.11.29  euisung     change name drawDetectedSymbolItem() -> createDetectedSymbolItem
1814
    '''
1815
    def createDetectedSymbolItem(self, symbolList):
1816
        from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
1817
        from SymbolSvgItem import SymbolSvgItem
1818
        import math
1819

    
1820
        try:
1821
            appDocData = AppDocData.instance()
1822
            project = appDocData.getCurrentProject()
1823

    
1824
            searchedMap = []
1825
            for symbol in symbolList:
1826
                pt = [float(x) for x in symbol.getSp()]
1827
                size = [symbol.getWidth(), symbol.getHeight()]
1828
                name = symbol.getName()
1829
                angle = round(math.radians(symbol.getRotatedAngle()), 2)
1830
                _type = symbol.getType()
1831
                flip = symbol.getDetectFlip()
1832
                origin = [0,0]
1833
                if 2 == len(symbol.getOriginalPoint().split(',')):
1834
                    tokens = symbol.getOriginalPoint().split(',')
1835
                    origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
1836
                connPts = []
1837
                if symbol.getConnectionPoint() is not None and symbol.getConnectionPoint() != '':
1838
                    for param in symbol.getConnectionPoint().split('/'):
1839
                        tokens = param.split(',')
1840
                        connPts.append(('AUTO', pt[0] + float(tokens[0]), pt[1] + float(tokens[1]), '0') if len(tokens) == 2 else \
1841
                                       (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), '0') if len(tokens) == 3 else \
1842
                                       (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), tokens[3]) if len(tokens) == 4 else None)
1843

    
1844
                parentSymbol = symbol.getBaseSymbol()
1845
                childSymbol = symbol.getAdditionalSymbol()
1846
                hasInstrumentLabel = symbol.getHasInstrumentLabel()
1847

    
1848
                svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
1849
                if os.path.isfile(svgFilePath):
1850
                    svg = SymbolSvgItem.createItem(_type, svgFilePath, owner=None, flip=flip)
1851
                    #print(pt)
1852
                    #print(origin)
1853
                    svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel)
1854
                    svg.reCalculationRotatedItem()
1855
                    svg.area = 'Drawing'
1856

    
1857
                    # set owner - 2018.07.20 added by humkyung                   
1858
                    matches = [searched for searched in searchedMap if searched[0] == symbol.owner]
1859
                    if len(matches) == 1:
1860
                        svg.owner = matches[0][1]
1861
                    searchedMap.append((symbol, svg))
1862
                    # up to here
1863

    
1864
                    svg.transfer.onRemoved.connect(self.itemRemoved)
1865
                    #self.addSvgItemToScene(svg)
1866
                    appDocData.symbols.append(svg)
1867
                    appDocData.allItems.append(svg)
1868
                else:
1869
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
1870
                    item.isSymbol = True
1871
                    item.angle = angle
1872
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
1873
                    #self.graphicsView.scene.addItem(item)
1874
                    #appDocData.symbols.append(item)
1875
                    appDocData.allItems.append(item)
1876
            # up to here
1877
        except Exception as ex:
1878
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1879
            self.addMessage.emit(MessageType.Error, message)
1880

    
1881
    '''
1882
        @history    2018.06.08  Jeongwoo    Add parameter on round method
1883
        @history    2018.11.02  euisung     Add save note text item
1884
        @history    2018.11.05  euisung     delete save note text item and move to drawDetectedItems()
1885
                    2018.11.26  euisung     remove scene dependency
1886
                    2018.11.29  euisung     change name drawDetectedTextItem() -> createDetectedTextItem
1887
    '''
1888
    def createDetectedTextItem(self, textInfoList):
1889
        from TextItemFactory import TextItemFactory
1890
        import math
1891

    
1892
        try:
1893
            appDocData = AppDocData.instance()
1894

    
1895
            # parse texts
1896
            for textInfo in textInfoList:
1897
                x = textInfo.getX()
1898
                y = textInfo.getY()
1899
                width = textInfo.getW()
1900
                height = textInfo.getH()
1901
                angle = round(math.radians(textInfo.getAngle()), 2)
1902
                text = textInfo.getText()
1903
                if not text: continue
1904

    
1905
                item = TextItemFactory.instance().createTextItem(textInfo)
1906
                if item is not None:
1907
                    item.loc = (x, y)
1908
                    item.size = (width, height)
1909
                    item.angle = angle
1910
                    item.area = 'Drawing'
1911
                    item.transfer.onRemoved.connect(self.itemRemoved)
1912
                    #self.addTextItemToScene(item)
1913
                    appDocData.texts.append(item)
1914
                    appDocData.allItems.append(item)
1915
        except Exception as ex:
1916
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1917
            self.addMessage.emit(MessageType.Error, message)
1918

    
1919
    '''
1920
        @brief      draw detected texts except which in drawing area
1921
        @history    2018.11.29  euisung     change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem
1922
    '''
1923
    def createDetectedOtherTextItem(self, otherTextInfoList):
1924
        from TextItemFactory import TextItemFactory
1925
        import math
1926

    
1927
        try:
1928
            appDocData = AppDocData.instance()
1929

    
1930
            # parse notes
1931
            for textInfoMap in otherTextInfoList:
1932
                if textInfoMap[0]=='Note':
1933
                    pass
1934

    
1935
                for textInfo in textInfoMap[1]:
1936
                    x = textInfo.getX()
1937
                    y = textInfo.getY()
1938
                    width = textInfo.getW()
1939
                    height = textInfo.getH()
1940
                    angle = round(math.radians(textInfo.getAngle()))
1941
                    text = textInfo.getText()
1942

    
1943
                    item = TextItemFactory.instance().createTextItem(textInfo)
1944

    
1945
                    item.loc = (x, y)
1946
                    item.size = (width, height)
1947
                    item.angle = angle
1948
                    item.area = textInfoMap[0]
1949
                    item.transfer.onRemoved.connect(self.itemRemoved)
1950
                    appDocData.texts.append(item)
1951
                    appDocData.allItems.append(item)
1952
        except Exception as ex:
1953
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1954
            self.addMessage.emit(MessageType.Error, message)
1955

    
1956
    '''
1957
        @brief  draw unknown items 
1958
        @author humkyung
1959
        @date   2018.06.12
1960
        @history    2018.06.14  Jeongwoo    Change method to add unknown item
1961
                    2018.06.18  Jeongwoo    Add connect on unknown item
1962
                                            Add [transfer] for using pyqtSignal
1963
                    2018.11.26  euisung     remove scene dependency
1964
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1965
                    2018.11.27  euisung     add save to xml
1966
                    2018.11.29  euisung     change name drawUnknownItems() -> createUnknownItems
1967
    '''
1968
    def createUnknownItems(self, path):
1969
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem 
1970
        from EngineeringLineItem import QEngineeringLineItem
1971
        from EngineeringUnknownItem import QEngineeringUnknownItem
1972
        from SaveWorkCommand import SaveWorkCommand
1973

    
1974
        try:
1975
            docData = AppDocData.instance()
1976
            project = docData.getCurrentProject()
1977
            windowSize = docData.getSlidingWindowSize()
1978

    
1979
            thickness = int(windowSize[1])
1980

    
1981
            if docData.needReOpening is not None:
1982
                docData.needReOpening = True
1983

    
1984
            diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path))
1985
            if os.path.isfile(diffFilePath):
1986
                imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)[1]
1987

    
1988
                ## remove line
1989
                lines = docData.lines
1990
                for line in lines:
1991
                    line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else line.drawToImage(imgDiff, 255, line.thickness)
1992
                cv2.imwrite(diffFilePath, imgDiff)
1993
                ## up to here
1994

    
1995
                imgNot = np.ones(imgDiff.shape, np.uint8)
1996
                cv2.bitwise_not(imgDiff, imgNot)
1997
                imgNot = cv2.dilate(imgNot, np.ones((8,8), np.uint8))
1998

    
1999
                image, contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
2000

    
2001
                ##
2002
                idx = 0
2003
                ##
2004
                smallContours = []
2005
                minimumSize = docData.getConfigs('Filter', 'MinimumSize')
2006
                for contour in contours:
2007
                    [x, y, w, h] = cv2.boundingRect(contour)
2008

    
2009
                    # remove too small one
2010
                    if len(minimumSize) is 1:
2011
                        if (w * h < int(minimumSize[0].value) * int(minimumSize[0].value)):
2012
                            smallContours.append(contour)
2013
                            idx += 1
2014
                            continue
2015

    
2016
                    '''
2017
                    rect = QRectF(x, y, w, h)
2018
                    items = [item for item in diffItems if item.boundingRect().contains(rect)]
2019
                    if len(items) > 0: continue
2020
                    
2021
                    items = [item for item in diffItems if rect.contains(item.boundingRect())]
2022
                    for item in items:
2023
                        diffItems.remove(item)
2024
                    '''
2025

    
2026
                    # create unknown item
2027
                    epsilon = cv2.arcLength(contour, True)*0.001
2028
                    approx = cv2.approxPolyDP(contour, epsilon, True)
2029
                    approx = [pt[0] for pt in approx]
2030
                    resultStr, resultList = self.determineRemainObject(idx, contours, imgNot)
2031
                    if resultStr == 'LineIndicator':
2032
                        item = QEngineeringUnknownItem(approx, 'True', resultList[0], resultList[1])
2033
                        docData.lineIndicators.append(item)
2034
                    elif resultStr == 'MissingLine':
2035
                        pass
2036
                    elif resultStr == 'Unknown':
2037
                        item = QEngineeringUnknownItem(approx, 'False')
2038
                        docData.unknowns.append(item)
2039
                    item.area = 'Drawing'
2040
                    docData.allItems.append(item)
2041
                    item.transfer.onRemoved.connect(self.itemRemoved)
2042
                    idx += 1
2043
                    # up to here                    
2044

    
2045
                imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1)
2046
                notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path))
2047
                cv2.imwrite(notFilePath, imgNotRemoveSmall)
2048
            else:
2049
                message = 'can\'t found {}'.format(diffFilePath)
2050
                self.addMessage.emit(MessageType.Normal, message)
2051

    
2052
            SaveWorkCommand.save_to_xml()
2053
        except Exception as ex:
2054
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2055
            self.addMessage.emit(MessageType.Error, message)
2056

    
2057
    def determineRemainObject(self, idx, contours, imgNot):
2058
        '''
2059
            @brief      determine remain objects -> line no indicator or unknown
2060
            @author     euisung
2061
            @date       2018.12.26
2062
            @history    2019.03.25  euisung    Change name isLineNoIndicator -> determineRemainObject
2063
        '''
2064
        import math
2065
        [x, y, w, h] = cv2.boundingRect(contours[idx])
2066
        
2067
        if (w < 250 and h < 250):
2068
            return ('Unknown', [])
2069
        
2070
        fLines = []
2071
        maxDifAngle = 3
2072
        mask = np.zeros_like(imgNot)
2073
        cv2.drawContours(mask, contours, idx, 123, -1) # Draw filled contour in mask
2074
        out = np.zeros_like(imgNot) # Extract out the object and place into output image
2075
        out[mask == 123] = imgNot[mask == 123]
2076

    
2077
        # Now crop
2078
        ##print(out)
2079
        (x, y) = np.where(mask == 123)
2080
        (topx, topy) = (np.min(x), np.min(y))
2081
        (bottomx, bottomy) = (np.max(x), np.max(y))
2082
        out = out[topx:bottomx+1, topy:bottomy+1]
2083
        h, w = out.shape[0], out.shape[1]
2084
        maxDifH, maxDifW = math.ceil(math.tan(4 * math.pi / 180) / 2 * w), math.ceil(math.tan(4 * math.pi / 180) / 2 * h)
2085

    
2086
        # detection lines
2087
        edged2 = cv2.Canny(out, 100, 200)
2088
        lines = cv2.HoughLinesP(image=edged2, rho=1, theta=np.pi/180, threshold=25, minLineLength=30, maxLineGap=25)
2089
        #lines = cv2.HoughLines(edged2, 1, np.pi/180, 60)
2090
        if lines is None:
2091
            return ('Unknown', [])
2092
        for line in lines:
2093
            #r, theta = line[0]
2094
            #a, b = np.cos(theta), np.sin(theta)
2095
            #x0, y0 = a * r, b * r
2096
            #x1, y1 = int(x0 + 1000 * (-b)), int(y0 + 1000 * a)
2097
            #x2, y2 = int(x0 - 1000 * (-b)), int(y0 - 1000 * a)
2098
            #cv2.line(out, (x1, y1), (x2, y2), (0, 255, 0), 3)
2099
            x1, y1, x2, y2 = line[0]
2100
            degree = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi
2101
            fLine = [x1, y1, x2, y2, degree]
2102
            #print(fLine)
2103
            fLines.append(fLine)
2104
        
2105
        horLines = []
2106
        verLines = []
2107
        otherLines = []
2108
        isVH = None
2109
        for fLine in fLines:
2110
            degree = math.fabs(fLine[4])
2111
            if degree >= 90 - maxDifAngle:
2112
                verLines.append(fLine)
2113
            elif degree <= maxDifAngle:
2114
                horLines.append(fLine)
2115
            else:
2116
                otherLines.append(fLine)
2117

    
2118
        baseLines = []
2119
        baseDifV = 0
2120
        if len(horLines):
2121
            x, y = w / 2, 0
2122
            baseDifV = maxDifH
2123
            for horLine in horLines:
2124
                x1, y1, x2, y2 = horLine[0], horLine[1], horLine[2], horLine[3]
2125
                y = ((y2-y1)/(x2-x1))*x + y1 - ((y2-y1)/(x2-x1))*x1
2126
                horLine.append(y)
2127
            baseLines = horLines
2128
            isVH = 'H'
2129
        if len(verLines):
2130
            x, y = 0, h / 2
2131
            baseDifV = maxDifW
2132
            for verLine in verLines:
2133
                x1, y1, x2, y2 = verLine[0], verLine[1], verLine[2], verLine[3]
2134
                x = ((x2-x1)/(y2-y1))*y + x1 - ((x2-x1)/(y2-y1))*y1
2135
                verLine.append(x)
2136
            baseLines = verLines
2137
            isVH = 'V'
2138

    
2139
        for otherLine in otherLines:
2140
            x, y = w / 2, 0
2141
            x1, y1, x2, y2 = otherLine[0], otherLine[1], otherLine[2], otherLine[3]
2142
            y = ((y2-y1)/(x2-x1))*x + y1 - ((y2-y1)/(x2-x1))*x1
2143
            otherLine.append(y)
2144

    
2145
        # determine line no indicator 
2146
        if not ((len(horLines) > 0 and len(verLines) > 0) or len(otherLines) is 0 or (len(horLines) == 0 and len(verLines) == 0)):    
2147
            result, mergedOtherLine = self.isLineNoIndicator(w, h, maxDifAngle, baseDifV, baseLines, otherLines)
2148
            if result:
2149
                #print(fLines)
2150
                return ('LineIndicator', [isVH, mergedOtherLine])
2151

    
2152
        return ('Unknown', [])
2153

    
2154
    def isLineNoIndicator(self, w, h, maxDifAngle, baseDifV, baseLines, otherLines):
2155
        '''
2156
            @brief      determine line no indicator
2157
            @author     euisung
2158
            @date       2019.03.25
2159
        '''
2160
        import math
2161

    
2162
        if (w < 250 and h < 250):
2163
            return (False, None)
2164

    
2165
        isSameLine = True
2166
        i = 0
2167
        for baseLine in baseLines:
2168
            if not isSameLine: break
2169
            j = 0
2170
            for baseLinee in baseLines:
2171
                if i == j:
2172
                    j += 1
2173
                    continue
2174
                difV = math.fabs(baseLine[5] - baseLinee[5])
2175
                if difV > baseDifV:
2176
                   isSameLine = False
2177
                   break
2178
                j += 1
2179
            i += 1
2180
        if not isSameLine:
2181
            return (False, None)
2182

    
2183
        isSameLine = True
2184
        i = 0
2185
        maxY = 0
2186
        for otherLine in otherLines:
2187
            y = otherLine[5]
2188
            if math.fabs(y) > maxY:
2189
                maxY = math.fabs(y)
2190
            if not isSameLine: break
2191
            j = 0
2192
            for otherLinee in otherLines:
2193
                if i == j:
2194
                    j += 1
2195
                    continue
2196
                difV = math.fabs(otherLine[4] - otherLinee[4])
2197
                if difV > maxDifAngle:
2198
                   isSameLine = False
2199
                   break
2200
                j += 1
2201
            i += 1
2202
        if not isSameLine:
2203
            return (False, None)
2204
                
2205
        isSameLine = True
2206
        mergedOtherLine = [0, 0, 0, 0]
2207
        i = 0
2208
        maxDif = math.ceil(math.tan(4 * math.pi / 180) * maxY)
2209
        for otherLine in otherLines:
2210
            if not isSameLine: break
2211
            j = 0
2212
            for otherLinee in otherLines:
2213
                if i == j:
2214
                    j += 1
2215
                    continue
2216
                angle = math.fabs(otherLine[4] + otherLinee[4]) / 2
2217
                difV = math.fabs(otherLine[5] - otherLinee[5])
2218
                dist = math.sin((90 - angle) * math.pi / 180) * difV 
2219
                if dist > maxDif:
2220
                   isSameLine = False
2221
                   break
2222
                j += 1
2223
            i += 1
2224
            mergedOtherLine[0] += otherLine[0]
2225
            mergedOtherLine[1] += otherLine[1]
2226
            mergedOtherLine[2] += otherLine[2]
2227
            mergedOtherLine[3] += otherLine[3]
2228
        if not isSameLine:
2229
            (False, None)
2230
                        
2231
        # Show the output image
2232
        #print('line no indicator')
2233
        mergedOtherLine[0] = round(mergedOtherLine[0] / len(otherLines))
2234
        mergedOtherLine[1] = round(mergedOtherLine[1] / len(otherLines))
2235
        mergedOtherLine[2] = round(mergedOtherLine[2] / len(otherLines))
2236
        mergedOtherLine[3] = round(mergedOtherLine[3] / len(otherLines))
2237
        #cv2.line(out, (mergedOtherLine[0], mergedOtherLine[1]), (mergedOtherLine[2], mergedOtherLine[3]), (255, 255, 255), 3)
2238
        #cv2.imshow('Output', out)
2239
        #cv2.waitKey(0)
2240
        #cv2.destroyAllWindows()
2241
        return (True, mergedOtherLine)
2242

    
2243
    '''
2244
        @brief      load recognition result
2245
        @author     humkyung
2246
        @date       2018.04.??
2247
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
2248
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
2249
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
2250
                    humkyung 2018.04.23 connect item remove slot to result tree
2251
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
2252
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
2253
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2254
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
2255
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
2256
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
2257
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
2258
                    Jeongwoo 2018.06.18 Update Scene after all item added
2259
                                        Add connect on unknown item
2260
                                        Add [transfer] for using pyqtSignal
2261
                    kyouho  2018.07.12  Add line property logic
2262
                    humkyung 2018.08.22 show progress while loading xml file
2263
                    2018.11.22      euisung     fix note road
2264
    '''
2265
    def loadRecognitionResultFromXml(self, xmlPath):
2266
        docData = AppDocData.instance()
2267
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2268
        from EngineeringRunItem import QEngineeringRunItem
2269
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2270

    
2271
        try:
2272
            #self.graphicsView.scene.blockSignals(True)
2273

    
2274
            symbols = []
2275

    
2276
            xml = parse(xmlPath)
2277
            root = xml.getroot()
2278
            
2279
            maxValue = 0
2280
            maxValue = maxValue + len(list(root.iter('SYMBOL')))
2281
            maxValue = maxValue + len(list(root.iter('ATTRIBUTE')))
2282
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
2283
            maxValue = maxValue + len(list(root.iter('LINE')))
2284
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
2285
            maxValue = maxValue + len(list(root.iter('SIZETEXT')))
2286
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
2287
            self.progress.setMaximum(maxValue)
2288

    
2289
            """ parsing all symbols """
2290
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
2291
                item = SymbolSvgItem.fromXml(symbol)
2292
                if item is not None:
2293
                    item.transfer.onRemoved.connect(self.itemRemoved)
2294
                    symbols.append(item)
2295
                    docData.symbols.append(item)
2296
                    self.addSvgItemToScene(item)
2297
                else:
2298
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2299
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2300
                    angle = float(symbol.find('ANGLE').text)
2301
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2302
                    item.isSymbol = True
2303
                    item.angle = angle
2304
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2305
                    self.graphicsView.scene.addItem(item)
2306

    
2307
                self.progress.setValue(self.progress.value() + 1)
2308
                
2309
            QApplication.processEvents()
2310

    
2311
            # parse texts
2312
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
2313
                item = QEngineeringTextItem.fromXml(text)
2314
                if item is not None:
2315
                    uid = text.find('UID')
2316
                    attributeValue = text.find('ATTRIBUTEVALUE')
2317
                    name = text.find('NAME').text
2318
                    item.transfer.onRemoved.connect(self.itemRemoved)
2319
                    self.addTextItemToScene(item)
2320
                    docData.texts.append(item)
2321

    
2322
                    if name == 'TEXT':
2323
                        if uid is not None and attributeValue is not None:
2324
                            item.uid = uid.text
2325
                            item.attribute = attributeValue.text
2326

    
2327
                self.progress.setValue(self.progress.value() + 1)
2328
                
2329
            QApplication.processEvents()
2330

    
2331
            # note
2332
            for text in root.find('NOTES').iter('ATTRIBUTE'):
2333
                item = QEngineeringTextItem.fromXml(text)
2334
                if item is not None:
2335
                    uid = text.find('UID')
2336
                    attributeValue = text.find('ATTRIBUTEVALUE')
2337
                    name = text.find('NAME').text
2338
                    item.transfer.onRemoved.connect(self.itemRemoved)
2339
                    self.addTextItemToScene(item)
2340

    
2341
                    if name == 'NOTE':
2342
                        if uid is not None:
2343
                            item.uid = uid.text
2344

    
2345
                self.progress.setValue(self.progress.value() + 1)
2346
                
2347
            QApplication.processEvents()
2348

    
2349
            for line in root.find('LINEINFOS').iter('LINE'):
2350
                item = QEngineeringLineItem.fromXml(line)
2351
                item.transfer.onRemoved.connect(self.itemRemoved)
2352
                if item:
2353
                    self.graphicsView.scene.addItem(item)
2354

    
2355
                self.progress.setValue(self.progress.value() + 1)
2356
                
2357
            QApplication.processEvents()
2358

    
2359
            for unknown in root.iter('UNKNOWN'):
2360
                item = QEngineeringUnknownItem.fromXml(unknown)
2361
                item.transfer.onRemoved.connect(self.itemRemoved)
2362
                if item is not None:
2363
                    item.transfer.onRemoved.connect(self.itemRemoved)
2364
                    self.graphicsView.scene.addItem(item)
2365

    
2366
                self.progress.setValue(self.progress.value() + 1)
2367
                
2368
            QApplication.processEvents()
2369

    
2370
            #""" add tree widget """
2371
            #for item in symbols:
2372
            #    docData.symbols.append(item)
2373
            #    self.addSvgItemToScene(item)
2374
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
2375

    
2376
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
2377
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
2378
                if line_no is None: continue
2379

    
2380
                line_no.transfer.onRemoved.connect(self.itemRemoved)
2381
                self.addTextItemToScene(line_no)
2382
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2383

    
2384
                runs_node = line_no_node.findall('RUN')
2385
                if runs_node is None: continue
2386

    
2387
                for run_node in runs_node:
2388
                    line_run = QEngineeringRunItem()
2389
                    for child_node in run_node:
2390
                        uidElement = child_node.find('UID')
2391
                        if uidElement is not None:
2392
                            uid = uidElement.text
2393
                            run_item = self.graphicsView.findItemByUid(uid)
2394
                            if run_item is not None:
2395
                                run_item._owner = line_no
2396
                                line_run.items.append(run_item)
2397
                    line_run.owner = line_no
2398
                    line_no.runs.append(line_run)
2399

    
2400
                    for run_item in line_run.items:
2401
                        if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2402

    
2403
                docData.tracerLineNos.append(line_no)
2404

    
2405
                self.progress.setValue(self.progress.value() + 1)
2406
            QApplication.processEvents()
2407

    
2408
            for trimLineNo in root.iter('TRIM_LINE_NO'):
2409
                line_no = QEngineeringTrimLineNoTextItem()
2410
                line_no.uid = trimLineNo.find('UID')
2411

    
2412
                run = trimLineNo.find('RUN')
2413
                if run is not None:
2414
                    line_run = QEngineeringRunItem()
2415
                    for child in run:
2416
                        uidElement = child.find('UID')
2417
                        if uidElement is not None:
2418
                            uid = uidElement.text
2419
                            run_item = self.graphicsView.findItemByUid(uid)
2420
                            if run_item is not None:
2421
                                #runItem.owner = item
2422
                                line_run.items.append(run_item)
2423

    
2424
                    line_no.runs.append(line_run)
2425
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2426
                    for run_item in line_run.items:
2427
                        if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2428
                    docData.tracerLineNos.append(line_no)
2429

    
2430
                self.progress.setValue(self.progress.value() + 1)
2431

    
2432
            if root.find('VENDORS') is not None:
2433
                for vendor in root.find('VENDORS').iter('VENDOR'):
2434
                    item = QEngineeringVendorItem.fromXml(vendor)
2435
                    item.transfer.onRemoved.connect(self.itemRemoved)
2436
                    self.graphicsView.scene.addItem(item)
2437
            # up to here
2438

    
2439
            """ update scene """
2440
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
2441
            for item in self.graphicsView.scene.items():
2442
                item.setVisible(True)
2443

    
2444
        except Exception as ex:
2445
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2446
            self.addMessage.emit(MessageType.Error, message)
2447
        finally:
2448
            pass
2449
            #self.graphicsView.scene.blockSignals(False)
2450

    
2451
    '''
2452
        @brief      Remove added item on same place and Add GraphicsItem
2453
        @author     Jeongwoo
2454
        @date       2018.05.25
2455
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
2456
                    2018.06.18  Jeongwoo    Set Z-index
2457
    '''
2458
    def addSvgItemToScene(self, svgItem):
2459
        svgItem.addSvgItemToScene(self.graphicsView.scene)
2460
        
2461
    '''
2462
        @brief      Remove added item on same place and Add GraphicsItem
2463
        @author     Jeongwoo
2464
        @date       2018.05.25
2465
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
2466
                    2018.06.05  Jeongwoo    Remove Size condition
2467
                    2018.06.18  Jeongwoo    Set Z-index
2468
    '''
2469
    def addTextItemToScene(self, textItem):
2470
        textItem.addTextItemToScene(self.graphicsView.scene)
2471
        
2472
    '''
2473
        @brief      Remove added item on same place and Add GraphicsItem
2474
        @author     Jeongwoo
2475
        @date       2018.05.29
2476
        @history    2018.06.18  Jeongwoo    Set Z-index
2477
    '''
2478
    def addLineItemToScene(self, lineItem):
2479
        self.graphicsView.scene.addItem(lineItem)
2480

    
2481
    '''
2482
        @brief      generate output xml file
2483
        @author     humkyung
2484
        @date       2018.04.23
2485
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
2486
    '''
2487
    def generateOutput(self):
2488
        import XmlGenerator as xg
2489

    
2490
        if not self.graphicsView.hasImage():
2491
            self.showImageSelectionMessageBox()
2492
            return
2493

    
2494
        try:
2495
            appDocData = AppDocData.instance()
2496

    
2497
            ## collect items
2498
            appDocData.lines.clear()
2499
            appDocData.lines = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem and item.owner is None]
2500

    
2501
            appDocData.symbols.clear()
2502
            appDocData.symbols = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) and item.owner is None]
2503

    
2504
            appDocData.equipments.clear()
2505
            for item in self.graphicsView.scene.items():
2506
                if type(item) is QEngineeringEquipmentItem:
2507
                    appDocData.equipments.append(item)
2508

    
2509
            appDocData.texts.clear()
2510
            appDocData.texts = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem) and type(item) is not QEngineeringLineNoTextItem]
2511
            ## up to here
2512

    
2513
            appDocData.imgOutput = np.ones((appDocData.imgHeight, appDocData.imgWidth), np.uint8)*255
2514
            xg.writeOutputXml(appDocData.imgName, appDocData.imgWidth, appDocData.imgHeight) # TODO: check
2515
            project = appDocData.getCurrentProject()
2516
            cv2.imwrite(os.path.join(project.getTempPath() , 'OUTPUT.png') , appDocData.imgOutput)
2517
        except Exception as ex:
2518
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2519
            self.addMessage.emit(MessageType.Error, message)
2520

    
2521
    '''
2522
        @brief      resetting attribute at secne
2523
        @author     kyoyho
2524
        @date       2018.08.21
2525
    '''
2526
    """
2527
    def checkAttribute(self):
2528
        try:
2529

2530
            docData = AppDocData.instance()
2531
            if not self.graphicsView.hasImage():
2532
                return
2533

2534
            # symbol 경우
2535
            items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringSpecBreakItem and type(item) is not QEngineeringEndBreakItem]
2536
            for item in items:
2537
                attrs = item.attrs
2538
                
2539
                removeAttrList = []
2540
                for attr in attrs:
2541
                    if type(attr) is tuple:
2542
                        continue
2543

2544
                    if attr is None:
2545
                        removeAttrList.append(attr)
2546
                        continue
2547

2548
                    attrInfo = docData.getSymbolAttributeByUID(attr.UID)
2549
                    if attrInfo is None:
2550
                        removeAttrList.append(attr)
2551
                    # 해당 attribute가 맞는지 확인
2552
                    else:
2553
                        attrType = attrInfo.AttributeType
2554
                        _type = type(attr)
2555
                        if attrType == 'Symbol Item':
2556
                            if not issubclass(_type, SymbolSvgItem):
2557
                                removeAttrList.append(attr)
2558
                        elif attrType == 'Text Item':
2559
                            if _type is not QEngineeringTextItem:
2560
                                removeAttrList.append(attr)
2561
                        elif attrType == 'Int':
2562
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
2563
                                removeAttrList.append(attr)
2564
                        elif attrType == 'String':
2565
                            if _type is not UserInputAttribute:
2566
                                removeAttrList.append(attr)
2567

2568
                for attr in removeAttrList:
2569
                    del attrs[attr]
2570

2571
            # Line No Text Item의 경우
2572
            items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringLineNoTextItem)]
2573
            for item in items:
2574
                attrs = item.attrs
2575
                
2576
                removeAttrList = []
2577
                for attr in attrs:
2578
                    if type(attr) is UserInputAttribute:
2579
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
2580
                        if attrInfo is None:
2581
                            removeAttrList.append(attr)
2582

2583
                for attr in removeAttrList:
2584
                    del attrs[attr]
2585

2586
        except Exception as ex:
2587
                message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2588
                self.addMessage.emit(MessageType.Error, message)
2589
    """
2590
    '''
2591
        @brief      Check Number
2592
        @author     kyouho
2593
        @date       2018.08.20
2594
    '''
2595
    def isNumber(self, num):
2596
        p = re.compile('(^[0-9]+$)')
2597
        result = p.match(num)
2598

    
2599
        if result:
2600
            return True
2601
        else:
2602
            return False
2603

    
2604
    '''
2605
        @brief      find overlap Connector
2606
        @author     kyouho
2607
        @date       2018.08.28
2608
    '''
2609
    def findOverlapConnector(self, connectorItem):
2610
        from shapely.geometry import Point
2611
        from EngineeringConnectorItem import QEngineeringConnectorItem
2612
        itemList = []
2613
        
2614
        x = connectorItem.center()[0]
2615
        y = connectorItem.center()[1]
2616

    
2617
        connectors = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringConnectorItem and item != connectorItem]
2618
        for connector in connectors:
2619
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
2620
                itemList.append(connector.parent)
2621

    
2622
        return itemList
2623

    
2624
if __name__ == '__main__':
2625
    import locale
2626
    from PyQt5.QtCore import QTranslator
2627
    from License import QLicenseDialog
2628
    from ProjectDialog import Ui_Dialog
2629
    from App import App 
2630

    
2631
    app = App(sys.argv)
2632
    try:
2633
        if True == QLicenseDialog.check_license_key():
2634
            dlg = Ui_Dialog()
2635
            selectedProject = dlg.showDialog()
2636
            if selectedProject is not None:
2637
                AppDocData.instance().setCurrentProject(selectedProject)
2638
                app._mainWnd = MainWindow.instance()
2639
                app._mainWnd.show()
2640
                sys.exit(app.exec_())
2641
    except Exception as ex:
2642
        print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
2643
    finally:
2644
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)