프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / Shapes / SymbolSvgItem.py @ 40db2c6f

이력 | 보기 | 이력해설 | 다운로드 (40.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 EngineeringSpecBreakItem import QEngineeringSpecBreakItem
17
from UserInputAttribute import UserInputAttribute
18
import SelectAttributeCommand
19

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

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

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

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

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

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

    
65

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

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

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

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

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

    
107

    
108
    '''
109
        @brief      build symbol item
110
        @author     humkyung
111
        @date       2018.05.02
112
        @history    2018.05.09  Jeongwoo    Clear self.connectors
113
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
114
    '''
115
    def buildItem(self, name, type, angle, loc, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel):
116
        try:
117
            docData = AppDocData.instance()
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
            symbolInfo = docData.getSymbolByQuery('name', name)
125
            originalPoint = symbolInfo.getOriginalPoint().split(',')
126
            self.symbolOrigin = (float(originalPoint[0]), float(originalPoint[1]))
127

    
128
            # setting connectors
129
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
130
            for index in range(len(connectionPoints)):
131
                tokens = connectionPoints[index].split(',')
132

    
133
                direction = 'AUTO'
134
                if len(tokens) == 2:
135
                    x = float(tokens[0])
136
                    y = float(tokens[1])
137
                elif len(tokens) == 3:
138
                    direction = tokens[0]
139
                    x = float(tokens[1])
140
                    y = float(tokens[2])
141

    
142
                self.setConnector()
143
                self.connectors[index].direction = direction
144
                self.connectors[index].setPos((x - self.specBreak_offsetX, y - self.specBreak_offsetY))
145
                self.connectors[index].connectPoint = (x, y)
146
                self.connectors[index].sceneConnectPoint = (connPts[index][0], connPts[index][1]) if len(connPts[index]) == 2 else (connPts[index][1], connPts[index][2]) \
147
                    if len(connPts) > index else None
148
                
149
            self.parentSymbol = parentSymbol
150
            self.childSymbol = childSymbol
151
            self.hasInstrumentLabel = hasInstrumentLabel
152
            self.currentPointModeIndex = 0
153

    
154
            self.setToolTip(self.name)
155
        except Exception as ex:
156
            from App import App 
157

    
158
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
159
            App.mainWnd().addMessage.emit(MessageType.Error, message)
160

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

    
183
        return False
184
 
185
    '''
186
        @brief      check if symbol and given item is jointed
187
        @author     humkyung
188
        @date       2018.07.03
189
    '''
190
    def isJointed(self, item, toler=5):
191
        import math
192
        from EngineeringLineItem import QEngineeringLineItem
193

    
194
        lhs = []
195
        for connector in self.connectors:
196
            lhs.append(connector.sceneConnectPoint)
197

    
198
        if type(item) is QEngineeringLineItem:
199
            rhs = [item.startPoint(), item.endPoint()]
200
        elif issubclass(type(item), SymbolSvgItem):
201
            rhs = []
202
            for connector in item.connectors:
203
                rhs.append(connector.sceneConnectPoint)
204
        else:
205
            rhs = []
206

    
207
        for pt in lhs:
208
            for _pt in rhs:
209
                dx = _pt[0] - pt[0]
210
                dy = _pt[1] - pt[1]
211
                if math.sqrt(dx*dx + dy*dy) < toler:
212
                    return True
213

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

    
228
        if type(obj) is QEngineeringLineItem:
229
            startPt = obj.startPoint()
230
            endPt = obj.endPoint()
231
            for i in range(len(self.connectors)):
232
                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):
233
                    self.connectors[i].connectedItem = obj 
234
                    obj.connectors[0].connectedItem = self
235
                    res.append(obj)
236
                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):
237
                    self.connectors[i].connectedItem = obj
238
                    obj.connectors[1].connectedItem = self
239
                    res.append(obj)
240
        elif issubclass(type(obj), SymbolSvgItem):
241
            for i in range(len(self.connectors)):
242
                for j in range(len(obj.connectors)):
243
                    _pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1])
244
                    if (self.connectors[i].connectedItem is None) and (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
245
                        self.connectors[i].connectedItem = obj 
246
                        obj.connectors[j].connectedItem = self
247
                        res.append(obj)
248

    
249
        return res
250

    
251
    '''
252
        @brief      check connector overlap specbreak
253
        @author     kyouho
254
        @date       2018.08.30
255
    '''
256
    def isConnectSpecBreak(self, specBreakList):
257
        for connector in self.connectors:
258
            for specBreak in specBreakList:
259
                if connector.isOverlapConnector(specBreak.connectors[0]):
260
                    return (True, connector)
261

    
262
        return (False,)
263

    
264
    '''
265
        @brief      disconnect connector item
266
        @author     kyouho
267
        @date       2018.08.30
268
    '''
269
    def disconnectedItemAtConnector(self, connector):
270
        for conn in self.connectors:
271
            if conn.isOverlapConnector(connector):
272
                conn.connectedItem = None
273

    
274
    '''
275
        @brief  get connection point close to given point in tolerance
276
        @author humkyung
277
        @dat
278
    '''
279
    def getConnectionPointCloseTo(self, pt, toler=10):
280
        import math
281

    
282
        for connector in self.connectors:
283
            dx = connector.sceneConnectPoint[0] - pt[0]
284
            dy = connector.sceneConnectPoint[1] - pt[1]
285
            if math.sqrt(dx*dx + dy*dy) < toler: return connPt
286
            
287
        return None
288

    
289
    '''
290
        @brief  return center of symbol
291
        @author humkyung
292
        @date   2018.04.08
293
    '''
294
    def center(self):
295
        return self.sceneBoundingRect().center()
296
        
297
    '''
298
        @brief      highlight connector and attribute
299
        @authro     humkyung
300
        @date       2018.05.02
301
    '''
302
    def hoverEnterEvent(self, event):
303
        try:
304
            from EngineeringTextItem import QEngineeringTextItem
305
            self.setHightlight()
306
            self.currentCursor = int(Qt.OpenHandCursor)
307
            cursor = QCursor(Qt.OpenHandCursor)
308
            QApplication.instance().setOverrideCursor(cursor)
309
            self.update()
310

    
311
            for attr in self.attrs:
312
                if issubclass(type(attr), QEngineeringTextItem):
313
                    attr.setDefaultTextColor(Qt.red)
314
                    attr.update()
315
                elif issubclass(type(attr), SymbolSvgItem):
316
                    attr._savedColor = attr.getColor()
317
                    attr.setColor(SymbolSvgItem.HIGHLIGHT)
318
                    attr.update()
319
        except Exception as ex: 
320
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
321

    
322
    '''
323
        @brief      unhighlight connector and attribute
324
        @author     humkyung
325
        @date       2018.05.02
326
        @history    kyouho 2018.07.18 edit ArrowCursor
327
    '''
328
    def hoverLeaveEvent(self, event):
329
        from EngineeringTextItem import QEngineeringTextItem
330
        self.unsetHightlight()
331
        self.currentCursor = int(Qt.ArrowCursor)
332
        cursor = QCursor(Qt.ArrowCursor)
333
        QApplication.instance().setOverrideCursor(cursor)
334
        self.update()
335

    
336
        for attr in self.attrs:
337
            if issubclass(type(attr), QEngineeringTextItem):
338
                attr.setDefaultTextColor(Qt.blue)
339
                attr.update()
340
            elif issubclass(type(attr), SymbolSvgItem):
341
                attr.setColor(attr._savedColor)
342
                attr.update()
343

    
344
    '''
345
        @brief      set highlight
346
        @author     kyouho
347
        @date       2018.08.27
348
    '''
349
    def setHightlight(self):
350
        self.setColor(SymbolSvgItem.HIGHLIGHT)
351
        self.update()
352

    
353
    '''
354
        @brief      unset highlight
355
        @author     kyouho
356
        @date       2018.08.27
357
    '''
358
    def unsetHightlight(self):
359
        self.setColor(self._savedColor)
360
        self.update()
361

    
362
    '''
363
        @brief  change cursor to CrossCursor if mouse point is close to connection point
364
        @author humkyung
365
        @date   2018.04.28
366
    '''
367
    def hoverMoveEvent(self, event):
368
        pass
369
    '''
370
        scenePos = self.mapToScene(event.pos())
371
        connPt = self.getConnectionPointCloseTo((scenePos.x(), scenePos.y()), 5)
372
        if connPt is not None:
373
            cursor = QCursor(Qt.CrossCursor)
374
            QApplication.instance().changeOverrideCursor(cursor)
375
        else:
376
            cursor = QCursor(Qt.OpenHandCursor)
377
            QApplication.instance().changeOverrideCursor(cursor)
378

379
        self.update()
380
    '''
381

    
382
    '''
383
        @brief      Mouse Press Event
384
        @author     Jeongwoo
385
        @date       18.04.11
386
        @history    kyouho 2018.07.18 add isClick logic
387
    '''
388
    def mousePressEvent(self, event):
389
        if event.buttons() == Qt.LeftButton:
390
            self.clicked.emit(self)
391

    
392
    '''
393
        @brief      Mouse Release Event
394
        @author     kyouho
395
        @date       18.07.17
396
    '''
397
    def mouseReleaseEvent(self, event):
398
        super().mouseReleaseEvent(event)
399

    
400
    '''
401
        @brief      Mouse Move Event
402
        @author     kyouho
403
        @date       18.07.17
404
    '''
405
    def removeSelfAttr(self, attributeName):
406
        for attr in self.attrs:
407
            if attr.attribute == attributeName:
408
                self.attrs.remove(attr)
409

    
410
    '''
411
        @brief      Find TextItem contain Point
412
        @author     kyouho
413
        @date       18.07.17
414
    '''
415
    def findTextItemInPoint(self, point):
416
        from EngineeringTextItem import QEngineeringTextItem
417
        
418
        scene = self.scene()
419
 
420
        for item in scene.items():
421
            if type(item) is QEngineeringTextItem:
422
                if self.isOverlapItemAndPoint(item, point):
423
                    return (True, item)
424

    
425
        return (False,)
426

    
427
    '''
428
        @brief      Check Overlap
429
        @author     kyouho
430
        @date       18.07.17
431
    '''
432
    def isOverlapItemAndPoint(self, item, point):
433
        x = point.x()
434
        y = point.y()
435
        loc = item.loc
436
        size = item.size
437

    
438
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
439
            return True
440
        else:
441
            return False
442

    
443
    '''
444
        @brief      Remove Attr
445
        @author     kyouho
446
        @date       18.07.17
447
    '''
448
    def removeAttr(self, item):
449
        scene = self.scene()
450
        for symbol in scene.items():
451
            if issubclass(type(symbol), SymbolSvgItem):
452
                for attr in symbol.attrs:
453
                    if attr == item:
454
                        symbol.attrs.remove(item)
455

    
456
    '''
457
        @brief  remove item when user press delete key
458
        @author humkyung
459
        @date   2018.04.23
460
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
461
                    2018.05.25  Jeongwoo    Seperate delete item method
462
    '''
463
    def keyPressEvent(self, event):
464
        if event.key() == Qt.Key_Delete:
465
            self.deleteSvgItemFromScene()
466
        elif event.key() == Qt.Key_R:
467
            self.rotateSymbol()
468
        elif event.key() == Qt.Key_O:
469
            self.changeStandardPoint()
470
        elif event.key() == Qt.Key_C:
471
            self.changeConnPoint()
472
            
473
    '''
474
        @brief      connect attribute
475
        @author     humkyung
476
        @date       2018.05.02
477
        @history    humkyung 2018.05.09 append only nearest size attribute
478
    '''
479
    def connectAttribute(self, attributes):
480
        import math
481
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
482

    
483
        self.attrs.clear()
484

    
485
        dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width())
486
        center = self.sceneBoundingRect().center()
487

    
488
        minDist = None
489
        selected = None
490
        for attr in attributes:
491
            if type(attr) is QEngineeringSizeTextItem:
492
                dx = attr.center().x() - center.x()
493
                dy = attr.center().y() - center.y()
494
                length = math.sqrt(dx*dx + dy*dy)
495
                if (length < dist*2) and (minDist is None or length < minDist):
496
                    minDist = length
497
                    selected = attr
498

    
499
        if selected is not None: self.attrs.append(selected)
500

    
501

    
502
    '''
503
        @Auther     Yecheol
504
        @Date       2018.07.06
505
        @History    add Get not connected Attribute Item
506
                    humkyung 2018.07.23 fixed the code
507
    '''
508
    def getConnectedLabel(self, worker):
509
        import math
510
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
511

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

    
514
        for symbol in findSymbols:
515
            isConnected = False
516
            for connector in symbol.connectors:
517
                if connector.connectedItem is not None:
518
                     isConnected = True
519
                     break
520
                    
521
            if isConnected == False:
522
                dx = symbol.origin[0] - self.origin[0]
523
                dy = symbol.origin[1] - self.origin[1]
524
                if math.sqrt(dx*dx + dy*dy) < 200:
525
                    self.attrs.append(symbol)
526

    
527
    '''
528
        @brief      get attribute
529
        @author     humkyung
530
        @date       2018.06.14
531
        @history    kyouho  2018.07.18  Add only attr QEngineeringTextItem
532
    '''
533
    def getAttributes(self):
534
        from EngineeringTextItem import QEngineeringTextItem
535
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
536
        attrs = {}
537
        
538
        # 해당 Type의 attribute setting
539
        docData = AppDocData.instance()
540
        if type(attr) is QEngineeringSpecBreakItem:
541
            attrs['Up Stream'] = ''
542
            attrs['Down Stream'] = ''
543
        
544
        symbolAttrs = docData.getSymbolAttribute(self.type)
545
        for attr in symbolAttrs:
546
            attrs[attr[0]] = ''
547

    
548

    
549
        for attr in self.attrs:
550
            if type(attr) is QEngineeringTextItem or issubclass(type(attr), SymbolSvgItem):
551
                attrs[attr.attribute] = attr.uid
552
            elif type(attr) is QEngineeringInstrumentItem:
553
                attrs['Label'] = '{}'.format(attr)
554
            elif type(attr) is UserInputAttribute:
555
                attrs[attr.attribute] = attr.text
556
            elif type(attr) is tuple:
557
                attrs[attr[0]] = attr[1]
558
        
559
        return attrs
560
    
561
    '''
562
        @brief      generate xml code
563
        @author     humkyung
564
        @date       2018.04.23
565
        @history    humkyung 2018.04.25 add angle xml node
566
                    humkyung 2018.04.27 add originalpoint xml node
567
                    humkyung 2018.05.02 add attribute of symbol
568
                    Jeongwoo 2018.05.30 add attribute of symbol (parentSymbol, childSymbol, type, connectionPoint)
569
                    yecheol  2018.07.11 add attribute of symbol (hasInstrumentLabel)
570
                    humkyung 2018.07.20 write owner's uid to xml
571
                    humkyung 2018.07.23 write connected item's uid to xml
572
                    kyouho  2018.07.31 
573
    '''
574
    def toXml(self):
575
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
576

    
577
        try:
578
            node = Element('SYMBOL')
579
            uidNode = Element('UID')
580
            uidNode.text = str(self.uid)
581
            node.append(uidNode)
582

    
583
            nameNode = Element('NAME')
584
            nameNode.text = self.name
585
            node.append(nameNode)
586

    
587
            attributeValueNode = Element('ATTRIBUTEVALUE')
588
            attributeValueNode.text = self.attribute
589
            node.append(attributeValueNode)
590

    
591
            typeNode = Element('TYPE')
592
            typeNode.text = self.type
593
            node.append(typeNode)
594

    
595
            # write owner's uid to xml
596
            if self.owner is not None:
597
                ownerNode = Element('OWNER')
598
                ownerNode.text = str(self.owner.uid)
599
                node.append(ownerNode)
600
            # up to here
601

    
602
            originNode = Element('ORIGINALPOINT')
603
            originNode.text = '{},{}'.format(self.origin[0], self.origin[1])
604
            node.append(originNode)
605

    
606
            connectorsNode = Element('CONNECTORS')
607
            for connector in self.connectors:
608
                connectorNode = Element('CONNECTOR')
609
                connectedItemNode = Element('CONNECTEDITEM')
610
                connectedItemNode.text = str(connector.connectedItem.uid) if connector.connectedItem is not None else 'None'
611
                connectPointNode = Element('CONNECTPOINT')
612
                connectPointNode.text = str(connector.connectPoint[0]) + ',' + str(connector.connectPoint[1])
613
                sceneConnectPointNode = Element('SCENECONNECTPOINT')
614
                sceneConnectPointNode.text = str(connector.sceneConnectPoint[0]) + ',' + str(connector.sceneConnectPoint[1])
615

    
616
                connectorNode.append(connectedItemNode)
617
                connectorNode.append(connectPointNode)
618
                connectorNode.append(sceneConnectPointNode)
619
                connectorsNode.append(connectorNode)
620
            node.append(connectorsNode)
621

    
622
            connectionNode = Element('CONNECTIONPOINT')
623
            connectionPoint = ''
624
            if self.connectors is not None:
625
                for index in range(len(self.connectors)):
626
                    if index != 0:
627
                        connectionPoint = connectionPoint + "/"
628
                    connTuple = self.connectors[index].sceneConnectPoint
629
                    connectionPoint = connectionPoint + str(connTuple[0]) + "," + str(connTuple[1])
630
            connectionNode.text = connectionPoint
631
            node.append(connectionNode)
632

    
633
            rect = self.sceneBoundingRect()
634
            locNode = Element('LOCATION')
635
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
636
            node.append(locNode)
637

    
638
            sizeNode = Element('SIZE')
639
            sizeNode.text = '{},{}'.format(rect.width(), rect.height())
640
            node.append(sizeNode)
641

    
642
            angleNode = Element('ANGLE')
643
            angleNode.text = str(self.angle)
644
            node.append(angleNode)
645

    
646
            parentSymbolNode = Element('PARENT')
647
            parentSymbolNode.text = str(self.parentSymbol)
648
            node.append(parentSymbolNode)
649

    
650
            childSymbolNode = Element('CHILD')
651
            childSymbolNode.text = str(self.childSymbol)
652
            node.append(childSymbolNode)
653

    
654
            hasInstrumentLabelNode = Element('HASINSTRUMENTLABEL')
655
            hasInstrumentLabelNode.text = str(self.hasInstrumentLabel)
656
            node.append(hasInstrumentLabelNode)
657

    
658
            attributesNode = Element('SYMBOLATTRIBUTES')
659
            for attr in self.attrs:
660
                if type(attr) is UserInputAttribute:
661
                    attributesNode.append(attr.toXml())
662
                elif type(attr) is not tuple:
663
                    attributeNode = Element('SYMBOLATTRIBUTE')
664
                    attributeNode.text = str(attr.uid)
665
                    attributesNode.append(attributeNode)
666
                elif type(attr) is tuple and type(self) is QEngineeringSpecBreakItem:
667
                    attributeNode = Element(attr[0].upper().replace(' ',''))
668
                    attributeNode.text = str(attr[1] if attr[1] is not None else '')
669
                    attributesNode.append(attributeNode)
670

    
671
            node.append(attributesNode)
672

    
673
            currentPointModeIndexNode = Element('CURRENTPOINTMODEINDEX')
674
            currentPointModeIndexNode.text = str(self.currentPointModeIndex)
675
            node.append(currentPointModeIndexNode)
676

    
677
            if type(self) is QEngineeringSpecBreakItem:
678
                specBreakOffsetXNode = Element('SPECBREAKOFFSETX')
679
                specBreakOffsetXNode.text = str(self.specBreak_offsetX)
680
                node.append(specBreakOffsetXNode)
681

    
682
                specBreakOffsetYNode = Element('SPECBREAKOFFSETY')
683
                specBreakOffsetYNode.text = str(self.specBreak_offsetY)
684
                node.append(specBreakOffsetYNode)
685

    
686
            
687

    
688
        except Exception as ex:
689
            return str(self.uid)
690
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
691

    
692
        return node 
693

    
694
    '''
695
        @brief  generate xml code for attribute
696
        @author humkyung
697
        @date   2018.05.02
698
    '''
699
    def toXmlAsAttribute(self, parent):
700
        for attr in self.attrs:
701
            parent.append(attr.toXml(self))
702

    
703
    '''
704
        @brief      parse xml code
705
        @author     humkyung
706
        @date       2018.07.20
707
        @history    humkyung 2018.07.20 parse uid from xml node
708
                    humkyung 2018.07.23 parse connected item's uid from xml node
709
                    kyouho  2018.07.31 
710
    '''
711
    @staticmethod 
712
    def fromXml(node):
713
        import uuid
714
        item = [None, None]
715

    
716
        try:
717
            uidNode = node.find('UID')
718
            uid = uidNode.text if uidNode is not None else uuid.uuid4() # generate UUID
719

    
720
            pt = [float(x) for x in node.find('LOCATION').text.split(',')]
721
            size = [float(x) for x in node.find('SIZE').text.split(',')]
722
            name = node.find('NAME').text
723
            angle = float(node.find('ANGLE').text)
724
            type = node.find('TYPE').text
725
            origin = [float(x) for x in node.find('ORIGINALPOINT').text.split(',')]
726
            connPts = []
727
            if node.find('CONNECTIONPOINT').text is not None:
728
                connPts = [(float(x.split(',')[0]), float(x.split(',')[1])) for x in node.find('CONNECTIONPOINT').text.split('/')]
729
            baseSymbol = node.find('PARENT').text
730
            childSymbolNode = node.find('CHILD')
731
            childSymbol = ''
732
            if childSymbolNode is not None:
733
                childSymbol = childSymbolNode.text
734
            
735
            ownerNode = node.find('OWNER')
736
            owner = ownerNode.text if ownerNode is not None else None
737

    
738
            hasInstrumentLabelNode = node.find('HASINSTRUMENTLABEL')
739
            hasInstrumentLabel = hasInstrumentLabelNode.text if hasInstrumentLabelNode is not None else 'False'
740

    
741
            project = AppDocData.instance().getCurrentProject()
742
            svgFilePath = os.path.join(project.getSvgFilePath(), type, name + '.svg')
743
            if os.path.isfile(svgFilePath):
744
                item[0] = SymbolSvgItem.createItem(type, svgFilePath, uid)
745
                item[0].buildItem(name, type, angle, pt, size, origin, connPts, baseSymbol, childSymbol, hasInstrumentLabel)
746
                
747
                connectors = node.find('CONNECTORS')
748
                if connectors is not None:
749
                    iterIndex = 0
750
                    for connector in connectors.iter('CONNECTOR'):
751
                        connectedItemStr = connector.find('CONNECTEDITEM').text
752
                        connectPointStr = connector.find('CONNECTPOINT').text.split(',')
753
                        sceneConnectPointStr = connector.find('SCENECONNECTPOINT').text.split(',')
754

    
755
                        item[0].connectors[iterIndex].connectedItem = connectedItemStr if connectedItemStr != 'None' else None
756
                        item[0].connectors[iterIndex].connectPoint = (float(connectPointStr[0]), float(connectPointStr[1]))
757
                        item[0].connectors[iterIndex].sceneConnectPoint = (float(sceneConnectPointStr[0]), float(sceneConnectPointStr[1]))
758

    
759
                        iterIndex += 1
760
                
761
                attributeValue = node.find('ATTRIBUTEVALUE')
762
                if attributeValue is not None:
763
                    item[0].attribute = attributeValue.text
764

    
765
                attributes = node.find('SYMBOLATTRIBUTES')
766
                if attributes is not None:
767
                    for attr in attributes.iter('SYMBOLATTRIBUTE'):
768
                        item[0].attrs.append(attr.text)
769
                    for attr in attributes.iter('USERINPUTATTRIBUTE'):
770
                        typeUID = attr.find('TYPEUID').text
771
                        typeValue = attr.find('TYPEVALUE').text
772
                        item[0].attrs.append(UserInputAttribute(typeUID, typeValue))
773

    
774
                    if item[0].type == 'Segment Breaks':
775
                        upStreamNode = attributes.find('UPSTREAM')
776
                        downStreamNode = attributes.find('DOWNSTREAM')
777
                        if upStreamNode is not None :
778
                            item[0].attrs.append(('Up Stream', upStreamNode.text))
779
                        if downStreamNode is not None:
780
                            item[0].attrs.append(('Down Stream', downStreamNode.text))
781

    
782
                currentPointModeIndex = node.find('CURRENTPOINTMODEINDEX')
783
                if currentPointModeIndex is not None:
784
                    item[0].currentPointModeIndex = int(currentPointModeIndex.text)
785

    
786
                if item[0].type == 'Segment Breaks':
787
                    specBreakOffsetXNode = node.find('SPECBREAKOFFSETX')
788
                    specBreakOffsetYNode = node.find('SPECBREAKOFFSETY')
789
                    if specBreakOffsetXNode is not None and specBreakOffsetYNode is not None:
790
                        item[0].specBreak_offsetX = float(specBreakOffsetXNode.text)
791
                        item[0].specBreak_offsetY = float(specBreakOffsetYNode.text)
792
                        connLoc = item[0].connectors[0]._loc
793
                        item[0].connectors[0].setPos((float(connLoc[0] + item[0].specBreak_offsetX), float(connLoc[1] + item[0].specBreak_offsetY)))
794
                        item[0].reSettingSymbol(item[0].getCurrentPoint(), item[0].angle)
795

    
796
                item[1] = owner
797
        except Exception as ex:
798
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
799

    
800
        return item
801

    
802
    '''
803
        @brief      create item corresponding to given type
804
        @author     humkyung
805
        @date       2018.05.02
806
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
807
                    humkyung 2018.05.10 change symbol's color to blue
808
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
809
    '''
810
    @staticmethod
811
    def createItem(type, path, uid=None):
812
        from QEngineeringOPCItem import QEngineeringOPCItem
813
        from QEngineeringEquipmentItem import QEngineeringEquipmentItem
814
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
815
        from EngineeringNozzleItem import QEngineeringNozzleItem
816

    
817
        from AppDocData import AppDocData
818

    
819
        docData = AppDocData.instance()
820

    
821
        item = None
822
        cateogry = docData.getSymbolCategoryByType(type)
823
        if type == "Piping OPC's":
824
            item = QEngineeringOPCItem(path, uid)
825
        elif cateogry == 'Equipment':
826
            item = QEngineeringEquipmentItem(path, uid)
827
        elif cateogry == 'Instrumentation':
828
            item = QEngineeringInstrumentItem(path, uid)
829
        elif type == 'Nozzles':
830
            item = QEngineeringNozzleItem(path, uid)
831
        elif type == 'Segment Breaks':
832
            item = QEngineeringSpecBreakItem(path, uid)
833
        else:
834
            item = SymbolSvgItem(path, uid)
835

    
836
        return item
837

    
838
    '''
839
        @brief      change svg's color
840
        @author     humkyung
841
        @date       2018.05.10
842
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
843
                    humkyung 2018.05.13 update after change color
844
    '''
845
    def setColor(self, color):
846
        self._color = color
847
        self.changeAttributes('fill', color)
848
        self.changeAttributes('stroke', color)
849
        self.renderer().load(self._document.toByteArray())
850
        self.update()
851

    
852
    '''
853
        @brief      Get Color code
854
        @author     Jeongwoo
855
        @date       2018.05.17
856
    '''
857
    def getColor(self):
858
        return self._color
859

    
860
    '''
861
        @brief  change attributes
862
        @author humkyung
863
        @date   2018.05.10
864
    '''
865
    def changeAttributes(self, attName, attValue):
866
        root = self._document.documentElement()
867
        node = root.firstChild()
868
        while not node.isNull():
869
            if node.isElement():
870
                element = node.toElement()
871
                if element.hasAttribute(attName):
872
                    element.setAttribute(attName, attValue)
873

    
874
                if element.hasChildNodes():
875
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
876

    
877
            node = node.nextSibling()
878

    
879
    '''
880
        @brief  change attribute
881
        @author humkyung
882
        @date   2018.05.10
883
    '''
884
    def recursiveChangeAttributes(self, node, attName, attValue):
885
        while not node.isNull():
886
            if node.isElement():
887
                element = node.toElement()
888
                if element.hasAttribute(attName):
889
                    element.setAttribute(attName, attValue)
890

    
891
                if node.hasChildNodes():
892
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
893
            
894
            node = node.nextSibling()
895

    
896
    '''
897
        @brief  draw rect when item is selected
898
        @author humkyung
899
        @date   2018.07.07
900
    '''
901
    def drawFocusRect(self, painter):
902
        self.focuspen = QPen(Qt.DotLine)
903
        self.focuspen.setColor(Qt.black)
904
        self.focuspen.setWidthF(1.5)
905
        hilightColor = QColor(255, 0, 0, 127)
906
        painter.setBrush(QBrush(hilightColor))
907
        painter.setPen(self.focuspen)
908
        painter.drawRect(self.boundingRect())
909

    
910
    '''
911
        @brief  override paint(draw connection points)
912
        @author humkyung
913
        @date   2018.04.21
914
    '''
915
    def paint(self, painter, options=None, widget=None):
916
        painter.setClipRect(options.exposedRect)
917
        QGraphicsSvgItem.paint(self, painter, options, widget)
918
        if self.isSelected():
919
            self.drawFocusRect(painter)
920

    
921
    '''
922
        @brief      Add Svg Item into ImageViewer's Scene
923
        @author     Jeongwoo
924
        @date       2018.05.03
925
        @history    add connectors which's parent is symbol
926
                    kyouho  2018.07.30  remove connectors logic
927
    '''
928
    def addSvgItemToScene(self, scene):
929
        transform = QTransform()
930
        transform.translate(self.loc[0] + self.symbolOrigin[0] + self.specBreak_offsetX, self.loc[1] + self.symbolOrigin[1] + self.specBreak_offsetY)
931
        transform.rotateRadians(-self.angle)
932
        currentPoint = self.getCurrentPoint()
933
        transform.translate(-currentPoint[0] - self.specBreak_offsetX, -currentPoint[1] - self.specBreak_offsetY)
934

    
935
        self.setTransform(transform)
936
        scene.addItem(self)
937

    
938

    
939
    '''
940
        @brief      
941
        @author     humkyung
942
        @date       2018.07.27
943
    '''
944
    def onConnectorPosChaned(self, connector):
945
        pass
946

    
947
    '''
948
        @brief      set connector
949
        @author     kyouho
950
        @date       2018.07.26
951
    '''
952
    def setConnector(self):
953
        connector = QEngineeringConnectorItem(self)
954
        connector.setParentItem(self)
955
        self.connectors.append(connector)
956

    
957
    '''
958
    '''
959
    def refreshConnector(self):
960
        for connector in self.connectors:
961
            connector.buildItem()
962

    
963
    '''
964
        @brief      Delete svg item
965
        @author     Jeongwoo
966
        @date       2018.05.25
967
    '''
968
    def deleteSvgItemFromScene(self):
969
        for connector in self.connectors:
970
            if connector.connectedItem is not None:
971
                connector.connectedItem.removeSymbol(self)
972
                break
973

    
974
        self.transfer.onRemoved.emit(self)
975
        
976
    '''
977
        @brief      Return real item position
978
        @author     Jeongwoo
979
        @date       2018.05.25
980
    '''
981
    def boundingRectOnScene(self):
982
        rect = self.boundingRect()
983
        rect.moveTo(self.loc[0], self.loc[1])
984
        return rect
985

    
986
    '''
987
        @brief      rotate Symbol
988
        @author     kyouho
989
        @date       2018.07.24
990
    '''
991
    def rotateSymbol(self):
992
        #degree 0
993
        if 0 == self.angle:
994
            self.angle = 1.57
995
        #degree 90
996
        elif (1.57 == self.angle):
997
            self.angle = 3.14
998
        #degree 180
999
        elif 3.14 == self.angle:
1000
            self.angle = 4.71
1001
        #degree 270
1002
        elif 4.71 == self.angle :
1003
            self.angle = 0
1004

    
1005
        currentPoint = self.getCurrentPoint()
1006
        self.reSettingSymbol(currentPoint, self.angle)
1007

    
1008
    '''
1009
        @brief      resetting rotate Symbol
1010
        @author     kyouho
1011
        @date       2018.07.24
1012
    '''
1013
    def reSettingSymbol(self, standardPoint, angle):
1014
        transform = QTransform()
1015
        
1016
        transform.translate(self.loc[0] + self.symbolOrigin[0] + self.specBreak_offsetX, self.loc[1] + self.symbolOrigin[1] + self.specBreak_offsetY)
1017
        transform.rotateRadians(-angle)
1018
        transform.translate(-standardPoint[0] - self.specBreak_offsetX, -standardPoint[1] - self.specBreak_offsetY)
1019

    
1020
        self.setTransform(transform)
1021

    
1022
        from EngineeringLineItem import QEngineeringLineItem
1023
        for connector in self.connectors:
1024
            if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
1025
                line = connector.connectedItem
1026
                line.reDrawLine(self, connector.center())
1027

    
1028

    
1029
    '''
1030
        @brief      change Conn point 
1031
        @author     kyouho
1032
        @date       2018.07.25
1033
    '''
1034
    def changeConnPoint(self):
1035
        if len(self.connectors) == 2:
1036

    
1037
            conn1Item = self.connectors[0].connectedItem
1038
            conn2Item = self.connectors[1].connectedItem
1039
            self.connectors[0].connectedItem = conn2Item
1040
            self.connectors[1].connectedItem = conn1Item
1041

    
1042
            currentPoint = self.getCurrentPoint()
1043
            self.reSettingSymbol(currentPoint, self.angle)
1044

    
1045
    '''
1046
        @brief      change standard point
1047
        @author     kyouho
1048
        @date       2018.07.24
1049
    '''
1050
    def changeStandardPoint(self):
1051
        connPtsCount = len(self.connectors)
1052
        
1053
        if self.currentPointModeIndex < connPtsCount:
1054
            self.currentPointModeIndex += 1
1055
        else:
1056
            self.currentPointModeIndex = 0
1057

    
1058
        currentPoint = self.getCurrentPoint()
1059
        self.reSettingSymbol(currentPoint, self.angle)
1060
    
1061
    '''
1062
        @brief      get standard point
1063
        @author     kyouho
1064
        @date       2018.07.25
1065
    '''
1066
    def getCurrentPoint(self):
1067
        pointList = []
1068
        pointList.append(self.symbolOrigin)
1069
        for connector in self.connectors:
1070
            pointList.append(connector.connectPoint)
1071

    
1072
        return pointList[self.currentPointModeIndex]
1073

    
1074
    '''
1075
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
1076
        @author     kyouho
1077
        @date       18.08.06
1078
    '''
1079
    def reCalculationRotatedItem(self):
1080

    
1081
        transform = QTransform()
1082
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1083
        transform.rotateRadians(-self.angle)
1084
        currentPoint = self.getCurrentPoint()
1085
        transform.translate(-currentPoint[0], -currentPoint[1])
1086
        # 시작점을 구하기 위해서
1087
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1088
        
1089
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1090

    
1091

    
1092
def recursiveChangeAttributes(node, attName, attValue):
1093
    while not node.isNull():
1094
        if node.isElement():
1095
            element = node.toElement()
1096
            if element.hasAttribute(attName):
1097
                element.setAttribute(attName, attValue)
1098

    
1099
            if node.hasChildNodes():
1100
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
1101
        
1102
        node = node.nextSibling()
1103

    
1104
'''
1105
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1106
    @author     Jeongwoo
1107
    @date       2018.06.18
1108
'''
1109
class Transfer(QObject):
1110
    onRemoved = pyqtSignal(QGraphicsItem)
1111

    
1112
    def __init__(self, parent = None):
1113
        QObject.__init__(self, parent)
1114

    
1115

    
1116
if __name__ == '__main__':
1117
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
1118
    f.open(QIODevice.ReadOnly)
1119
    array = f.readAll()
1120
    document = QDomDocument()
1121
    document.setContent(array)
1122

    
1123
    root = document.documentElement()
1124
    node = root.firstChild()
1125
    while not node.isNull():
1126
        if node.isElement():
1127
            element = node.toElement()
1128
            if element.hasAttribute('fill'):
1129
                element.setAttribute('fill', '#FFFFF')
1130

    
1131
            if element.hasChildNodes():
1132
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
1133

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