프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / Shapes / SymbolSvgItem.py @ 3d6ff047

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

1
#!/usr/bin/env/python3
2
# coding: utf-8
3

    
4
import sys
5
import os
6
import math
7
from PyQt5.QtGui import *
8
from PyQt5.QtCore import *
9
from PyQt5.QtSvg import *
10
from PyQt5.QtWidgets import (QApplication, QGraphicsItem)
11
from PyQt5.QtXml import *
12

    
13
from AppDocData import *
14
from EngineeringConnectorItem import QEngineeringConnectorItem
15
from EngineeringAbstractItem import QEngineeringAbstractItem
16
from UserInputAttribute import UserInputAttribute
17
import SelectAttributeCommand
18

    
19
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem):
20
    clicked = pyqtSignal(QGraphicsSvgItem)
21
    ZVALUE = 50
22
    HIGHLIGHT = '#BC4438'
23

    
24
    '''
25
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
26
                    18.05.11    Jeongwoo    Declare variable self.color
27
                    18.05.25    Jeongwoo    Call setColor() method
28
                    18.05.30    Jeongwoo    Add self variables (parentSymbol, childSymbol)
29
    '''
30
    def __init__(self, path, uid=None):
31
        import uuid
32

    
33
        QGraphicsSvgItem.__init__(self)
34
        QEngineeringAbstractItem.__init__(self)
35

    
36
        self.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable)
37
                      #QGraphicsItem.ItemIsMovable)
38
        
39
        self.uid = uuid.uuid4() if uid is None else uid
40
        self.name = ''
41
        self.type = ''
42
        self.angle = 0
43
        self.origin = None
44
        self.loc = None
45
        self.size = None
46
        self.attrs = [] # attributes
47
        self._owner = None
48
        self.parentSymbol = ''
49
        self.childSymbol = ''
50
        self.hasInstrumentLabel = 0
51
        # attributeType uid
52
        self.attribute = ''
53

    
54
        self.setAcceptHoverEvents(True)
55
        self.setAcceptedMouseButtons(Qt.LeftButton)
56
        self.setAcceptTouchEvents(True)
57
        
58
        self.currentCursor = 0
59
        self.transfer = Transfer()
60

    
61
        self.specBreak_offsetX = 0
62
        self.specBreak_offsetY = 0
63

    
64

    
65
        try:
66
            f = QFile(path)
67
            f.open(QIODevice.ReadOnly)
68
            array = f.readAll()
69
            self._document = QDomDocument()
70
            self._document.setContent(array)
71
            self._renderer = QSvgRenderer(self._document.toByteArray())
72
            self.setSharedRenderer(self._renderer)
73

    
74
            self.setColor(self._color)
75
            self._savedColor = self.getColor()
76
        except Exception as ex:
77
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
78
        finally:
79
            f.close()
80

    
81
        self.setZValue(SymbolSvgItem.ZVALUE)
82
            
83
    '''
84
        @breif  getter owner
85
        @author humkyung
86
        @date   2018.05.10
87
    '''
88
    @property
89
    def owner(self):
90
        return self._owner
91

    
92
    '''
93
        @brief  setter owner
94
        @author humkyung
95
        @date   2018.05.10
96
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
97
    '''
98
    @owner.setter
99
    def owner(self, value):
100
        self._owner = value
101

    
102
        if self._owner is None:
103
            self._color = self.DEFAULT_COLOR
104
        self.setColor(self._color)
105

    
106

    
107
    '''
108
        @brief  build symbol item
109
        @author humkyung
110
        @date   2018.05.02
111
        @history    2018.05.09  Jeongwoo    Clear self.connectors
112
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
113
    '''
114
    def buildItem(self, name, type, angle, loc, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel):
115
        try:
116
            docData = AppDocData.instance()
117
            symbolInfo = docData.getSymbolByQuery('name', name)
118
            self.name = name
119
            self.type = type
120
            self.angle = angle
121
            self.loc = loc
122
            self.size = size
123
            self.origin = origin
124
            originalPoint = symbolInfo.getOriginalPoint().split(',')
125
            self.symbolOrigin = (float(originalPoint[0]), float(originalPoint[1]))
126

    
127
            # setting connectors
128
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
129
            for index in range(len(connectionPoints)):
130
                split = connectionPoints[index].split(',')
131
                self.setConnector()
132
                self.connectors[index].setPos((float(split[0]) - self.specBreak_offsetX, float(split[1]) - self.specBreak_offsetY))
133
                self.connectors[index].connectPoint = (float(split[0]), float(split[1]))
134
                self.connectors[index].sceneConnectPoint = connPts[index] if len(connPts) > index else None
135
                
136
            self.parentSymbol = parentSymbol
137
            self.childSymbol = childSymbol
138
            self.hasInstrumentLabel = hasInstrumentLabel
139
            self.currentPointModeIndex = 0
140

    
141
            '''
142
            self.connectors.clear()
143
            center = (loc[0] + size[0]*0.5, loc[1] + size[1]*0.5)
144
            for pt in self.connPts:
145
                connector = QEngineeringConnectorItem(self)
146
                connector.setPos((pt[0] - loc[0], pt[1] - loc[1]))
147
                connector.setParentItem(self)
148
                self.connectors.append(connector)
149
            '''
150

    
151
            self.setToolTip(self.name)
152
        except Exception as ex:
153
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
154

    
155
    '''
156
        @brief  return bounding box of symbol
157
        @author humkyung
158
        @date   2018.04.08
159
    '''
160
    def rect(self):
161
        return self.sceneBoundingRect()
162
        
163
    '''
164
        @brief  return true if line is able to connect symbol
165
        @author humkyung
166
        @date   2018.04.13
167
    '''
168
    def isConnectable(self, line, offset,  toler=10):
169
        for connector in self.connectors:
170
            dx = connector.sceneConnectPoint[0] - (line[0][0] + offset[0])
171
            dy = connector.sceneConnectPoint[1] - (line[0][1] + offset[1])
172
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
173
            dx = connector.sceneConnectPoint[0] - (line[-1][0] + offset[0])
174
            dy = connector.sceneConnectPoint[1] - (line[-1][1] + offset[1])
175
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
176

    
177
        return False
178
 
179
    '''
180
        @brief      check if symbol and given item is jointed
181
        @author     humkyung
182
        @date       2018.07.03
183
    '''
184
    def isJointed(self, item, toler=5):
185
        import math
186
        from EngineeringLineItem import QEngineeringLineItem
187

    
188
        lhs = []
189
        for connector in self.connectors:
190
            lhs.append(connector.sceneConnectPoint)
191

    
192
        if type(item) is QEngineeringLineItem:
193
            rhs = [item.startPoint(), item.endPoint()]
194
        elif issubclass(type(item), SymbolSvgItem):
195
            rhs = []
196
            for connector in item.connectors:
197
                rhs.append(connector.sceneConnectPoint)
198
        else:
199
            rhs = []
200

    
201
        for pt in lhs:
202
            for _pt in rhs:
203
                dx = _pt[0] - pt[0]
204
                dy = _pt[1] - pt[1]
205
                if math.sqrt(dx*dx + dy*dy) < toler:
206
                    return True
207

    
208
        return False
209
       
210
    '''
211
        @brief      connect line and symbol is able to be connected and return line
212
        @author     humkyung
213
        @date       2018.04.16
214
        @history    humkyung 2018.05.08 check if symbol is possible to be connected
215
                    Jeongwoo 2018.05.15 Connect each symbol and line
216
    '''
217
    def connectIfPossible(self, obj, toler=10):
218
        from shapely.geometry import Point
219
        from EngineeringLineItem import QEngineeringLineItem
220
        res = []
221

    
222
        if type(obj) is QEngineeringLineItem:
223
            startPt = obj.startPoint()
224
            endPt = obj.endPoint()
225
            for i in range(len(self.connectors)):
226
                if (self.connectors[i].connectedItem is None) and (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
227
                    self.connectors[i].connectedItem = obj 
228
                    obj.connectors[0].connectedItem = self
229
                    res.append(obj)
230
                if (self.connectors[i].connectedItem is None) and (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
231
                    self.connectors[i].connectedItem = obj
232
                    obj.connectors[1].connectedItem = self
233
                    res.append(obj)
234
        elif issubclass(type(obj), SymbolSvgItem):
235
            for i in range(len(self.connectors)):
236
                for j in range(len(obj.connectors)):
237
                    _pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1])
238
                    if (self.connectors[i].connectedItem is None) and (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
239
                        self.connectors[i].connectedItem = obj 
240
                        obj.connectors[j].connectedItem = self
241
                        res.append(obj)
242

    
243
        return res
244

    
245
    '''
246
        @brief  get connection point close to given point in tolerance
247
        @author humkyung
248
        @dat
249
    '''
250
    def getConnectionPointCloseTo(self, pt, toler=10):
251
        import math
252

    
253
        for connector in self.connectors:
254
            dx = connector.sceneConnectPoint[0] - pt[0]
255
            dy = connector.sceneConnectPoint[1] - pt[1]
256
            if math.sqrt(dx*dx + dy*dy) < toler: return connPt
257
            
258
        return None
259

    
260
    '''
261
        @brief  return center of symbol
262
        @author humkyung
263
        @date   2018.04.08
264
    '''
265
    def center(self):
266
        return self.sceneBoundingRect().center()
267
        
268
    '''
269
        @brief      highlight connector and attribute
270
        @authro     humkyung
271
        @date       2018.05.02
272
    '''
273
    def hoverEnterEvent(self, event):
274
        try:
275
            from EngineeringTextItem import QEngineeringTextItem
276
            self.setHightlight()
277
            self.currentCursor = int(Qt.OpenHandCursor)
278
            cursor = QCursor(Qt.OpenHandCursor)
279
            QApplication.instance().setOverrideCursor(cursor)
280
            self.update()
281

    
282
            for attr in self.attrs:
283
                if issubclass(type(attr), QEngineeringTextItem):
284
                    attr.setDefaultTextColor(Qt.red)
285
                    attr.update()
286
                elif issubclass(type(attr), SymbolSvgItem):
287
                    attr._savedColor = attr.getColor()
288
                    attr.setColor(SymbolSvgItem.HIGHLIGHT)
289
                    attr.update()
290
        except Exception as ex: 
291
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
292

    
293
    '''
294
        @brief      unhighlight connector and attribute
295
        @author     humkyung
296
        @date       2018.05.02
297
        @history    kyouho 2018.07.18 edit ArrowCursor
298
    '''
299
    def hoverLeaveEvent(self, event):
300
        from EngineeringTextItem import QEngineeringTextItem
301
        self.unsetHightlight()
302
        self.currentCursor = int(Qt.ArrowCursor)
303
        cursor = QCursor(Qt.ArrowCursor)
304
        QApplication.instance().setOverrideCursor(cursor)
305
        self.update()
306

    
307
        for attr in self.attrs:
308
            if issubclass(type(attr), QEngineeringTextItem):
309
                attr.setDefaultTextColor(Qt.blue)
310
                attr.update()
311
            elif issubclass(type(attr), SymbolSvgItem):
312
                attr.setColor(attr._savedColor)
313
                attr.update()
314

    
315
    '''
316
        @brief      set highlight
317
        @author     kyouho
318
        @date       2018.08.27
319
    '''
320
    def setHightlight(self):
321
        self.setColor(SymbolSvgItem.HIGHLIGHT)
322
        self.update()
323

    
324
    '''
325
        @brief      unset highlight
326
        @author     kyouho
327
        @date       2018.08.27
328
    '''
329
    def unsetHightlight(self):
330
        self.setColor(self._savedColor)
331
        self.update()
332

    
333
    '''
334
        @brief  change cursor to CrossCursor if mouse point is close to connection point
335
        @author humkyung
336
        @date   2018.04.28
337
    '''
338
    def hoverMoveEvent(self, event):
339
        pass
340
    '''
341
        scenePos = self.mapToScene(event.pos())
342
        connPt = self.getConnectionPointCloseTo((scenePos.x(), scenePos.y()), 5)
343
        if connPt is not None:
344
            cursor = QCursor(Qt.CrossCursor)
345
            QApplication.instance().changeOverrideCursor(cursor)
346
        else:
347
            cursor = QCursor(Qt.OpenHandCursor)
348
            QApplication.instance().changeOverrideCursor(cursor)
349

350
        self.update()
351
    '''
352

    
353
    '''
354
        @brief      Mouse Press Event
355
        @author     Jeongwoo
356
        @date       18.04.11
357
        @history    kyouho 2018.07.18 add isClick logic
358
    '''
359
    def mousePressEvent(self, event):
360
        if event.buttons() == Qt.LeftButton:
361
            self.clicked.emit(self)
362

    
363
    '''
364
        @brief      Mouse Release Event
365
        @author     kyouho
366
        @date       18.07.17
367
    '''
368
    def mouseReleaseEvent(self, event):
369
        super().mouseReleaseEvent(event)
370

    
371
    '''
372
        @brief      Mouse Move Event
373
        @author     kyouho
374
        @date       18.07.17
375
    '''
376
    def removeSelfAttr(self, attributeName):
377
        for attr in self.attrs:
378
            if attr.attribute == attributeName:
379
                self.attrs.remove(attr)
380

    
381
    '''
382
        @brief      Find TextItem contain Point
383
        @author     kyouho
384
        @date       18.07.17
385
    '''
386
    def findTextItemInPoint(self, point):
387
        from EngineeringTextItem import QEngineeringTextItem
388
        
389
        scene = self.scene()
390
 
391
        for item in scene.items():
392
            if type(item) is QEngineeringTextItem:
393
                if self.isOverlapItemAndPoint(item, point):
394
                    return (True, item)
395

    
396
        return (False,)
397

    
398
    '''
399
        @brief      Check Overlap
400
        @author     kyouho
401
        @date       18.07.17
402
    '''
403
    def isOverlapItemAndPoint(self, item, point):
404
        x = point.x()
405
        y = point.y()
406
        loc = item.loc
407
        size = item.size
408

    
409
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
410
            return True
411
        else:
412
            return False
413

    
414
    '''
415
        @brief      Remove Attr
416
        @author     kyouho
417
        @date       18.07.17
418
    '''
419
    def removeAttr(self, item):
420
        scene = self.scene()
421
        for symbol in scene.items():
422
            if issubclass(type(symbol), SymbolSvgItem):
423
                for attr in symbol.attrs:
424
                    if attr == item:
425
                        symbol.attrs.remove(item)
426

    
427
    '''
428
        @brief  remove item when user press delete key
429
        @author humkyung
430
        @date   2018.04.23
431
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
432
                    2018.05.25  Jeongwoo    Seperate delete item method
433
    '''
434
    def keyPressEvent(self, event):
435
        if event.key() == Qt.Key_Delete:
436
            self.deleteSvgItemFromScene()
437
        elif event.key() == Qt.Key_R:
438
            self.rotateSymbol()
439
        elif event.key() == Qt.Key_O:
440
            self.changeStandardPoint()
441
        elif event.key() == Qt.Key_C:
442
            self.changeConnPoint()
443
            
444
    '''
445
        @brief      connect attribute
446
        @author     humkyung
447
        @date       2018.05.02
448
        @history    humkyung 2018.05.09 append only nearest size attribute
449
    '''
450
    def connectAttribute(self, attributes):
451
        import math
452
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
453

    
454
        self.attrs.clear()
455

    
456
        dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width())
457
        center = self.sceneBoundingRect().center()
458

    
459
        minDist = None
460
        selected = None
461
        for attr in attributes:
462
            if type(attr) is QEngineeringSizeTextItem:
463
                dx = attr.center().x() - center.x()
464
                dy = attr.center().y() - center.y()
465
                length = math.sqrt(dx*dx + dy*dy)
466
                if (length < dist*2) and (minDist is None or length < minDist):
467
                    minDist = length
468
                    selected = attr
469

    
470
        if selected is not None: self.attrs.append(selected)
471

    
472

    
473
    '''
474
        @Auther     Yecheol
475
        @Date       2018.07.06
476
        @History    add Get not connected Attribute Item
477
                    humkyung 2018.07.23 fixed the code
478
    '''
479
    def getConnectedLabel(self, worker):
480
        import math
481
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
482

    
483
        findSymbols = [symbol for symbol in worker.graphicsView.scene.items() if type(symbol) is QEngineeringInstrumentItem]
484

    
485
        for symbol in findSymbols:
486
            isConnected = False
487
            for connector in symbol.connectors:
488
                if connector.connectedItem is not None:
489
                     isConnected = True
490
                     break
491
                    
492
            if isConnected == False:
493
                dx = symbol.origin[0] - self.origin[0]
494
                dy = symbol.origin[1] - self.origin[1]
495
                if math.sqrt(dx*dx + dy*dy) < 200:
496
                    self.attrs.append(symbol)
497

    
498
    '''
499
        @brief      get attribute
500
        @author     humkyung
501
        @date       2018.06.14
502
        @history    kyouho  2018.07.18  Add only attr QEngineeringTextItem
503
    '''
504
    def getAttributes(self):
505
        from EngineeringTextItem import QEngineeringTextItem
506
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
507
        attrs = {}
508
        
509
        # 해당 Type의 attribute setting
510
        docData = AppDocData.instance()
511
        if self.type == 'Segment Breaks':
512
            attrs['Up Stream'] = ''
513
            attrs['Down Stream'] = ''
514
        
515
        symbolAttrs = docData.getSymbolAttribute(self.type)
516
        for attr in symbolAttrs:
517
            attrs[attr[0]] = ''
518

    
519

    
520
        for attr in self.attrs:
521
            if type(attr) is QEngineeringTextItem or issubclass(type(attr), SymbolSvgItem):
522
                attrs[attr.attribute] = attr.uid
523
            elif type(attr) is QEngineeringInstrumentItem:
524
                attrs['Label'] = '{}'.format(attr)
525
            elif type(attr) is UserInputAttribute:
526
                attrs[attr.attribute] = attr.text
527
            elif type(attr) is tuple:
528
                attrs[attr[0]] = attr[1]
529
        
530
        return attrs
531
    
532
    '''
533
        @brief      generate xml code
534
        @author     humkyung
535
        @date       2018.04.23
536
        @history    humkyung 2018.04.25 add angle xml node
537
                    humkyung 2018.04.27 add originalpoint xml node
538
                    humkyung 2018.05.02 add attribute of symbol
539
                    Jeongwoo 2018.05.30 add attribute of symbol (parentSymbol, childSymbol, type, connectionPoint)
540
                    yecheol  2018.07.11 add attribute of symbol (hasInstrumentLabel)
541
                    humkyung 2018.07.20 write owner's uid to xml
542
                    humkyung 2018.07.23 write connected item's uid to xml
543
                    kyouho  2018.07.31 
544
    '''
545
    def toXml(self):
546
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
547

    
548
        try:
549
            node = Element('SYMBOL')
550
            uidNode = Element('UID')
551
            uidNode.text = str(self.uid)
552
            node.append(uidNode)
553

    
554
            nameNode = Element('NAME')
555
            nameNode.text = self.name
556
            node.append(nameNode)
557

    
558
            attributeValueNode = Element('ATTRIBUTEVALUE')
559
            attributeValueNode.text = self.attribute
560
            node.append(attributeValueNode)
561

    
562
            typeNode = Element('TYPE')
563
            typeNode.text = self.type
564
            node.append(typeNode)
565

    
566
            # write owner's uid to xml
567
            if self.owner is not None:
568
                ownerNode = Element('OWNER')
569
                ownerNode.text = str(self.owner.uid)
570
                node.append(ownerNode)
571
            # up to here
572

    
573
            originNode = Element('ORIGINALPOINT')
574
            originNode.text = '{},{}'.format(self.origin[0], self.origin[1])
575
            node.append(originNode)
576

    
577
            connectorsNode = Element('CONNECTORS')
578
            for connector in self.connectors:
579
                connectorNode = Element('CONNECTOR')
580
                connectedItemNode = Element('CONNECTEDITEM')
581
                connectedItemNode.text = str(connector.connectedItem.uid) if connector.connectedItem is not None else 'None'
582
                connectPointNode = Element('CONNECTPOINT')
583
                connectPointNode.text = str(connector.connectPoint[0]) + ',' + str(connector.connectPoint[1])
584
                sceneConnectPointNode = Element('SCENECONNECTPOINT')
585
                sceneConnectPointNode.text = str(connector.sceneConnectPoint[0]) + ',' + str(connector.sceneConnectPoint[1])
586

    
587
                connectorNode.append(connectedItemNode)
588
                connectorNode.append(connectPointNode)
589
                connectorNode.append(sceneConnectPointNode)
590
                connectorsNode.append(connectorNode)
591
            node.append(connectorsNode)
592

    
593
            connectionNode = Element('CONNECTIONPOINT')
594
            connectionPoint = ''
595
            if self.connectors is not None:
596
                for index in range(len(self.connectors)):
597
                    if index != 0:
598
                        connectionPoint = connectionPoint + "/"
599
                    connTuple = self.connectors[index].sceneConnectPoint
600
                    connectionPoint = connectionPoint + str(connTuple[0]) + "," + str(connTuple[1])
601
            connectionNode.text = connectionPoint
602
            node.append(connectionNode)
603

    
604
            rect = self.sceneBoundingRect()
605
            locNode = Element('LOCATION')
606
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
607
            node.append(locNode)
608

    
609
            sizeNode = Element('SIZE')
610
            sizeNode.text = '{},{}'.format(rect.width(), rect.height())
611
            node.append(sizeNode)
612

    
613
            angleNode = Element('ANGLE')
614
            angleNode.text = str(self.angle)
615
            node.append(angleNode)
616

    
617
            parentSymbolNode = Element('PARENT')
618
            parentSymbolNode.text = str(self.parentSymbol)
619
            node.append(parentSymbolNode)
620

    
621
            childSymbolNode = Element('CHILD')
622
            childSymbolNode.text = str(self.childSymbol)
623
            node.append(childSymbolNode)
624

    
625
            hasInstrumentLabelNode = Element('HASINSTRUMENTLABEL')
626
            hasInstrumentLabelNode.text = str(self.hasInstrumentLabel)
627
            node.append(hasInstrumentLabelNode)
628

    
629
            attributesNode = Element('SYMBOLATTRIBUTES')
630
            for attr in self.attrs:
631
                if type(attr) is UserInputAttribute:
632
                    attributesNode.append(attr.toXml())
633
                elif type(attr) is not tuple:
634
                    attributeNode = Element('SYMBOLATTRIBUTE')
635
                    attributeNode.text = str(attr.uid)
636
                    attributesNode.append(attributeNode)
637
                elif type(attr) is tuple and self.type == 'Segment Breaks':
638
                    attributeNode = Element(attr[0].upper().replace(' ',''))
639
                    attributeNode.text = str(attr[1] if attr[1] is not None else '')
640
                    attributesNode.append(attributeNode)
641

    
642
            node.append(attributesNode)
643

    
644
            currentPointModeIndexNode = Element('CURRENTPOINTMODEINDEX')
645
            currentPointModeIndexNode.text = str(self.currentPointModeIndex)
646
            node.append(currentPointModeIndexNode)
647

    
648
            if self.type == 'Segment Breaks':
649
                specBreakOffsetXNode = Element('SPECBREAKOFFSETX')
650
                specBreakOffsetXNode.text = str(self.specBreak_offsetX)
651
                node.append(specBreakOffsetXNode)
652

    
653
                specBreakOffsetYNode = Element('SPECBREAKOFFSETY')
654
                specBreakOffsetYNode.text = str(self.specBreak_offsetY)
655
                node.append(specBreakOffsetYNode)
656

    
657
            
658

    
659
        except Exception as ex:
660
            return str(self.uid)
661
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
662

    
663
        return node 
664

    
665
    '''
666
        @brief  generate xml code for attribute
667
        @author humkyung
668
        @date   2018.05.02
669
    '''
670
    def toXmlAsAttribute(self, parent):
671
        for attr in self.attrs:
672
            parent.append(attr.toXml(self))
673

    
674
    '''
675
        @brief      parse xml code
676
        @author     humkyung
677
        @date       2018.07.20
678
        @history    humkyung 2018.07.20 parse uid from xml node
679
                    humkyung 2018.07.23 parse connected item's uid from xml node
680
                    kyouho  2018.07.31 
681
    '''
682
    @staticmethod 
683
    def fromXml(node):
684
        import uuid
685
        item = [None, None]
686

    
687
        try:
688
            uidNode = node.find('UID')
689
            uid = uidNode.text if uidNode is not None else uuid.uuid4() # generate UUID
690

    
691
            pt = [float(x) for x in node.find('LOCATION').text.split(',')]
692
            size = [float(x) for x in node.find('SIZE').text.split(',')]
693
            name = node.find('NAME').text
694
            angle = float(node.find('ANGLE').text)
695
            type = node.find('TYPE').text
696
            origin = [float(x) for x in node.find('ORIGINALPOINT').text.split(',')]
697
            connPts = []
698
            if node.find('CONNECTIONPOINT').text is not None:
699
                connPts = [(float(x.split(',')[0]), float(x.split(',')[1])) for x in node.find('CONNECTIONPOINT').text.split('/')]
700
            baseSymbol = node.find('PARENT').text
701
            childSymbolNode = node.find('CHILD')
702
            childSymbol = ''
703
            if childSymbolNode is not None:
704
                childSymbol = childSymbolNode.text
705
            
706
            ownerNode = node.find('OWNER')
707
            owner = ownerNode.text if ownerNode is not None else None
708

    
709
            hasInstrumentLabelNode = node.find('HASINSTRUMENTLABEL')
710
            hasInstrumentLabel = hasInstrumentLabelNode.text if hasInstrumentLabelNode is not None else 'False'
711

    
712
            project = AppDocData.instance().getCurrentProject()
713
            svgFilePath = os.path.join(project.getSvgFilePath(), type, name + '.svg')
714
            if os.path.isfile(svgFilePath):
715
                item[0] = SymbolSvgItem.createItem(type, svgFilePath, uid)
716
                item[0].buildItem(name, type, angle, pt, size, origin, connPts, baseSymbol, childSymbol, hasInstrumentLabel)
717
                
718
                connectors = node.find('CONNECTORS')
719
                if connectors is not None:
720
                    iterIndex = 0
721
                    for connector in connectors.iter('CONNECTOR'):
722
                        connectedItemStr = connector.find('CONNECTEDITEM').text
723
                        connectPointStr = connector.find('CONNECTPOINT').text.split(',')
724
                        sceneConnectPointStr = connector.find('SCENECONNECTPOINT').text.split(',')
725

    
726
                        item[0].connectors[iterIndex].connectedItem = connectedItemStr if connectedItemStr != 'None' else None
727
                        item[0].connectors[iterIndex].connectPoint = (float(connectPointStr[0]), float(connectPointStr[1]))
728
                        item[0].connectors[iterIndex].sceneConnectPoint = (float(sceneConnectPointStr[0]), float(sceneConnectPointStr[1]))
729

    
730
                        iterIndex += 1
731
                
732
                attributeValue = node.find('ATTRIBUTEVALUE')
733
                if attributeValue is not None:
734
                    item[0].attribute = attributeValue.text
735

    
736
                attributes = node.find('SYMBOLATTRIBUTES')
737
                if attributes is not None:
738
                    for attr in attributes.iter('SYMBOLATTRIBUTE'):
739
                        item[0].attrs.append(attr.text)
740
                    for attr in attributes.iter('USERINPUTATTRIBUTE'):
741
                        typeUID = attr.find('TYPEUID').text
742
                        typeValue = attr.find('TYPEVALUE').text
743
                        item[0].attrs.append(UserInputAttribute(typeUID, typeValue))
744

    
745
                    if item[0].type == 'Segment Breaks':
746
                        upStreamNode = attributes.find('UPSTREAM')
747
                        downStreamNode = attributes.find('DOWNSTREAM')
748
                        if upStreamNode is not None :
749
                            item[0].attrs.append(('Up Stream', upStreamNode.text))
750
                        if downStreamNode is not None:
751
                            item[0].attrs.append(('Down Stream', downStreamNode.text))
752

    
753
                currentPointModeIndex = node.find('CURRENTPOINTMODEINDEX')
754
                if currentPointModeIndex is not None:
755
                    item[0].currentPointModeIndex = int(currentPointModeIndex.text)
756

    
757
                if item[0].type == 'Segment Breaks':
758
                    specBreakOffsetXNode = node.find('SPECBREAKOFFSETX')
759
                    specBreakOffsetYNode = node.find('SPECBREAKOFFSETY')
760
                    if specBreakOffsetXNode is not None and specBreakOffsetYNode is not None:
761
                        item[0].specBreak_offsetX = float(specBreakOffsetXNode.text)
762
                        item[0].specBreak_offsetY = float(specBreakOffsetYNode.text)
763
                        connLoc = item[0].connectors[0]._loc
764
                        item[0].connectors[0].setPos((float(connLoc[0] + item[0].specBreak_offsetX), float(connLoc[1] + item[0].specBreak_offsetY)))
765
                        item[0].reSettingSymbol(item[0].getCurrentPoint(), item[0].angle)
766

    
767
                item[1] = owner
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      create item corresponding to given type
775
        @author     humkyung
776
        @date       2018.05.02
777
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
778
                    humkyung 2018.05.10 change symbol's color to blue
779
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
780
    '''
781
    @staticmethod
782
    def createItem(type, path, uid=None):
783
        from QEngineeringOPCItem import QEngineeringOPCItem
784
        from QEngineeringEquipmentItem import QEngineeringEquipmentItem
785
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
786
        from EngineeringNozzleItem import QEngineeringNozzleItem
787
        from AppDocData import AppDocData
788

    
789
        docData = AppDocData.instance()
790

    
791
        item = None
792
        cateogry = docData.getSymbolCategoryByType(type)
793
        if type == "Piping OPC's":
794
            item = QEngineeringOPCItem(path, uid)
795
        elif cateogry == 'Equipment':
796
            item = QEngineeringEquipmentItem(path, uid)
797
        elif cateogry == 'Instrumentation':
798
            item = QEngineeringInstrumentItem(path, uid)
799
        elif type == 'Nozzles':
800
            item = QEngineeringNozzleItem(path, uid)
801
        else:
802
            item = SymbolSvgItem(path, uid)
803

    
804
        return item
805

    
806
    '''
807
        @brief      change svg's color
808
        @author     humkyung
809
        @date       2018.05.10
810
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
811
                    humkyung 2018.05.13 update after change color
812
    '''
813
    def setColor(self, color):
814
        self._color = color
815
        self.changeAttributes('fill', color)
816
        self.changeAttributes('stroke', color)
817
        self.renderer().load(self._document.toByteArray())
818
        self.update()
819

    
820
    '''
821
        @brief      Get Color code
822
        @author     Jeongwoo
823
        @date       2018.05.17
824
    '''
825
    def getColor(self):
826
        return self._color
827

    
828
    '''
829
        @brief  change attributes
830
        @author humkyung
831
        @date   2018.05.10
832
    '''
833
    def changeAttributes(self, attName, attValue):
834
        root = self._document.documentElement()
835
        node = root.firstChild()
836
        while not node.isNull():
837
            if node.isElement():
838
                element = node.toElement()
839
                if element.hasAttribute(attName):
840
                    element.setAttribute(attName, attValue)
841

    
842
                if element.hasChildNodes():
843
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
844

    
845
            node = node.nextSibling()
846

    
847
    '''
848
        @brief  change attribute
849
        @author humkyung
850
        @date   2018.05.10
851
    '''
852
    def recursiveChangeAttributes(self, node, attName, attValue):
853
        while not node.isNull():
854
            if node.isElement():
855
                element = node.toElement()
856
                if element.hasAttribute(attName):
857
                    element.setAttribute(attName, attValue)
858

    
859
                if node.hasChildNodes():
860
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
861
            
862
            node = node.nextSibling()
863

    
864
    '''
865
        @brief  draw rect when item is selected
866
        @author humkyung
867
        @date   2018.07.07
868
    '''
869
    def drawFocusRect(self, painter):
870
        self.focuspen = QPen(Qt.DotLine)
871
        self.focuspen.setColor(Qt.black)
872
        self.focuspen.setWidthF(1.5)
873
        hilightColor = QColor(255, 0, 0, 127)
874
        painter.setBrush(QBrush(hilightColor))
875
        painter.setPen(self.focuspen)
876
        painter.drawRect(self.boundingRect())
877

    
878
    '''
879
        @brief  override paint(draw connection points)
880
        @author humkyung
881
        @date   2018.04.21
882
    '''
883
    def paint(self, painter, options=None, widget=None):
884
        painter.setClipRect(options.exposedRect)
885
        QGraphicsSvgItem.paint(self, painter, options, widget)
886
        if self.isSelected():
887
            self.drawFocusRect(painter)
888

    
889
    '''
890
        @brief      Add Svg Item into ImageViewer's Scene
891
        @author     Jeongwoo
892
        @date       2018.05.03
893
        @history    add connectors which's parent is symbol
894
                    kyouho  2018.07.30  remove connectors logic
895
    '''
896
    def addSvgItemToScene(self, scene):
897
        transform = QTransform()
898
        transform.translate(self.loc[0] + self.symbolOrigin[0] + self.specBreak_offsetX, self.loc[1] + self.symbolOrigin[1] + self.specBreak_offsetY)
899
        transform.rotateRadians(-self.angle)
900
        currentPoint = self.getCurrentPoint()
901
        transform.translate(-currentPoint[0] - self.specBreak_offsetX, -currentPoint[1] - self.specBreak_offsetY)
902

    
903
        self.setTransform(transform)
904
        scene.addItem(self)
905

    
906

    
907
    '''
908
        @brief      
909
        @author     humkyung
910
        @date       2018.07.27
911
    '''
912
    def onConnectorPosChaned(self, connector):
913
        pass
914

    
915
    '''
916
        @brief      set connector
917
        @author     kyouho
918
        @date       2018.07.26
919
    '''
920
    def setConnector(self):
921
        connector = QEngineeringConnectorItem(self)
922
        connector.setParentItem(self)
923
        self.connectors.append(connector)
924

    
925
    '''
926
    '''
927
    def refreshConnector(self):
928
        for connector in self.connectors:
929
            connector.buildItem()
930

    
931
    '''
932
        @brief      Delete svg item
933
        @author     Jeongwoo
934
        @date       2018.05.25
935
    '''
936
    def deleteSvgItemFromScene(self):
937
        for connector in self.connectors:
938
            if connector.connectedItem is not None:
939
                connector.connectedItem.removeSymbol(self)
940
                break
941

    
942
        self.transfer.onRemoved.emit(self)
943
        
944
    '''
945
        @brief      Return real item position
946
        @author     Jeongwoo
947
        @date       2018.05.25
948
    '''
949
    def boundingRectOnScene(self):
950
        rect = self.boundingRect()
951
        rect.moveTo(self.loc[0], self.loc[1])
952
        return rect
953

    
954
    '''
955
        @brief      rotate Symbol
956
        @author     kyouho
957
        @date       2018.07.24
958
    '''
959
    def rotateSymbol(self):
960
        #degree 0
961
        if 0 == self.angle:
962
            self.angle = 1.57
963
        #degree 90
964
        elif (1.57 == self.angle):
965
            self.angle = 3.14
966
        #degree 180
967
        elif 3.14 == self.angle:
968
            self.angle = 4.71
969
        #degree 270
970
        elif 4.71 == self.angle :
971
            self.angle = 0
972

    
973
        currentPoint = self.getCurrentPoint()
974
        self.reSettingSymbol(currentPoint, self.angle)
975

    
976
    '''
977
        @brief      resetting rotate Symbol
978
        @author     kyouho
979
        @date       2018.07.24
980
    '''
981
    def reSettingSymbol(self, standardPoint, angle):
982
        transform = QTransform()
983
        
984
        transform.translate(self.loc[0] + self.symbolOrigin[0] + self.specBreak_offsetX, self.loc[1] + self.symbolOrigin[1] + self.specBreak_offsetY)
985
        transform.rotateRadians(-angle)
986
        transform.translate(-standardPoint[0] - self.specBreak_offsetX, -standardPoint[1] - self.specBreak_offsetY)
987

    
988
        self.setTransform(transform)
989

    
990
        from EngineeringLineItem import QEngineeringLineItem
991
        for connector in self.connectors:
992
            if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
993
                line = connector.connectedItem
994
                line.reDrawLine(self, connector.center())
995

    
996

    
997
    '''
998
        @brief      change Conn point 
999
        @author     kyouho
1000
        @date       2018.07.25
1001
    '''
1002
    def changeConnPoint(self):
1003
        if len(self.connectors) == 2:
1004

    
1005
            conn1Item = self.connectors[0].connectedItem
1006
            conn2Item = self.connectors[1].connectedItem
1007
            self.connectors[0].connectedItem = conn2Item
1008
            self.connectors[1].connectedItem = conn1Item
1009

    
1010
            currentPoint = self.getCurrentPoint()
1011
            self.reSettingSymbol(currentPoint, self.angle)
1012

    
1013
    '''
1014
        @brief      change standard point
1015
        @author     kyouho
1016
        @date       2018.07.24
1017
    '''
1018
    def changeStandardPoint(self):
1019
        connPtsCount = len(self.connectors)
1020
        
1021
        if self.currentPointModeIndex < connPtsCount:
1022
            self.currentPointModeIndex += 1
1023
        else:
1024
            self.currentPointModeIndex = 0
1025

    
1026
        currentPoint = self.getCurrentPoint()
1027
        self.reSettingSymbol(currentPoint, self.angle)
1028
    
1029
    '''
1030
        @brief      get standard point
1031
        @author     kyouho
1032
        @date       2018.07.25
1033
    '''
1034
    def getCurrentPoint(self):
1035
        pointList = []
1036
        pointList.append(self.symbolOrigin)
1037
        for connector in self.connectors:
1038
            pointList.append(connector.connectPoint)
1039

    
1040
        return pointList[self.currentPointModeIndex]
1041

    
1042
    '''
1043
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
1044
        @author     kyouho
1045
        @date       18.08.06
1046
    '''
1047
    def reCalculationRotatedItem(self):
1048

    
1049
        transform = QTransform()
1050
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1051
        transform.rotateRadians(-self.angle)
1052
        currentPoint = self.getCurrentPoint()
1053
        transform.translate(-currentPoint[0], -currentPoint[1])
1054
        # 시작점을 구하기 위해서
1055
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1056
        
1057
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1058

    
1059

    
1060
def recursiveChangeAttributes(node, attName, attValue):
1061
    while not node.isNull():
1062
        if node.isElement():
1063
            element = node.toElement()
1064
            if element.hasAttribute(attName):
1065
                element.setAttribute(attName, attValue)
1066

    
1067
            if node.hasChildNodes():
1068
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
1069
        
1070
        node = node.nextSibling()
1071

    
1072
'''
1073
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1074
    @author     Jeongwoo
1075
    @date       2018.06.18
1076
'''
1077
class Transfer(QObject):
1078
    onRemoved = pyqtSignal(QGraphicsItem)
1079

    
1080
    def __init__(self, parent = None):
1081
        QObject.__init__(self, parent)
1082

    
1083

    
1084
if __name__ == '__main__':
1085
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
1086
    f.open(QIODevice.ReadOnly)
1087
    array = f.readAll()
1088
    document = QDomDocument()
1089
    document.setContent(array)
1090

    
1091
    root = document.documentElement()
1092
    node = root.firstChild()
1093
    while not node.isNull():
1094
        if node.isElement():
1095
            element = node.toElement()
1096
            if element.hasAttribute('fill'):
1097
                element.setAttribute('fill', '#FFFFF')
1098

    
1099
            if element.hasChildNodes():
1100
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
1101

    
1102
        node = node.nextSibling()
클립보드 이미지 추가 (최대 크기: 500 MB)