프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / Shapes / EngineeringLineItem.py @ d7080855

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

1
# coding: utf-8
2
import sys
3
import os.path
4
import copy
5
import cv2
6

    
7
try:
8
    from PyQt5.QtCore import Qt, QPointF, QRectF, pyqtSignal, QT_VERSION_STR, QRect
9
    from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QColor, QBrush, QPen, QTransform
10
    from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QGraphicsItem, QAbstractGraphicsShapeItem, QGraphicsPathItem
11
except ImportError:
12
    try:
13
        from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR, QRect
14
        from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog
15
    except ImportError:
16
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
17

    
18
from GraphicsPolylineItem import QGraphicsPolylineItem
19
from QGraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
20
import shapely
21

    
22
class QEngineeringLineItem(QGraphicsPolylineItem):
23
    '''
24
        @history    2018.05.11  Jeongwoo    Make Comments self.setPen()
25
                    2018.05.15  Jeongwoo    Change method to call parent's __init__
26
                    humkyung 2018.06.21 add vertices to parameter
27
    '''
28
    def __init__(self, vertices=[], parent=None):
29
        QGraphicsPolylineItem.__init__(self, parent)
30
        self.isCreated = True 
31

    
32
        self.conns = [None, None]
33
        self._owner = None
34
        self._flowMark = None
35
        self._lineType = 'Primary'
36

    
37
        # add vertex
38
        for vertex in vertices:
39
            self._pol.append(QPointF(vertex[0], vertex[1]))
40
        # up to here
41

    
42
        self.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable)
43

    
44
        self.setAcceptHoverEvents(True)
45
        self.setAcceptTouchEvents(True)
46

    
47
        ptStart = self.startPoint()
48
        ptEnd = self.endPoint()
49
        self.setToolTip('({},{})-({},{})'.format(ptStart[0], ptStart[1], ptEnd[0], ptEnd[1]))
50

    
51
    '''
52
        @breif  getter owner
53
        @author humkyung
54
        @date   2018.05.10
55
    '''
56
    @property
57
    def owner(self):
58
        return self._owner
59

    
60
    '''
61
        @brief  setter owner
62
        @author humkyung
63
        @date   2018.05.10
64
        @history    2018.05.17  Jeongwoo    Add Calling setColor
65
    '''
66
    @owner.setter
67
    def owner(self, value):
68
        self._owner = value
69

    
70
        if self._owner is None:
71
            self._color = self.DEFAULT_COLOR
72
        self.setColor(self._color)
73

    
74
    '''
75
        @brief  getter flow mark
76
        @author humkyung
77
        @date   2018.06.21
78
    '''
79
    @property
80
    def flowMark(self):
81
        return self._flowMark
82

    
83
    '''
84
        @brief  setter flow mark
85
        @author humkyung
86
        @date   2018.06.21
87
    '''
88
    @flowMark.setter
89
    def flowMark(self, value):
90
        self._flowMark = value
91

    
92
    '''
93
        @brief  getter of lineType
94
        @author humkyung
95
        @date   2018.06.27
96
    '''
97
    @property
98
    def lineType(self):
99
        return self._lineType
100
    
101
    '''
102
        @brief  setter of lineType
103
        @author humkyung
104
        @date   2018.06.27
105
    '''
106
    @lineType.setter
107
    def lineType(self, value):
108
        from AppDocData import AppDocData
109

    
110
        self._lineType = value
111

    
112
        docData = AppDocData.instance()
113
        config = docData.getLineTypeConfig(self._lineType)
114

    
115
        _pen = self.pen() 
116
        _pen.setWidth(config[1])
117
        _pen.setStyle(config[2])
118
        self.setPen(_pen)
119
        self.update()
120

    
121
    '''
122
        @brief  clone an object
123
    '''
124
    def clone(self):
125
        clone = QEngineeringLineItem()
126
        clone._vertices = copy.deepcopy(self._vertices)
127
        for vertex in clone._vertices:
128
            clone._pol.append(QPointF(vertex[0], vertex[1]))
129
        clone.buildItem()
130
        clone.isCreated = self.isCreated
131

    
132
        return clone
133

    
134
    '''
135
        @brief  dot product of given two vectors
136
        @author humkyung
137
        @date   2018.04.14
138
    '''
139
    def dotProduct(self, lhs, rhs):
140
        return sum([lhs[i]*rhs[i] for i in range(len(lhs))])
141

    
142
    '''
143
        @brief  distance between line and point
144
        @author humkyung
145
        @date   2018.04.16
146
    '''
147
    def distanceTo(self, pt):
148
        from shapely.geometry import Point, LineString
149

    
150
        startPt = self.startPoint()
151
        endPt = self.endPoint()
152
        line = LineString([(startPt[0], startPt[1]), (endPt[0], endPt[1])])
153
        dist = line.distance(Point(pt[0], pt[1]))
154

    
155
        return dist
156

    
157
    '''
158
        @brief  return perpendicular vector
159
        @author humkyung
160
        @date   2018.04.21
161
    '''
162
    def perpendicular(self):
163
        import math
164

    
165
        dx = self.endPoint()[0] - self.startPoint()[0]
166
        dy = self.endPoint()[1] - self.startPoint()[1]
167
        dx,dy = -dy,dx
168
        length = math.sqrt(dx*dx + dy*dy)
169
        dx /= length
170
        dy /= length
171

    
172
        return (dx,dy)
173

    
174
    '''
175
        @brief  return angle of line in radian
176
        @author humkyung
177
        @date   2018.04.22
178
    '''
179
    def angle(self):
180
        import math
181

    
182
        startPt = self.startPoint()
183
        endPt = self.endPoint()
184
        dx = endPt[0] - startPt[0]
185
        dy = endPt[1] - startPt[1]
186
        dot = self.dotProduct((1,0), (dx, dy))
187
        length = math.sqrt(dx*dx + dy*dy)
188
        return math.acos(dot/length)
189

    
190
    '''
191
        @brief  return length of line
192
        @author humkyung
193
        @date   2018.05.08
194
    '''
195
    def length(self):
196
        import math
197

    
198
        startPt = self.startPoint()
199
        endPt = self.endPoint()
200
        dx = endPt[0] - startPt[0]
201
        dy = endPt[1] - startPt[1]
202
        return math.sqrt(dx*dx + dy*dy)
203

    
204
    '''
205
        @brief  check if line is horizontal
206
        @author humkyung
207
        @date   2018.04.27
208
    '''
209
    def isHorizontal(self):
210
        import math
211

    
212
        startPt = self.startPoint()
213
        endPt = self.endPoint()
214
        dx = endPt[0] - startPt[0]
215
        dy = endPt[1] - startPt[1]
216

    
217
        return math.fabs(dx) > math.fabs(dy)
218

    
219
    '''
220
        @brief  check if line is vertical 
221
        @author humkyung
222
        @date   2018.04.27
223
    '''
224
    def isVertical(self):
225
        import math
226

    
227
        startPt = self.startPoint()
228
        endPt = self.endPoint()
229
        dx = endPt[0] - startPt[0]
230
        dy = endPt[1] - startPt[1]
231

    
232
        return math.fabs(dy) > math.fabs(dx)
233

    
234
    '''
235
        @brief  get intersection point between this and given line
236
        @author humkyung
237
        @date   2018.04.21
238
        @history    Jeongwoo 2018.05.15 Add normalize
239
                    Jeongwoo 2018.05.16 Add length == 0 check
240
    '''
241
    def intersection(self, line):
242
        import math
243
        from shapely.geometry import Point, LineString
244

    
245
        startPt = self.startPoint()
246
        endPt = self.endPoint()
247
        dx = endPt[0] - startPt[0]
248
        dy = endPt[1] - startPt[1]
249
        length = math.sqrt(dx*dx + dy*dy)
250
        if length == 0:
251
            return None
252
        dx /= length
253
        dy /= length
254
        lhs = LineString([(startPt[0] - dx*20, startPt[1] - dy*20), (endPt[0] + dx*20, endPt[1] + dy*20)])
255
        rhs = LineString(line)
256
        return lhs.intersection(rhs)
257

    
258
    '''
259
        @brief      check if two lines are connectable
260
        @author     humkyung
261
        @date       2018.05.12
262
        @history    Jeongwoo 18.05.15 Add check pt's type
263
                    Jeongwoo 18.05.16 Add length == 0 check
264
    '''
265
    def isConnectable(self, line, toler=20):
266
        import math
267

    
268
        startPt = line.startPoint()
269
        endPt = line.endPoint()
270

    
271
        dx = endPt[0] - startPt[0]
272
        dy = endPt[1] - startPt[1]
273
        length = math.sqrt(dx*dx + dy*dy)
274
        if length == 0:
275
            return False
276
        dx /= length
277
        dy /= length
278
        extendedLine = [(startPt[0] - dx*toler, startPt[1] - dy*toler), (endPt[0] + dx*toler, endPt[1] + dy*toler)]
279
        pt = self.intersection(extendedLine)
280

    
281
        return (pt is not None) and (type(pt) == shapely.geometry.point.Point)
282

    
283
    '''
284
        @brief      check if line and given item is jointable
285
        @author     humkyung
286
        @date       2018.06.26
287
        @history    humkyung 2018.07.03 allow item to be line or symbol
288
    '''
289
    def isJointed(self, item, toler=5):
290
        import math
291
        from SymbolSvgItem import SymbolSvgItem
292

    
293
        lhs = [self.startPoint(), self.endPoint()]
294
        if type(item) is QEngineeringLineItem:
295
            rhs = [item.startPoint(), item.endPoint()]
296
        elif issubclass(type(item), SymbolSvgItem):
297
            rhs = item.connPts
298
        else:
299
            rhs = []
300

    
301
        for pt in lhs:
302
            for _pt in rhs:
303
                dx = _pt[0] - pt[0]
304
                dy = _pt[1] - pt[1]
305
                if math.sqrt(dx*dx + dy*dy) < toler:
306
                    return True
307

    
308
        return False
309

    
310
    '''
311
        @brief      arrange vertex order
312
        @author     humkyung
313
        @date       2018.07.04
314
    '''
315
    def arrangeVertexOrder(self, arranged):
316
        import math
317

    
318
        lhs = [arranged.startPoint(), arranged.endPoint()]
319
        rhs = [self.startPoint(), self.endPoint()]
320

    
321
        index = 0
322
        indexed = 0
323
        minDist = None
324
        for pt in lhs:
325
            for _pt in rhs:
326
                index += 1
327
                dx = _pt[0] - pt[0]
328
                dy = _pt[1] - pt[1]
329
                dist = math.sqrt(dx*dx + dy*dy)
330
                if minDist is None or dist < minDist:
331
                    minDist = dist
332
                    indexed = index
333
                    
334
        if indexed == 1 or indexed == 4:
335
            self.reverse()
336

    
337
    '''
338
        @brief      check if two lines are extendable
339
        @author     humkyung
340
        @date       2018.06.25
341
        @history    humkyung 2018.06.27 check line type
342
    '''
343
    def isExtendable(self, line, toler=5):
344
        import math
345
        from SymbolSvgItem import SymbolSvgItem
346

    
347
        if self.lineType == line.lineType:
348
            if self.isHorizontal() and line.isHorizontal():
349
                flag = (line.conns[0] is not None and issubclass(type(line.conns[0]), SymbolSvgItem)) or (line.conns[1] is not None and issubclass(type(line.conns[1]), SymbolSvgItem))
350
                return (flag and (math.fabs(self.startPoint()[1] - line.startPoint()[1]) < toler))
351
            elif self.isVertical() and line.isVertical():
352
                flag = (line.conns[0] is not None and issubclass(type(line.conns[0]), SymbolSvgItem)) or (line.conns[1] is not None and issubclass(type(line.conns[1]), SymbolSvgItem))
353
                return (flag and (math.fabs(self.startPoint()[0] - line.startPoint()[0]) < toler))
354
            
355
        return False
356
        
357
    '''
358
        @brief      connect line and symbol is able to be connected and return symbol
359
        @author     humkyung
360
        @date       2018.04.16
361
        @history    humkyung 2018.05.08 check if line is possible to be connected
362
                    Jeongwoo 2018.05.15 Split if-statement and Connect each symbol and line
363
    '''
364
    def connectIfPossible(self, obj, toler):
365
        from shapely.geometry import Point
366
        from SymbolSvgItem import SymbolSvgItem
367
        res = []
368

    
369
        startPt = self.startPoint() 
370
        endPt = self.endPoint()
371

    
372
        if issubclass(type(obj), SymbolSvgItem):
373
            for i in range(len(obj.connPts)):
374
                pt = obj.connPts[i]
375
                if len(obj.conns) <= i: obj.conns.append(None)
376

    
377
                if (self.conns[0] is None) and (Point(startPt[0], startPt[1]).distance(Point(pt[0], pt[1])) < toler):
378
                    self.conns[0] = obj 
379
                    obj.conns[i] = self
380
                    res.append(obj)
381
                if (self.conns[1] is None) and (Point(endPt[0], endPt[1]).distance(Point(pt[0], pt[1])) < toler):
382
                    self.conns[1] = obj
383
                    obj.conns[i] = self
384
                    res.append(obj)
385
        elif type(obj) is QEngineeringLineItem:
386
            _startPt = obj.startPoint()
387
            _endPt = obj.endPoint()
388
            if((Point(startPt[0], startPt[1]).distance(Point(_startPt[0], _startPt[1])) < toler)):
389
                self.conns[0] = obj
390
                obj.conns[0] = self
391
                res.append(obj)
392
            if ((Point(startPt[0], startPt[1]).distance(Point(_endPt[0], _endPt[1])) < toler)):
393
                self.conns[0] = obj
394
                obj.conns[1] = self
395
                res.append(obj)
396
            
397
            if((Point(endPt[0], endPt[1]).distance(Point(_startPt[0], _startPt[1])) < toler)):
398
                self.conns[1] = obj
399
                obj.conns[0] = self
400
                res.append(obj)
401
            
402
            if ((Point(endPt[0], endPt[1]).distance(Point(_endPt[0], _endPt[1])) < toler)):
403
                self.conns[1] = obj
404
                obj.conns[1] = self
405
                res.append(obj)
406

    
407
        return res
408

    
409
    '''
410
        @brief      reverse line
411
        @author     humkyung
412
        @date       2018.07.03
413
    '''
414
    def reverse(self):
415
        clone = self._pol.toPolygon()
416
        self._pol.clear()
417
        for idx in reversed(range(clone.count())):
418
            self._pol.append(clone.at(idx))
419

    
420
    '''
421
        @brief      add flow arrow
422
        @author     humkyung
423
        @date       2018.05.08
424
        @history    2018.05.24  Jeongwoo    Modifying Draw Flow Arrow
425
    '''
426
    def addFlowArrow(self):
427
        import numpy as np
428
        import cv2
429
        import math
430
        import sys
431
        global src
432
        from shapely.geometry import Point
433
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem
434
        from AppDocData import AppDocData
435
        
436
        try:
437
            docData = AppDocData.instance()
438
            area = docData.getArea('Drawing')
439

    
440
            startPt = self.startPoint()
441
            endPt = self.endPoint()
442
            length = self.length()
443
            direction = [(endPt[0] - startPt[0]) / length, (endPt[1] - startPt[1]) / length]
444

    
445
            left = min(startPt[0], endPt[0])
446
            top = min(startPt[1], endPt[1])
447
            right = max(startPt[0], endPt[0])
448
            bottom = max(startPt[1], endPt[1])
449

    
450
            rect = None
451
            if self.isVertical():
452
                rect = QRectF(left - 10, top, (right - left) + 20, (bottom - top))
453
            else:
454
                rect = QRectF(left, top - 10, (right - left), (bottom - top) + 20)
455

    
456
            docData = AppDocData.instance()
457
            area = docData.getArea('Drawing')
458
            img = np.array(AppDocData.instance().getCurrentPidSource().getPyImageOnRect(rect))
459
            
460
            imgLine = cv2.threshold(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)[1]
461
            # remove noise
462
            imgLine = cv2.bitwise_not(imgLine)
463
            imgLine = cv2.erode(imgLine, np.ones((10, 10), np.uint8))
464

    
465
            image, contours, hierarchy = cv2.findContours(imgLine, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
466
            if contours:
467
                contours = sorted(contours, key=cv2.contourArea, reverse=True)
468
                [x, y, w, h] = cv2.boundingRect(contours[0])
469
                if w > 10 and w < 100 and h > 10 and h < 100:   # check arrow mark size
470
                    imgArrowMark = imgLine[y:y+h, x:x+w]
471

    
472
                    # DEBUG - display flow arrow area
473
                    '''
474
                    item = QGraphicsBoundingBoxItem(rect.left() + x - 10, rect.top() + y - 10, w + 20, h + 20)
475
                    item.isSymbol = True
476
                    item.angle = 0
477
                    item.setPen(QPen(Qt.red, 1, Qt.SolidLine))
478
                    item.setBrush(QBrush(QColor(255,255,0,100)))
479
                    self.scene().addItem(item)
480
                    '''
481
                    # up to here
482

    
483
                    edges = cv2.Canny(imgArrowMark, 50, 150, apertureSize=3)
484
                    lines = cv2.HoughLinesP(edges, 1, np.pi/180, 10, minLineLength=10, maxLineGap=5)
485

    
486
                    ####### HoughLinesP
487
                    if lines is not None:
488
                        maxLength = None
489
                        selected = None
490
                        for line in lines:
491
                            for x1, y1, x2, y2 in line:
492
                                dx = x2 - x1
493
                                dy = y2 - y1
494
                                selected = line
495
                                length = math.sqrt(dx*dx + dy*dy)
496
                                if maxLength is None or length > maxLength:
497
                                    maxLength = length
498
                                    selected = line
499

    
500
                        for x1, y1, x2, y2 in selected:
501
                            dx = math.fabs(x2 - x1)
502
                            dy = math.fabs(y2 - y1)
503
                            length = math.sqrt(dx*dx + dy*dy)
504
                            dx /= length
505
                            dy /= length
506
                            if (self.isVertical() and (dx < 0.001 or math.fabs(dx - 1) < 0.001)) or (self.isHorizontal() and (dx < 0.001 or math.fabs(dx - 1) < 0.001)): continue 
507
                            dist1 = self.distanceTo((rect.left() + x + x1, rect.top() + y + y1))
508
                            dist2 = self.distanceTo((rect.left() + x + x2, rect.top() + y + y2))
509
                            if dist1 > dist2:   # point which's distance is longer would be start point
510
                                _start = (rect.left() + x + x1, rect.top() + y + y1)
511
                                _end = (rect.left() + x + x2, rect.top() + y + y2)
512
                            else:
513
                                _start = (rect.left() + x + x2, rect.top() + y + y2)
514
                                _end = (rect.left() + x + x1, rect.top() + y + y1)
515
                            
516
                            # DEBUG display detected line
517
                            '''
518
                            poly = QGraphicsPolylineItem()
519
                            poly._pol.append(QPointF(_start[0], _start[1]))
520
                            poly._pol.append(QPointF(_end[0], _end[1]))
521
                            poly.setPen(QPen(Qt.red, 2, Qt.SolidLine))
522
                            poly.buildItem()
523
                            self.scene().addItem(poly)
524
                            '''
525
                            # up to here
526

    
527
                            dist1 = Point(startPt[0], startPt[1]).distance(Point(_start[0], _start[1]))
528
                            dist2 = Point(startPt[0], startPt[1]).distance(Point(_end[0], _end[1]))
529
                            if dist1 > dist2:
530
                                startPt,endPt = endPt,startPt
531
                                direction[0],direction[1] = -direction[0],-direction[1]
532
                                self.reverse()
533
                                    
534
                        center = [(startPt[0]+endPt[0])*0.5, (startPt[1]+endPt[1])*0.5]
535
                        arrow = QEngineeringFlowArrowItem(center, direction)
536
                        arrow.buildItem()
537
                        self.scene().addItem(arrow)
538

    
539
                        x = round(rect.left() + x - 5)
540
                        y = round(rect.top() + y - 5)
541
                        self.flowMark = ([x, y, w + 10, h + 10], None)
542
                else:
543
                    pass
544
        except Exception as ex:
545
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
546

    
547
    '''
548
        @breif  insert symbol
549
        @author humkyung
550
        @date   2018.04.22
551
    '''
552
    def insertSymbol(self, symbol, pos):
553
        import math
554
        from shapely.geometry import Point
555
        from shapely import affinity
556

    
557
        vec = self.perpendicular()
558
        line = [(pos.x() - vec[0]*20, pos.y() - vec[1]*20),(pos.x() + vec[0]*20, pos.y() + vec[1]*20)]
559
        origin = self.intersection(line)
560
        transform = QTransform()
561
        transform.translate(origin.x, origin.y)
562
        angle = self.angle()
563
        transform.rotateRadians(-angle)
564
        transform.translate(-symbol.origin[0], -symbol.origin[1])
565
        symbol.setTransform(transform)
566
        if 2 == len(symbol.connPts):    # 2 way component
567
            for i in range(len(symbol.connPts)):
568
                rotatedPt = affinity.rotate(Point(symbol.connPts[i][0] - symbol.origin[0], symbol.connPts[i][1] - symbol.origin[1]), -angle, Point(0, 0), use_radians=True)
569
                symbol.connPts[i] = (origin.x+rotatedPt.x, origin.y+rotatedPt.y)
570

    
571
            dx1 = symbol.connPts[0][0] - self.startPoint()[0]
572
            dy1 = symbol.connPts[0][1] - self.startPoint()[1]
573
            length1 = math.sqrt(dx1*dx1 + dy1*dy1)
574
            dx2 = symbol.connPts[1][0] - self.startPoint()[0]
575
            dy2 = symbol.connPts[1][1] - self.startPoint()[1]
576
            length2 = math.sqrt(dx2*dx2 + dy2*dy2)
577

    
578
            if length1 < length2:
579
                processLine = QEngineeringLineItem()
580
                processLine._pol.append(QPointF(symbol.connPts[1][0], symbol.connPts[1][1]))
581
                processLine._pol.append(QPointF(self.endPoint()[0], self.endPoint()[1]))
582
                processLine.buildItem()
583
                processLine.conns.append(symbol)
584
                processLine.conns.append(self.conns[1])
585
                self.scene().addItem(processLine)
586

    
587
                self._pol.replace(self._pol.count() - 1, QPointF(symbol.connPts[0][0], symbol.connPts[0][1]))
588
                self.conns[1] = symbol
589

    
590
                symbol.conns = []
591
                symbol.conns.append(self)
592
                symbol.conns.append(processLine)
593
            else:
594
                processLine = QEngineeringLineItem()
595
                processLine._pol.append(QPointF(symbol.connPts[0][0], symbol.connPts[0][1]))
596
                processLine._pol.append(QPointF(self.endPoint()[0], self.endPoint()[1]))
597
                processLine.buildItem()
598
                processLine.conns.append(symbol)
599
                processLine.conns.append(self.conns[1])
600
                self.scene().addItem(processLine)
601

    
602
                self._pol.replace(self._pol.count() - 1, QPointF(symbol.connPts[1][0], symbol.connPts[1][1]))
603
                self.conns[1] = symbol
604

    
605
                symbol.conns = []
606
                symbol.conns.append(processLine)
607
                symbol.conns.append(self)
608

    
609
            self.buildItem()
610
            self.update()
611

    
612
        symbol.loc = [origin.x - symbol.origin[0], origin.y - symbol.origin[1]]
613
        symbol.size = [symbol.boundingRect().width(), symbol.boundingRect().height()]
614
        self.scene().addItem(symbol)
615
        for connector in symbol.connectors:
616
            self.scene().addItem(connector)
617
    
618
    '''
619
        @brief  remove symbol
620
        @author humkyung
621
        @date   2018.04.23
622
    '''
623
    def removeSymbol(self, symbol):
624
        import math
625

    
626
        if 2 == len(symbol.conns):  # 2-way component
627
            connected = symbol.conns[0] if symbol.conns[0] is not self else symbol.conns[1]
628
            
629
            pts = []
630
            pts.append(self.startPoint())
631
            pts.append(self.endPoint())
632
            pts.append(connected.startPoint())
633
            pts.append(connected.endPoint())
634

    
635
            self.scene().removeItem(connected)
636

    
637
            start = None
638
            end = None
639
            maxDist = None
640
            for i in range(len(pts)):
641
                for j in range(i+1,len(pts)):
642
                    dx = pts[i][0] - pts[j][0]
643
                    dy = pts[i][1] - pts[j][1]
644
                    dist = math.sqrt(dx*dx + dy*dy)
645
                    if maxDist is None:
646
                        maxDist = dist
647
                        start = pts[i]
648
                        end = pts[j]
649
                    elif dist > maxDist:
650
                        maxDist = dist
651
                        start = pts[i]
652
                        end = pts[j]
653

    
654
            if (pts[0] == end) or (pts[1] == start): start,end = end,start
655

    
656
            self._pol.clear()
657
            self._pol.append(QPointF(start[0], start[1]))
658
            self._pol.append(QPointF(end[0], end[1]))
659
            self.buildItem()
660
            self.update()
661

    
662
    '''
663
        @brief  update line type
664
        @author humkyung
665
        @date   2018.07.05
666
    '''
667
    def updateLineType(self):
668
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
669

    
670
        if len(self.conns) == 2:
671
            lines = [item for item in self.conns if item is not None and type(item) is QEngineeringLineItem]
672
            insts = [item for item in self.conns if item is not None and type(item) is QEngineeringInstrumentItem]
673

    
674
            matches = [inst for inst in insts if (inst.measuredVariableCode + inst.typeModifier) not in ['FT', 'PT', 'TT', 'TI', 'TG', 'PG']]
675
            if matches:
676
                self.lineType = 'Electric'
677

    
678
                pool = [item for item in self.conns if item is not None and type(item) is QEngineeringLineItem]
679
                visited = []
680
                visited.extend(pool)
681
                while len(pool):
682
                    line = pool.pop()
683
                    line.lineType = 'Electric'
684

    
685
                    matches = [item for item in line.conns if item is not None and item not in visited and type(item) is QEngineeringLineItem]
686
                    pool.extend(matches)
687
                    visited.extend(matches)
688
            else:
689
                matches = [inst for inst in insts if (inst.measuredVariableCode + inst.typeModifier) in ['FT', 'PT', 'TT', 'TI', 'TG', 'PG']]
690
                if matches:
691
                    self.lineType = 'Connect To Process'
692

    
693
    def hoverEnterEvent(self, event):
694
        pass
695

    
696
    def hoverLeaveEvent(self, event):
697
        pass
698

    
699
    def hoverMoveEvent(self, event):
700
        pass
701
    
702
    '''
703
        @brief  remove item when user press delete key
704
        @author humkyung
705
        @date   2018.04.23
706
    '''
707
    def keyPressEvent(self, event): 
708
        if event.key() == Qt.Key_Delete:
709
            #self.removed.emit((QGraphicsPathItem)(self))
710
            self.scene().removeItem(self)
711
    
712
    '''
713
        @brief  draw rect when item is selected
714
        @author humkyung
715
        @date   2018.07.07
716
    '''
717
    def drawFocusRect(self, painter):
718
        self.focuspen = QPen(Qt.DotLine)
719
        self.focuspen.setColor(Qt.black)
720
        self.focuspen.setWidthF(1.5)
721
        hilightColor = QColor(255, 0, 0, 127)
722
        painter.setBrush(QBrush(hilightColor))
723
        painter.setPen(self.focuspen)
724
        painter.drawRect(self.boundingRect())
725

    
726
    '''
727
        @brief  override paint method
728
    '''
729
    def paint(self, painter, option, widget):
730
        QGraphicsPolylineItem.paint(self, painter, option, widget)
731
        if self.isSelected():
732
            self.drawFocusRect(painter)
733

    
734
    '''
735
        @brief  draw self to given image
736
        @author humkyung
737
        @date   2018.06.21
738
    '''
739
    def drawToImage(self, img, color, thickness):
740
        try:
741
            # write recognized lines to image
742
            ptStart = self.startPoint()
743
            ptEnd = self.endPoint()
744
            cv2.line(img, (round(ptStart[0]), round(ptStart[1])), (round(ptEnd[0]), round(ptEnd[1])), color, thickness)
745
            # up to here
746

    
747
            if self.flowMark is not None:
748
                x, y, w, h = self.flowMark[0]
749
                img[y:(y+h), x:(x+w)] = color
750
        except Exception as ex:
751
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
752

    
753
    '''
754
        @brief      parse xml code
755
        @author     humkyung
756
        @date       2018.06.27
757
    '''
758
    @staticmethod 
759
    def fromXml(node):
760
        item = None
761
        try:
762
            startPoint = [float(x) for x in node.find('STARTPOINT').text.split(',')]
763
            endPoint = [float(x) for x in node.find('ENDPOINT').text.split(',')]
764
            lineType = node.find('TYPE').text if node.find('TYPE') else 'Primary'
765
            item = QEngineeringLineItem(vertices=[startPoint, endPoint])
766
            item.lineType = lineType
767
            item.buildItem()
768
        except Exception as ex:
769
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
770

    
771
        return item
772

    
773
    '''
774
        @brief      generate xml code
775
        @author     humkyung
776
        @date       2018.04.23
777
        @history    humkyung 2018.06.27 write line type to xml
778
    '''
779
    def toXml(self):
780
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
781

    
782
        try:
783
            node = Element('LINE')
784
            uidNode = Element('UID')
785
            uidNode.text = str(self.uid)
786
            node.append(uidNode)
787

    
788
            startPt = self.startPoint()
789
            endPt = self.endPoint()
790

    
791
            startNode = Element('STARTPOINT')
792
            startNode.text = '{},{}'.format(startPt[0], startPt[1])
793
            node.append(startNode)
794

    
795
            endNode = Element('ENDPOINT')
796
            endNode.text = '{},{}'.format(endPt[0], endPt[1])
797
            node.append(endNode)
798

    
799
            typeNode = Element('TYPE')
800
            typeNode.text = self.lineType
801
            node.append(typeNode)
802
        except Exception as ex:
803
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
804

    
805
        return node
806

    
807
    '''
808
        @brief      Delete Line Item from scene
809
        @author     Jeongwoo
810
        @date       2018.05.29
811
        @history    2018.05.29  Add parameter 'self' / Make comments emit()
812
    '''
813
    def deleteLineItemFromScene(self):
814
        #self.removed.emit(self)
815
        self.scene().removeItem(self)
816
        
817
    '''
818
        @brief      Add Line Item 
819
        @author     Jeongwoo
820
        @date       2018.05.29
821
    '''
822
    def addLineItemToScene(self, scene):
823
        scene.addItem(self)
클립보드 이미지 추가 (최대 크기: 500 MB)