프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / LineNoTracer.py @ 8a48a60b

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

1
# coding: utf-8
2
"""
3
    This is line no tracer module
4
"""
5

    
6
import sys
7
import math
8
import shapely
9
from AppDocData import AppDocData, MessageType
10
from EngineeringLineItem import QEngineeringLineItem
11
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
12
from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem
13
from SymbolSvgItem import SymbolSvgItem
14
from EngineeringTextItem import QEngineeringTextItem
15
from EngineeringUnknownItem import QEngineeringUnknownItem
16
try:
17
    from PyQt5.QtCore import *
18
    from PyQt5.QtGui import *
19
    from PyQt5.QtWidgets import *
20
except ImportError:
21
    try:
22
        from PyQt4.QtCore import *
23
        from PyQt4.QtGui import *
24
    except ImportError:
25
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
26

    
27
class LineNoTracer:
28
    '''
29
        @history    2018.04.26 Jeongwoo Variable name changed (texts → lineNos)
30
    '''
31
    def __init__(self, symbols, lines, lineNos, specBreak, lineIndicator):
32
        try:
33
            self._symbols = symbols
34
            #for symbol in self._symbols: symbol.owner = None
35
            self._lines = lines
36
            #for line in self._lines: line.owner = None
37
            self._lineNos = lineNos
38
            self._specBreak = specBreak
39
            self._specBreakUID = []
40
            self._lineIndicator = lineIndicator
41
            
42
            for spec in self._specBreak:
43
                for attr in spec.attrs:
44
                    if type(attr) is tuple and attr[1] != '':
45
                        self._specBreakUID.append(attr[1])
46

    
47
        except Exception as ex:
48
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
49

    
50
    '''
51
        @brief  find primary lines connected to given line no
52
        @author humkyung
53
    '''
54
    def findPrimaryLines(self, lineno):
55
        from EngineeringLineItem import QEngineeringLineItem
56
        from EngineeringRunItem import QEngineeringRunItem
57

    
58
        connectedItems = []
59
        if 1 == len(lineno.conns):
60
            connectedItems = self.findConnectedObjects(lineno.conns[0], toler=10)
61
            for item in connectedItems: 
62
                item.owner = lineno # set item's owner
63
                item.linkedItem = lineno
64
            
65
            pipeRun = QEngineeringRunItem()
66
            pipeRun.items = connectedItems
67
            lineno.runs.append(pipeRun)
68

    
69
        return connectedItems
70

    
71
    '''
72
        @brief  find secondary lines
73
        @author humkyung
74
    '''
75
    def findSecondaryLines(self, lines):
76
        from EngineeringLineItem import QEngineeringLineItem
77
        from EngineeringRunItem import QEngineeringRunItem
78

    
79
        try:
80
            foundCount = 1
81
            while foundCount:
82
                foundCount = 0
83
                notMatches = []
84
                for line in lines:
85
                    if line.linkedItem is not None: continue
86

    
87
                    matches = [x for x in self._lines if x.linkedItem is not None and x.isConnectable(line)]
88
                    if matches:
89
                        foundCount += 1
90
                        connectedItems = self.findConnectedObjects(line, toler=10)
91
                        # set connection object
92
                        for idx in range(len(line.connectors)):
93
                            if line.connectors[idx].connectedItem is None: line.connectors[idx].connectedItem = matches[0]
94
                        # up to here
95
                        for item in connectedItems:
96
                            item.owner = matches[0].owner   # set item's owner
97
                            item.linkedItem = matches[0].owner
98

    
99
                        pipeRun = QEngineeringRunItem()
100
                        pipeRun.items = connectedItems
101
                        if pipeRun.items is not None and len(pipeRun.items) > 0:
102
                            matches[0].owner.runs.append(pipeRun)
103
                    else:
104
                        notMatches.append(line)
105
                lines = notMatches
106
        except Exception as ex:
107
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
108

    
109
            
110

    
111
    '''
112
        @brief      trace line no
113
        @author     humkyung
114
        @date       2018.04.16
115
        @history    2018.04.26 Jeongwoo docDatalineNos = self.lineNos, Not For loop
116
                    humkyung 2018.05.08 add flow arrow
117
                    Jeongwoo 2018.05.14 Add [runs] on Primary/Secondary Line - Need to modify Secondary Line
118
                    Jeongwoo 2018.05.15 Make Comments [lineno.conns[0].owner = lineno]
119
                    Jeongwoo 2018.05.17 Modify find secondary lines with 'while'
120
                                        Modify find secondary lines with 'while' used sublist for unconnected line
121
                    humkyung 2018.05.18 set start line's owner before tracing
122
    '''
123
    def execute(self, displayMessage, updateProgress, toler=50):
124
        from EngineeringLineItem import QEngineeringLineItem
125
        from SymbolSvgItem import SymbolSvgItem
126
        from EngineeringRunItem import QEngineeringRunItem
127
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
128

    
129
        try:
130
            docData = AppDocData.instance()
131

    
132
            configs = docData.getConfigs('Line No', 'Delimiter')
133
            if 1 == len(configs):
134
                delimiter = configs[0].value
135
                configs = docData.getConfigs('Line No', 'Configuration')
136

    
137
                docData.tracerLineNos.clear()
138
                
139
                ## 기존에 찾은 것 유지
140
                #for lineNo in self._lineNos:
141
                #    lineNo.conns.clear()
142

    
143
                docData.tracerLineNos = self._lineNos
144
                remainLineNos = []
145
                remainLines = []
146
                for lineno in docData.tracerLineNos:
147
                    ## CONN은 유지
148
                    if lineno.conns:
149
                        continue
150

    
151
                    minDist = None
152
                    startLine = None
153
                    for line in self._lines:
154
                        dist = line.distanceTo((lineno.center().x(), lineno.center().y()))
155
                        if (minDist is None) or (dist < minDist):
156
                            minDist = dist
157
                            startLine = line
158
                    if (startLine is not None) and (minDist < toler):
159
                        lineno.conns.append(startLine)
160
                    else:
161
                        remainLineNos.append(lineno)
162
                
163
                ## lineIndicator
164
                extendPixel = 10
165
                for lineIndicator in self._lineIndicator:
166
                    maxOverLap = 0
167
                    matchLineNo = None
168
                    liInRect = [round(lineIndicator.boundingRect().x()), round(lineIndicator.boundingRect().y()), round(lineIndicator.boundingRect().x() + lineIndicator.boundingRect().width()), round(lineIndicator.boundingRect().y() + lineIndicator.boundingRect().height())]
169
                    for remainLineNo in remainLineNos:
170
                        xOverlap = False
171
                        yOverlap = False
172
                        extendDx = remainLineNo.size[0] if lineIndicator.isVH == 'V' else remainLineNo.size[1]
173
                        reNoRect = [round(remainLineNo.loc[0] - extendDx), round(remainLineNo.loc[1] - extendDx), round(remainLineNo.loc[0] + remainLineNo.size[0] + extendDx), round(remainLineNo.loc[1] + remainLineNo.size[1] + extendDx)]
174
                        w, h = 0, 0                        
175
                        for x1 in range(reNoRect[0], reNoRect[2] + 1):
176
                            for x2 in range(liInRect[0], liInRect[2] + 1):
177
                                if x1 - x2 is 0:
178
                                    xOverlap = True
179
                                    w += 1
180
                        if not xOverlap:
181
                            continue
182
                        for y1 in range(reNoRect[1], reNoRect[3] + 1):
183
                            for y2 in range(liInRect[1], liInRect[3] + 1):
184
                                if y1 - y2 is 0:
185
                                    yOverlap = True
186
                                    h += 1
187

    
188
                        if not xOverlap or not yOverlap:
189
                            continue
190
                        overLapRate = (w / lineIndicator.boundingRect().width() * 100) if lineIndicator.boundingRect().width() > lineIndicator.boundingRect().height() else (h / lineIndicator.boundingRect().height() * 100)
191
                        #print(overLapRate)
192
                        if maxOverLap < overLapRate:
193
                            maxOverLap = overLapRate
194
                            matchLineNo = remainLineNo
195
                            #lineIndicator.setBrush(QBrush(QColor(255, 0, 0, 127)))
196

    
197
                    if matchLineNo is not None:
198
                        #print(matchLineNo.text() + ' indicator : ' + str(lineIndicator.boundingRect().x()) + ', ' + str(lineIndicator.boundingRect().y()))
199
                        matchLine = None
200
                        x1, y1, x2, y2 = round(lineIndicator.boundingRect().x() + lineIndicator.otherLine[0]), round(lineIndicator.boundingRect().y() + lineIndicator.otherLine[1]), round(lineIndicator.boundingRect().x() + lineIndicator.otherLine[2]), round(lineIndicator.boundingRect().y() + lineIndicator.otherLine[3])
201
                        startXorY = (min(liInRect[0], liInRect[2]) - extendPixel) if lineIndicator.isVH == 'V' else (min(liInRect[1], liInRect[3]) - extendPixel)
202
                        endXorY = (max(liInRect[0], liInRect[2]) + extendPixel) if lineIndicator.isVH == 'V' else (max(liInRect[1], liInRect[3]) + extendPixel)
203
                        fXorY = []
204
                        for dXOrdY in range(startXorY, endXorY + 1): # if horizontal -> Y, if vertical -> X
205
                            if lineIndicator.isVH == 'V':
206
                                fXorY.append(round(((y2-y1)/(x2-x1))*dXOrdY + y1 - ((y2-y1)/(x2-x1))*x1)) # f(x)
207
                            else:
208
                                fXorY.append(round(((x2-x1)/(y2-y1))*dXOrdY + x1 - ((x2-x1)/(y2-y1))*y1)) # f(y)
209

    
210
                        for line in self._lines:
211
                            axis1Overlap = False
212
                            axis2Overlap = False
213
                            lX1, lY1, lX2, lY2 = int(line.startPoint()[0]), int(line.startPoint()[1]), int(line.endPoint()[0]), int(line.endPoint()[1])
214

    
215
                            if lineIndicator.isVH == 'V':
216
                                range11 = range(startXorY, endXorY + 1)
217
                                range12 = range(min(lX1, lX2), max(lX1, lX2)+ 1)
218
                                range21 = fXorY
219
                                range22 = range(min(lY1, lY2), max(lY1, lY2) + 1)
220
                            else:
221
                                range11 = range(startXorY, endXorY + 1)
222
                                range12 = range(min(lY1, lY2), max(lY1, lY2) + 1)
223
                                range21 = fXorY
224
                                range22 = range(min(lX1, lX2), max(lX1, lX2) + 1)
225

    
226
                            for axis11 in range11:
227
                                for axis12 in range12:
228
                                    if axis11 - axis12 is 0:
229
                                        axis1Overlap = True
230
                                        break
231
                                if axis1Overlap: break
232
                            if not axis1Overlap:
233
                                continue
234
                            for axis21 in range21:
235
                                for axis22 in range22:
236
                                    if axis21 - axis22 is 0:
237
                                        axis2Overlap = True
238
                                        break
239
                                if axis2Overlap: break
240
                            
241
                            if axis1Overlap and axis2Overlap:
242
                                matchLine = line
243
                                break
244
                        if matchLine is not None:
245
                            matchLineNo.conns.append(matchLine)
246
                            lineIndicator.lineIndicator = 'Match'
247
                            lineIndicator.setBrush(QBrush(QColor(0, 0, 255, 127)))
248
                            #print('connected ' + matchLineNo.text() + ' and ' + matchLine.uid)                     
249
                ## up to here
250
                            
251
                # set start line's owner
252
                for lineno in docData.tracerLineNos:
253
                    if lineno.conns: 
254
                        lineno.conns[0].owner = lineno
255
                        lineno.conns[0].linkedItem = lineno
256
                
257
                maxValue = len(self._lineNos) + 1   ## line no's count + secondary line
258

    
259
                # find primary lines
260
                for lineno in docData.tracerLineNos:
261
                    displayMessage.emit('{} {}'.format(lineno.text(), 'Topology Construction'))
262
                    self.findPrimaryLines(lineno)
263
                    updateProgress.emit(maxValue)
264

    
265
                # find secondary lines
266
                lines = self._lines
267
                self.findSecondaryLines(lines)
268
                updateProgress.emit(maxValue)
269

    
270
            ### make trim lines
271
            updateProgress.emit(-1) # reset progressbar
272
            displayMessage.emit('TrimLine Topology Construction')
273
            orphanLines = [line for line in self._lines if line.linkedItem is None] 
274
            if orphanLines:
275
                maxValue = len(orphanLines)
276
                orphanLines = sorted(orphanLines, key=lambda param:param.length(), reverse=True)
277
                while len(orphanLines) > 0:
278
                    trimLineNo = QEngineeringTrimLineNoTextItem()
279
                    trimLineNo.conns.append(orphanLines[0])
280
                    orphanLines[0].owner = trimLineNo
281
                    orphanLines[0].linkedItem = trimLineNo
282

    
283
                    connectedItems = self.findPrimaryLines(trimLineNo)
284
                    for item in connectedItems:
285
                        if item in orphanLines:
286
                            orphanLines.remove(item)
287
                            updateProgress.emit(maxValue)
288

    
289
                    self.findSecondaryLines(orphanLines)
290
                    for item in orphanLines[:]:
291
                        if item.linkedItem is not None:
292
                            orphanLines.remove(item)
293
                            updateProgress.emit(maxValue)
294

    
295
                    docData.tracerLineNos.append(trimLineNo)
296
            
297
            updateProgress.emit(maxValue)
298
        except Exception as ex:
299
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
300

    
301
    '''
302
        @brief      find objects connected to given line while loop
303
        @author     humkyung
304
        @date       2018.04.16
305
        @history    humkyung 2018.05.08 find symbol or line connected to given object
306
                    humkyung 2018.05.10 set found object's owner
307
                    humkyung 2018.05.17 try to connect both symbol and line
308
                    humkyung 2018.06.22 order connected objects
309
    '''
310
    def findConnectedObjects(self, startLine, toler):
311
        from EngineeringLineItem import QEngineeringLineItem
312
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
313
        from SymbolSvgItem import SymbolSvgItem
314

    
315
        visited = [startLine]
316

    
317
        try:
318
            pool = []
319
            pool.append((0, startLine))
320
            
321
            while len(pool) > 0:
322
                sign, obj = pool.pop()
323
                if type(obj) is QEngineeringLineItem:
324
                    symbolMatches = [x for x in self._symbols if (x.linkedItem is None) and (x not in visited) and len(obj.connectIfPossible(x, toler)) > 0]
325
                    lineMatches = [x for x in self._lines if (x.linkedItem is None) and (x is not obj) and (x not in visited) and (len(obj.connectIfPossible(x, toler)) > 0)]
326

    
327
                elif issubclass(type(obj), SymbolSvgItem):
328
                    lineMatches = [x for x in self._lines if (x.linkedItem is None) and (x not in visited) and len(obj.connectIfPossible(x, toler)) > 0]
329
                    symbolMatches = [x for x in self._symbols if (x.linkedItem is None) and (x is not obj) and (x not in visited) and (len(obj.connectIfPossible(x, toler)) > 0)]
330

    
331
                # order connected objects
332
                matches = []
333
                matches.extend([x for x in symbolMatches if not issubclass(type(x), QEngineeringEquipmentItem)])    # except equipment
334
                matches.extend(lineMatches)
335

    
336
                # specBreak 확인
337
                isContainSpecBreak = False
338
                for uid in self._specBreakUID:
339
                    if obj.uid == uid:
340
                        isContainSpecBreak = True
341
                    for item in matches:
342
                        if item.uid == uid:
343
                            isContainSpecBreak = True
344
                            
345
                    if isContainSpecBreak:
346
                        break
347

    
348
                # specBreak 포함시
349
                if isContainSpecBreak:
350
                    isConnSpecBreak = obj.isConnectSpecBreak(self._specBreak)
351
                    if isConnSpecBreak[0]:
352
                        connector = isConnSpecBreak[1]
353
                        removeList = []
354
                        if connector.connectedItem is not None:
355
                            for item in matches:
356
                                if item == connector.connectedItem:
357
                                    removeList.append(connector.connectedItem)
358
                    
359
                        # connectedItem 제거
360
                        if connector.connectedItem is not None:
361
                            connector.connectedItem.disconnectedItemAtConnector(connector)
362
                        obj.disconnectedItemAtConnector(connector)
363
                    
364
                        for item in removeList:
365
                            matches.remove(item)
366
                
367
            
368
                if sign == 0 and len(matches) > 1:
369
                    mid = int(len(matches)*0.5)
370
                    lhs = matches[0:mid]
371
                    rhs = matches[mid:]
372
                elif sign == -1:
373
                    lhs = matches
374
                    rhs = []
375
                else:
376
                    lhs = []
377
                    rhs = matches
378

    
379
                for match in lhs:
380
                    pool.append((-1, match))
381
                    visited.insert(0, match)
382

    
383
                for match in rhs:
384
                    pool.append((1, match))
385
                    visited.append(match)
386
                # up to here
387

    
388
        except Exception as ex:
389
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
390

    
391
        return visited
392

    
393
'''
394
    @brief      connect attributes
395
    @author     humkyung
396
    @date       2018.06.17
397
    @history    humkyung 2018.06.21 paste connect attributes codes from recognizeLine function
398
                kyouho  2018.09.14  clear Item's owner 
399
'''
400
def connectAttrImpl(worker):
401
    from LineNoTracer import LineNoTracer
402
    from AppDocData import AppDocData
403
    from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
404

    
405
    try:
406
        symbols = []
407
        lines = []
408
        lineNos = []
409
        specBreak = []
410
        lineIndicator = []
411
        for item in worker.graphicsView.scene.items():
412
            if type(item) is QEngineeringSpecBreakItem:
413
                specBreak.append(item)
414
            elif issubclass(type(item), SymbolSvgItem):
415
                #item.owner = None
416
                item.linkedItem = None
417
                symbols.append(item)
418
            elif type(item) is QEngineeringLineNoTextItem:
419
                #item.owner = None
420
                item.linkedItem = None
421
                item.runs.clear()
422
                lineNos.append(item)
423
            elif type(item) is QEngineeringLineItem:
424
                #item.owner = None
425
                item.linkedItem = None
426
                lines.append(item)
427
            elif type(item) is QEngineeringUnknownItem and item.lineIndicator != 'False':
428
                lineIndicator.append(item)
429

    
430
        # trace line no
431
        tracer = LineNoTracer(symbols, lines, lineNos, specBreak, lineIndicator)
432
        tracer.execute(worker.displayMessage, worker.updateProgress)
433
        # up to here
434

    
435
        # connect attribut
436
        texts = [item for item in worker.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
437
        for symbol in symbols:
438
            try:
439
                symbol.connectAttribute(texts)
440
            except Exception as ex:
441
                from App import App 
442
                message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
443
                App.mainWnd().addMessage.emit(MessageType.Error, message)
444

    
445
        # up to here
446
    except Exception as ex:
447
        print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
448
    finally:
449
        worker.finished.emit()