프로젝트

일반

사용자정보

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

hytos / HYTOS / HYTOS / Shapes / SymbolSvgItem.py @ 47a53a74

이력 | 보기 | 이력해설 | 다운로드 (49.3 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
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QMessageBox
13

    
14
from AppDocData import *
15
from EngineeringAbstractItem import QEngineeringAbstractItem
16
from EngineeringConnectorItem import QEngineeringConnectorItem
17
from EngineeringEqpDescTextItem import QEngineeringEqpDescTextItem
18

    
19

    
20
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem):
21
    """ This is symbolsvgitem class """
22

    
23
    clicked = pyqtSignal(QGraphicsSvgItem)
24
    ZVALUE = 100
25
    HOVER_COLOR = 'url(#hover)'
26

    
27
    '''
28
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
29
                    18.05.11    Jeongwoo    Declare variable self.color
30
                    18.05.25    Jeongwoo    Call setColor() method
31
                    18.05.30    Jeongwoo    Add self variables (parentSymbol, childSymbol)
32
    '''
33

    
34
    def __init__(self, path, uid=None, flip=0):
35
        import uuid
36
        from SymbolAttr import SymbolProp
37

    
38
        QGraphicsSvgItem.__init__(self)
39
        QEngineeringAbstractItem.__init__(self)
40

    
41
        self.setFlags(
42
            QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsGeometryChanges)
43

    
44
        self.dbUid = None
45
        self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid, version=4)
46
        self.name = ''
47
        self.category = ''
48
        self.type = ''
49
        self.angle = 0
50
        self._scale = 1
51
        self.origin = None
52
        self.loc = None
53
        self.size = None
54
        self._owner = None
55
        self.parentSymbol = ''
56
        self.childSymbol = ''
57
        self.hasInstrumentLabel = 0
58
        self.flip = flip
59
        # attributeType uid
60
        self.attribute = ''
61
        self._properties = {SymbolProp(None, 'Supplied By', 'String'): None}
62

    
63
        self.setAcceptDrops(True)
64
        self.setAcceptHoverEvents(True)
65
        self.setAcceptedMouseButtons(Qt.LeftButton)
66
        self.setAcceptTouchEvents(True)
67

    
68
        self.currentCursor = 0
69
        self.transfer = Transfer()
70

    
71
        try:
72
            f = QFile(path)
73
            f.open(QIODevice.ReadOnly)
74
            array = f.readAll()
75
            self._document = QDomDocument()
76
            self._document.setContent(array)
77
            self._renderer = QSvgRenderer(self._document.toByteArray())
78
            self.setSharedRenderer(self._renderer)
79

    
80
            self._color = self.get_attribute('fill')
81
        except Exception as ex:
82
            from App import App
83
            from AppDocData import MessageType
84

    
85
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
86
                                                          sys.exc_info()[-1].tb_lineno)
87
            App.mainWnd().addMessage.emit(MessageType.Error, message)
88
        finally:
89
            f.close()
90

    
91
        self.setZValue(SymbolSvgItem.ZVALUE)
92
        self._desc_label = QEngineeringEqpDescTextItem('eqp name<br>pressure drop<br>elevation', self)
93

    
94
    def __str__(self):
95
        """ return string represent uuid """
96
        return str(self.uid)
97

    
98
    '''
99
        @breif  getter owner
100
        @author humkyung
101
        @date   2018.05.10
102
    '''
103

    
104
    @property
105
    def owner(self):
106
        import uuid
107

    
108
        if self._owner and type(self._owner) is uuid.UUID:
109
            matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._owner)]
110
            if matches: self._owner = matches[0]
111

    
112
        if type(self._owner) is not uuid.UUID and type(self._owner) is not str:
113
            return self._owner
114
        else:
115
            self._owner = None
116
            return None
117

    
118
    '''
119
        @brief  setter owner
120
        @author humkyung
121
        @date   2018.05.10
122
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
123
    '''
124

    
125
    @owner.setter
126
    def owner(self, value):
127
        self._owner = value
128

    
129
        if self._owner is None:
130
            self._color = self.DEFAULT_COLOR
131
        self.setColor(self._color)
132

    
133
    @property
134
    def properties(self):
135
        """ getter of properties """
136
        import uuid
137

    
138
        for prop, value in self._properties.items():
139
            try:
140
                if prop.is_selectable and type(value) is uuid.UUID and self.scene():
141
                    matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
142
                    if matches: self._properties[prop] = matches[0]
143

    
144
                if prop.Expression:
145
                    item = self._properties[prop]  # assign item
146
                    self._properties[prop] = eval(prop.Expression)
147
            except Exception as ex:
148
                from App import App
149

    
150
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
151
                                                              sys.exc_info()[-1].tb_lineno)
152
                App.mainWnd().addMessage.emit(MessageType.Error, message)
153

    
154
        return self._properties
155

    
156
    @properties.setter
157
    def properties(self, value):
158
        """ setter of properties """
159
        self._properties = value
160

    
161
    def set_property(self, property, value):
162
        """ set property with given value """
163
        if issubclass(type(value), QEngineeringAbstractItem): self.add_assoc_item(value, 0)
164
        matches = [prop for prop, _ in self._properties.items() if prop.Attribute == property]
165
        if matches: self._properties[matches[0]] = value
166

    
167
    def prop(self, name):
168
        """ return the value of given property with name """
169
        matches = [(prop, value) for prop, value in self.properties.items() if prop.Attribute == name]
170
        if matches: return matches[0][1]
171

    
172
        return None
173

    
174
    @property
175
    def desc_label(self):
176
        """ return equipment description label """
177

    
178
        return self._desc_label
179

    
180
    @property
181
    def Size(self):
182
        """ return valve's size """
183
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
184

    
185
        matches = [assoc for assoc in self.associations() if type(assoc) is QEngineeringSizeTextItem]
186
        if matches:
187
            return matches[0].text()
188
        else:
189
            return None
190

    
191
    def includes(self, pt, margin=0):
192
        """ return True if symbol contains given point else return False """
193
        rect = self.sceneBoundingRect()
194
        allowed_error = 0.1
195

    
196
        if abs(rect.x() - 0) <= allowed_error and abs(rect.y() - 0) <= allowed_error:
197
            # when first recognition step, symbols are not in scene(not yet added) therefore cannot use scenebounding rect
198
            minX = self.loc[0] - margin
199
            minY = self.loc[1] - margin
200
            maxX = minX + self.size[0] + margin
201
            maxY = minY + self.size[1] + margin
202
        else:
203
            minX = rect.x() - margin
204
            minY = rect.y() - margin
205
            maxX = minX + rect.width() + margin
206
            maxY = minY + rect.height() + margin
207

    
208
        # print([minX, minY, maxX, maxY])
209

    
210
        return True if (pt[0] >= minX and pt[0] <= maxX and pt[1] >= minY and pt[1] <= maxY) else False
211

    
212
    def toSql(self):
213
        """ convert valve data to sql query """
214
        import uuid
215
        from AppDocData import AppDocData
216

    
217
        res = []
218
        appDocData = AppDocData.instance()
219

    
220
        rect = self.sceneBoundingRect()
221

    
222
        cols = ['UID', 'Symbols_UID', 'X', 'Y', 'Rotation', 'Scale']
223
        values = ['?', '?', '?', '?', '?', '?']
224
        param = [str(self.uid), str(self.dbUid), rect.left(), rect.top(), str(self.angle), self.transform().m11()]
225
        sql = 'insert or replace into Components({}) values({})'.format(','.join(cols), ','.join(values))
226
        res.append((sql, tuple(param)))
227

    
228
        # save connectors to database
229
        index = 1
230
        for connector in self.connectors:
231
            res.extend(connector.toSql(index))
232
            index += 1
233
        # up to here
234

    
235
        return res
236

    
237
    '''
238
        @brief  build symbol item
239
        @author humkyung
240
        @date   2018.05.02
241
        @history    2018.05.09  Jeongwoo    Clear self.connectors
242
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
243
    '''
244

    
245
    def buildItem(self, name, _type, angle, scale, loc, origin, connPts, dbUid=None, pointsUids=None):
246
        try:
247
            if not hasattr(self, 'counters'): self.counters = {}
248
            if name in self.counters:
249
                self.counters[name] += 1
250
            else:
251
                self.counters[name] = 1
252

    
253
            self.name = name
254
            self.index = self.counters[name]
255
            self.type = _type
256
            self.angle = angle
257
            self._scale = scale
258
            self.loc = loc
259

    
260
            docData = AppDocData.instance()
261
            if dbUid is None:
262
                symbolInfo = docData.getSymbolByQuery('name', name)
263
            else:
264
                symbolInfo = docData.getSymbolByQuery('UID', dbUid)
265

    
266
            self.dbUid = symbolInfo.uid
267
            self.category = symbolInfo.sCategory
268
            originalPoint = symbolInfo.getOriginalPoint().split(',')
269
            self.symbolOrigin = [float(originalPoint[0]), float(originalPoint[1])]
270

    
271
            # setting connectors
272
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
273
            for index in range(len(connectionPoints)):
274
                if connectionPoints[index] == '':
275
                    break
276
                tokens = connectionPoints[index].split(',')
277

    
278
                direction = 'AUTO'
279
                symbol_idx = '0'
280

    
281
                if len(tokens) == 2:
282
                    x = float(tokens[0])
283
                    y = float(tokens[1])
284
                elif len(tokens) == 3:
285
                    direction = tokens[0]
286
                    x = float(tokens[1])
287
                    y = float(tokens[2])
288
                elif len(tokens) == 4:
289
                    direction = tokens[0]
290
                    x = float(tokens[1])
291
                    y = float(tokens[2])
292
                    symbol_idx = tokens[3]
293

    
294
                if pointsUids:
295
                    self.set_connector(pointsUids[index], index + 1)
296
                else:
297
                    self.set_connector(None, index + 1)
298

    
299
                self.connectors[index].direction = direction
300
                self.connectors[index].symbol_idx = symbol_idx
301
                self.connectors[index].setPos((x, y))
302
                self.connectors[index].connectPoint = (x, y)
303

    
304
            tooltip = '<b>{}</b><br>{}={}'.format(str(self.uid), self.type, self.name)
305
            self.setToolTip(tooltip)
306

    
307
            self.build_label()
308
        except Exception as ex:
309
            from App import App
310

    
311
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
312
                                                          sys.exc_info()[-1].tb_lineno)
313
            App.mainWnd().addMessage.emit(MessageType.Error, message)
314

    
315
    def build_label(self):
316
        """ build equipment label """
317

    
318
        rect = self.boundingRect()
319
        if self.name in ('CV_H', 'CV_V') or self.name == 'Line_Splitter' or self.name in ('Filter_H', 'Filter_V'):
320
            data = self.connectors[0].data
321
            self.desc_label.setHtml(f"{self.name}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
322
        elif self.name in ('Y_Strainer_H', 'Y_Strainer_V'):
323
            data = self.connectors[0].data
324
            self.desc_label.setHtml(f"{self.name}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
325
        elif self.name in ('L_Pump', 'R_Pump', 'V_Pump'):
326
            data = self.connectors[0].data
327
            self.desc_label.setHtml(f"{self.name}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
328
        elif self.name in ('Ori_Flowmeter_H', 'Oth_Flowmeter_H', 'Ven_Flowmeter_H', 'Ori_Flowmeter_V', 'Oth_Flowmeter_V',
329
                           'Ven_Flowmeter_V'):
330
            data = self.connectors[0].data
331
            self.desc_label.setHtml(f"{self.name}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
332
        elif self.name in ('HEX_V', 'HEX_DP', 'HEX_H', 'HEX_K', 'HEX_V'):
333
            data = [conn.data for conn in self.connectors
334
                    if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None)]
335
            if data:
336
                self.desc_label.setHtml(f"{self.name}<br>{data[0].pressure_drop} kg/cm2<br>{data[0].elevation} m")
337
        elif self.name == 'M_DP_E':
338
            data = [conn.data for conn in self.connectors
339
                    if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None)]
340
            if data:
341
                self.desc_label.setHtml(f"{self.name}<br>{data[0].pressure_drop} kg/cm2<br>{data[0].elevation} m")
342
        elif self.type == 'Battery Limit':
343
            data = [conn.data for conn in self.connectors
344
                    if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None)]
345
            if data:
346
                self.desc_label.setHtml(f"{self.name}<br>{data[0].pressure} kg/cm2(g)<br>{data[0].elevation} m")
347
        else:
348
            self.desc_label.setHtml(f"{self.name}")
349

    
350
        self.desc_label.setPos(QPointF(rect.width(), 0))
351

    
352
    '''
353
        @brief  return bounding box of symbol
354
        @author humkyung
355
        @date   2018.04.08
356
    '''
357

    
358
    def rect(self):
359
        return self.sceneBoundingRect()
360

    
361
    '''
362
        @brief  return true if line is able to connect symbol
363
        @author humkyung
364
        @date   2018.04.13
365
    '''
366

    
367
    def is_connectable(self, item, toler=10):
368
        # from EngineeringLineItem import QEngineeringLineItem
369

    
370
        '''
371
        if False:#type(item) is QEngineeringLineItem:
372
            line = item
373
            start_pt = line.startPoint()
374
            end_pt = line.endPoint()
375
            for connector in self.connectors:
376
                dx = connector.sceneConnectPoint[0] - (start_pt[0])
377
                dy = connector.sceneConnectPoint[1] - (start_pt[1])
378
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
379
                dx = connector.sceneConnectPoint[0] - (end_pt[0])
380
                dy = connector.sceneConnectPoint[1] - (end_pt[1])
381
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
382
        elif True:#issubclass(type(item), SymbolSvgItem):
383
        '''
384
        for connector in self.connectors:
385
            for iConnector in item.connectors:
386
                dx = connector.sceneConnectPoint[0] - iConnector.sceneConnectPoint[0]
387
                dy = connector.sceneConnectPoint[1] - iConnector.sceneConnectPoint[1]
388
                if (math.sqrt(dx * dx + dy * dy) < toler): return True
389

    
390
        return False
391

    
392
    '''
393
        @author     humkyung
394
        @date       2018.07.03
395
    '''
396

    
397
    def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
398
        """ check if given item is connected to self """
399

    
400
        _connectors = [connector for connector in self.connectors if
401
                       (connector.connectedItem == item and (connector._connected_at == at if at else True))]
402
        return len(_connectors) > 0
403

    
404
    def next_connected(self, lhs, rhs):
405
        """ check given two item's are next connected(ex: 0-1, 2-3) """
406

    
407
        lhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == lhs]
408
        rhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == rhs]
409
        if lhs_matches and rhs_matches:
410
            return (lhs_matches[0] in [0, 1] and rhs_matches[0] in [0, 1]) or (
411
                    lhs_matches[0] in [2, 3] and rhs_matches[0] in [2, 3])
412

    
413
        return False
414

    
415
    '''
416
        @brief      connect line and symbol is able to be connected and return line
417
        @author     humkyung
418
        @date       2018.04.16
419
        @history    humkyung 2018.05.08 check if symbol is possible to be connected
420
                    Jeongwoo 2018.05.15 Connect each symbol and line
421
    '''
422

    
423
    def connect_if_possible(self, obj, toler=10):
424
        from shapely.geometry import Point
425
        from EngineeringLineItem import QEngineeringLineItem
426

    
427
        res = []
428
        try:
429
            if type(obj) is QEngineeringLineItem:
430
                startPt = obj.startPoint()
431
                endPt = obj.endPoint()
432
                for i in range(len(self.connectors)):
433
                    if (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0],
434
                                                                     self.connectors[i].sceneConnectPoint[1])) < toler):
435
                        if self.connectors[i].connectedItem is None:
436
                            self.connectors[i].connect(obj)
437
                        if obj.connectors[0].connectedItem is None:
438
                            obj.connectors[0].connect(self)
439

    
440
                        res.append(obj)
441
                    if (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0],
442
                                                                 self.connectors[i].sceneConnectPoint[1])) < toler):
443
                        if self.connectors[i].connectedItem is None:
444
                            self.connectors[i].connect(obj)
445
                        if obj.connectors[1].connectedItem is None:
446
                            obj.connectors[1].connect(self)
447

    
448
                        res.append(obj)
449
            elif issubclass(type(obj), SymbolSvgItem):
450
                for i in range(len(self.connectors)):
451
                    for j in range(len(obj.connectors)):
452
                        _pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1])
453
                        if (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0],
454
                                               self.connectors[i].sceneConnectPoint[1])) < toler):
455
                            if self.connectors[i].connectedItem is None:
456
                                self.connectors[i].connect(obj)
457
                            if obj.connectors[j].connectedItem is None:
458
                                obj.connectors[j].connect(self)
459

    
460
                            res.append(obj)
461
        except Exception as ex:
462
            from App import App
463
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
464
                                                          sys.exc_info()[-1].tb_lineno)
465
            App.mainWnd().addMessage.emit(MessageType.Error, message)
466

    
467
        return res
468

    
469
    '''
470
        @brief      disconnect connector item
471
        @author     kyouho
472
        @date       2018.08.30
473
    '''
474

    
475
    def disconnectedItemAtConnector(self, connector):
476
        for conn in self.connectors:
477
            if conn.isOverlapConnector(connector):
478
                conn.connectedItem = None
479

    
480
    '''
481
        @brief  get connection point close to given point in tolerance
482
        @author humkyung
483
        @dat
484
    '''
485

    
486
    def getConnectionPointCloseTo(self, pt, toler=10):
487
        import math
488

    
489
        for connector in self.connectors:
490
            dx = connector.sceneConnectPoint[0] - pt[0]
491
            dy = connector.sceneConnectPoint[1] - pt[1]
492
            if math.sqrt(dx * dx + dy * dy) < toler: return connPt
493

    
494
        return None
495

    
496
    '''
497
        @brief  return center of symbol
498
        @author humkyung
499
        @date   2018.04.08
500
    '''
501

    
502
    def center(self):
503
        return self.sceneBoundingRect().center()
504

    
505
    '''
506
        @brief      highlight connector and attribute
507
        @authro     humkyung
508
        @date       2018.05.02
509
    '''
510

    
511
    def hoverEnterEvent(self, event):
512
        from Resizer import Resizer
513

    
514
        self.highlight(True)
515

    
516
        ''' 잠시 주석 처리 
517
        """ create a resizer """
518
        resizer = Resizer.instance()
519
        resizer.connected = self
520
        resizerWidth = resizer.rect.width() / 2
521
        rect = self.sceneBoundingRect()
522
        resizerOffset = QPointF(resizerWidth, resizerWidth)
523
        resizer.setPos(rect.bottomRight() - resizerOffset)
524
        if resizer.receivers(resizer.resizeSignal) > 0: resizer.resizeSignal.disconnect()
525
        resizer.resizeSignal.connect(self.resize)
526
        try:
527
            self.transfer.on_pos_changed.disconnect(resizer.on_symbol_pos_changed)
528
        except Exception as ex:
529
            pass
530
        self.transfer.on_pos_changed.connect(resizer.on_symbol_pos_changed)
531
        resizer.setVisible(True)
532
        if not resizer.scene(): self.scene().addItem(resizer)
533
        '''
534

    
535
    '''
536
        @brief      unhighlight connector and attribute
537
        @author     humkyung
538
        @date       2018.05.02
539
        @history    kyouho 2018.07.18 edit ArrowCursor
540
    '''
541

    
542
    def hoverLeaveEvent(self, event):
543
        self.highlight(False)
544

    
545
    def highlight(self, flag):
546
        """ highlight/unhighlight the symbol """
547

    
548
        try:
549
            self.hover = flag
550
            self.setZValue(QEngineeringAbstractItem.HOVER_ZVALUE) if flag else self.setZValue(SymbolSvgItem.ZVALUE)
551
            self.update()
552
        except Exception as ex:
553
            from App import App
554
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
555
                                                          sys.exc_info()[-1].tb_lineno)
556
            App.mainWnd().addMessage.emit(MessageType.Error, message)
557

    
558
    '''
559
        @brief      set highlight
560
        @author     kyouho
561
        @date       2018.08.27
562
    '''
563

    
564
    def setHightlight(self):
565
        self.setColor('url(#hover)')
566
        self.update()
567

    
568
    '''
569
        @brief      unset highlight
570
        @author     kyouho
571
        @date       2018.08.27
572
    '''
573

    
574
    def unsetHightlight(self):
575
        self.setColor('url(#normal)')
576
        self.update()
577

    
578
    '''
579
        @brief  change cursor to CrossCursor if mouse point is close to connection point
580
        @author humkyung
581
        @date   2018.04.28
582
    '''
583

    
584
    def hoverMoveEvent(self, event):
585
        pass
586

    
587
    '''
588
        @brief      Mouse Press Event
589
        @author     Jeongwoo
590
        @date       18.04.11
591
        @history    kyouho 2018.07.18 add isClick logic
592
    '''
593

    
594
    def mousePressEvent(self, event):
595
        if event.buttons() == Qt.LeftButton:
596
            self.clicked.emit(self)
597

    
598
    '''
599
        @brief      call on_pos_changed signal
600
        @author     humkyung
601
        @date       19.07.17
602
    '''
603

    
604
    def mouseReleaseEvent(self, event):
605
        super().mouseReleaseEvent(event)
606

    
607
    def itemChange(self, change, value):
608
        """ call signals when item's position is changed """
609
        if change == QGraphicsItem.ItemPositionHasChanged:
610
            self.transfer.on_pos_changed.emit(self)
611
            return value
612

    
613
        return super().itemChange(change, value)
614

    
615
    def removeSelfAttr(self, attributeName):
616
        target = None
617
        for attr in self.attrs:
618
            if attr.Attribute == attributeName:
619
                target = attr
620
                break
621

    
622
        if target:
623
            del self.attrs[attr]
624

    
625
    '''
626
        @brief      Check Overlap
627
        @author     kyouho
628
        @date       18.07.17
629
    '''
630

    
631
    def isOverlapItemAndPoint(self, item, point):
632
        x = point.x()
633
        y = point.y()
634
        loc = item.loc
635
        size = item.size
636

    
637
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
638
            return True
639
        else:
640
            return False
641

    
642
    '''
643
        @brief  remove item when user press delete key
644
        @author humkyung
645
        @date   2018.04.23
646
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
647
                    2018.05.25  Jeongwoo    Seperate delete item method
648
    '''
649

    
650
    def keyPressEvent(self, event):
651
        if not self.isSelected(): return
652

    
653
        if event.key() == Qt.Key_Delete:
654
            self.deleteSvgItemFromScene()
655
        elif event.key() == Qt.Key_QuoteLeft:
656
            self.mouseDoubleClickEvent(event)
657

    
658
    '''
659
        @brief      connect attribute
660
        @author     humkyung
661
        @date       2018.05.02
662
        @history    humkyung 2018.05.09 append only nearest size attribute
663
    '''
664

    
665
    def connectAttribute(self, attributes, clear=True):
666
        import math
667

    
668
        try:
669
            if clear:
670
                self.clear_attr_and_assoc_item()
671

    
672
            configs = AppDocData.instance().getConfigs('Range', 'Detection Ratio')
673
            ratio = float(configs[0].value) if 1 == len(configs) else 1.5
674

    
675
            dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width()) * ratio
676
            center = self.sceneBoundingRect().center()
677

    
678
            minDist = None
679
            selected = None
680
            for attr in attributes:
681
                # size text and operation code text will find onwer themselves in findowner method
682
                if False:  # type(attr) is QEngineeringSizeTextItem or type(attr) is QEngineeringValveOperCodeTextItem:
683
                    dx = attr.center().x() - center.x()
684
                    dy = attr.center().y() - center.y()
685
                    length = math.sqrt(dx * dx + dy * dy)
686
                    if (length < dist) and (minDist is None or length < minDist):
687
                        minDist = length
688
                        selected = attr
689
                elif type(attr) is QEngineeringInstrumentItem:
690
                    if not attr.is_connected:
691
                        dx = attr.center().x() - center.x()
692
                        dy = attr.center().y() - center.y()
693
                        if math.sqrt(dx * dx + dy * dy) < dist:
694
                            if self.add_assoc_item(attr):
695
                                attr.owner = self
696

    
697
            if selected is not None:
698
                if self.add_assoc_item(selected):
699
                    selected.owner = self
700

    
701
        except Exception as ex:
702
            from App import App
703
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
704
                                                          sys.exc_info()[-1].tb_lineno)
705
            App.mainWnd().addMessage.emit(MessageType.Error, message)
706

    
707
    '''
708
        @brief      Double click event, Show rotate symbol dialog
709
        @author     euisung
710
        @date       2019.04.16
711
    '''
712

    
713
    def mouseDoubleClickEvent(self, event):
714
        func_map = [
715
            (('Equipment - [ Pressure Drop ]', 'Air Fin Cooler', 'AF_Cooler'), self.show_AirFinCooler),
716
            (('Equipment - [ Pressure Drop ]', 'Filter', ('Filter_H', 'Filter_V')), self.show_Filter),
717
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_DP', 'HEX_H', 'HEX_K', 'HEX_V')),
718
             self.show_ShlTubHeatExchanger),
719
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_P')), self.show_PlateHeatExchanger),
720
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_Coil')), self.show_Coil),
721
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_DP_E')), self.show_DP_Equipment),
722
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_React')), self.show_Reactor),
723
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('T_Strainer_H', 'T_Strainer_V')), self.show_Strainer_T),
724
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('Y_Strainer_H', 'Y_Strainer_V')), self.show_Strainer_Y),
725
            (('Equipment - [ Pressurized ]', 'Battery Limit', None), self.show_BatteryLimit),
726
            (('Equipment - [ Pressurized ]', 'Column', ('CwT')), self.show_Tray),
727
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Single')), self.show_SinglePacked),
728
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Dual')), self.show_DualPacked),
729
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_H')), self.show_Drum_Horizontal),
730
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_V')), self.show_Drum_Vertical),
731
            (('Equipment - [ Pressurized ]', 'Miscellaneous', ('ME')), self.show_Equipment),
732
            (('Equipment - [ Pressurized ]', 'Tank', ('Ball_Tank')), self.show_Ball),
733
            (('Equipment - [ Pressurized ]', 'Tank', ('CRT')), self.show_ConeRoof),
734
            (('Equipment - [ Pressurized ]', 'Tank', ('DRT')), self.show_DomeRoof),
735
            (('Equipment - [ Rotating ]', 'Compressor', ('L_Comp', 'R_Comp')), self.show_Compressor),
736
            (('Equipment - [ Rotating ]', 'Pump', ('L_Pump', 'R_Pump', 'V_Pump')), self.show_Pump),
737
            (('Instrument', 'Valve', ('CV_H', 'CV_V')), self.show_ValveControl),
738
            (('Instrument', 'Valve', ('MV_H', 'MV_V')), self.show_ValveManual),
739
            (('Instrument', 'Line Splitter', ('Line_Splitter')), self.show_LineSplitter),
740
            (('Instrument', 'Flowmeter', (
741
                'Ori_Flowmeter_H', 'Oth_Flowmeter_H', 'Ven_Flowmeter_H', 'Ori_Flowmeter_V', 'Oth_Flowmeter_V',
742
                'Ven_Flowmeter_V')), self.show_Flowmeter),
743
            (('Instrument', 'Reducer', ('Re_Ex_Dw', 'Re_Ex_L', 'Re_Ex_R', 'Re_Ex_Up')), self.show_Reducer)
744
        ]
745

    
746
        connectedItems = [connector for connector in self.connectors if connector.connectedItem is not None]
747
        if len(connectedItems) < 1:
748
            msg = QMessageBox()
749
            msg.setIcon(QMessageBox.Information)
750
            msg.setText(self.tr('Connect Line before Data input'))
751
            msg.setWindowTitle(self.tr("Notice"))
752
            msg.setStandardButtons(QMessageBox.Ok)
753
            msg.exec_()
754
            return
755

    
756
        matches = [func for func in func_map if func[0][0] == self.category and func[0][1] == self.type and (
757
                func[0][2] is None or self.name in func[0][2])]
758
        if matches: matches[0][1]()
759

    
760
    def show_AirFinCooler(self):
761
        from AirFinCooler import QAirFinCooler
762

    
763
        dialog = QAirFinCooler()
764
        dialog.showDialog(self)
765

    
766
    def show_Filter(self):
767
        from Filter import QFilter
768

    
769
        dialog = QFilter()
770
        dialog.showDialog(self)
771

    
772
    def show_Coil(self):
773
        from Coil import QCoil
774

    
775
        dialog = QCoil()
776
        dialog.showDialog(self)
777

    
778
    def show_DP_Equipment(self):
779
        from DP_Equipment import QDP_Equipment
780

    
781
        dialog = QDP_Equipment()
782
        dialog.showDialog(self)
783

    
784
    def show_Reactor(self):
785
        from Reactor import QReactor
786

    
787
        dialog = QReactor()
788
        dialog.showDialog(self)
789

    
790
    def show_Strainer_T(self):
791
        from Strainer_T import QStrainer_T
792

    
793
        dialog = QStrainer_T()
794
        dialog.showDialog(self)
795

    
796
    def show_Strainer_Y(self):
797
        from Strainer_Y import QStrainer_Y
798

    
799
        dialog = QStrainer_Y()
800
        dialog.showDialog(self)
801

    
802
    def show_BatteryLimit(self):
803
        from BatteryLimit import QBatteryLimit
804

    
805
        dialog = QBatteryLimit()
806
        dialog.showDialog(self)
807

    
808
    def show_Tray(self):
809
        from Tray import QTray
810

    
811
        dialog = QTray()
812
        dialog.showDialog(self)
813

    
814
    def show_SinglePacked(self):
815
        from SinglePacked import QSinglePacked
816

    
817
        dialog = QSinglePacked()
818
        dialog.showDialog(self)
819

    
820
    def show_DualPacked(self):
821
        from DualPacked import QDualPacked
822

    
823
        dialog = QDualPacked()
824
        dialog.showDialog(self)
825

    
826
    def show_Drum_Horizontal(self):
827
        from Drum_Horizontal import QDrum_Horizontal
828

    
829
        dialog = QDrum_Horizontal()
830
        dialog.showDialog(self)
831

    
832
    def show_Drum_Vertical(self):
833
        from Drum_Vertical import QDrum_Vertical
834

    
835
        dialog = QDrum_Vertical()
836
        dialog.showDialog(self)
837

    
838
    def show_PlateHeatExchanger(self):
839
        from PlateHeatExchanger import QPlateHeatExchanger
840

    
841
        dialog = QPlateHeatExchanger()
842
        dialog.showDialog(self)
843

    
844
    def show_Equipment(self):
845
        from Equipment import QEquipment
846

    
847
        dialog = QEquipment()
848
        dialog.showDialog(self)
849

    
850
    def show_Ball(self):
851
        from Ball import QBall
852

    
853
        dialog = QBall()
854
        dialog.showDialog(self)
855

    
856
    def show_ShlTubHeatExchanger(self):
857
        from ShlTubHeatExchanger import QShlTubHeatExchanger
858

    
859
        dialog = QShlTubHeatExchanger()
860
        dialog.showDialog(self)
861

    
862
    def show_ConeRoof(self):
863
        from ConeRoof import QConeRoof
864

    
865
        dialog = QConeRoof()
866
        dialog.showDialog(self)
867

    
868
    def show_DomeRoof(self):
869
        from DomeRoof import QDomeRoof
870

    
871
        dialog = QDomeRoof()
872
        dialog.showDialog(self)
873

    
874
    def show_Compressor(self):
875
        from Compressor import QCompressor
876

    
877
        dialog = QCompressor()
878
        dialog.showDialog(self)
879

    
880
    def show_Pump(self):
881
        from Pump import QPump
882

    
883
        dialog = QPump()
884
        dialog.showDialog(self)
885

    
886
    def show_ValveControl(self):
887
        from Valve_Control import QValve_Control
888

    
889
        dialog = QValve_Control()
890
        dialog.showDialog(self)
891

    
892
    def show_ValveManual(self):
893
        from Valve_Manual import QValve_Manual
894

    
895
        dialog = QValve_Manual()
896
        dialog.showDialog(self)
897

    
898
    def show_LineSplitter(self):
899
        from LineSplitter import QLineSplitter
900

    
901
        dialog = QLineSplitter()
902
        dialog.showDialog(self)
903

    
904
    def show_Flowmeter(self):
905
        from Flowmeter import QFlowmeter
906

    
907
        dialog = QFlowmeter()
908
        dialog.showDialog(self)
909

    
910
    def show_Reducer(self):
911
        from Reducer import QReducer
912

    
913
        dialog = QReducer()
914
        dialog.showDialog(self)
915

    
916
    @staticmethod
917
    def fromDatabase(componentInfos):
918
        """ create a componenet from database """
919
        item = None
920

    
921
        try:
922
            uid = componentInfos[0][0]  # uid@Components
923
            dbUid = componentInfos[0][2]  # Symbol_UID@Components
924
            category = componentInfos[0][3]  # Category@SymbolType
925
            _type = componentInfos[0][4]  # Type@SymbolType
926
            name = componentInfos[0][5]  # Name@Symbols
927
            originalPoint = componentInfos[0][6]  # OriginalPoint@Symbols
928
            x = componentInfos[0][7]  # X@Components
929
            y = componentInfos[0][8]  # Y@Components
930
            angle = componentInfos[0][9]  # Rotation@Components
931
            scale = componentInfos[0][10]  # Scale@Components
932

    
933
            pt = []
934
            pt.append(float(x))
935
            pt.append(float(y))
936

    
937
            origin = [float(x) for x in str(originalPoint).split(',')]
938

    
939
            connPts = []
940

    
941
            pointsUids = []
942
            for componentInfo in componentInfos:
943
                pointsUid = componentInfo[11]  # uid@Points
944
                pointsUids.append(pointsUid)
945

    
946
            app_doc_data = AppDocData.instance()
947
            svgFilePath = os.path.join(app_doc_data.symbol_file_path, category, _type, name + '.svg')
948

    
949
            if os.path.isfile(svgFilePath):
950
                item = SymbolSvgItem.createItem(_type, svgFilePath, uid)
951
                item.setVisible(False)
952
                item.buildItem(name, _type, float(angle), float(scale), pt, origin, connPts, dbUid, pointsUids)
953
        except Exception as ex:
954
            from App import App
955
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
956
                                                          sys.exc_info()[-1].tb_lineno)
957
            App.mainWnd().addMessage.emit(MessageType.Error, message)
958

    
959
        return item
960

    
961
    '''
962
        @brief      create item corresponding to given type
963
        @author     humkyung
964
        @date       2018.05.02
965
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
966
                    humkyung 2018.05.10 change symbol's color to blue
967
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
968
    '''
969

    
970
    @staticmethod
971
    def createItem(type, path, uid=None, owner=None, flip=0):
972
        import uuid
973

    
974
        item = SymbolSvgItem(path, uid, flip=flip)
975

    
976
        if owner is not None:
977
            item.owner = uuid.UUID(owner, version=4)
978

    
979
        return item
980

    
981
    '''
982
        @brief      change svg's color
983
        @author     humkyung
984
        @date       2018.05.10
985
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
986
                    humkyung 2018.05.13 update after change color
987
    '''
988

    
989
    def setColor(self, color):
990
        self.changeAttributes('fill', color)
991
        self.changeAttributes('stroke', color)
992
        self.renderer().load(self._document.toByteArray())
993
        self.update()
994

    
995
    def getColor(self):
996
        """ return hover color if mouse is over otherwise reutrn owner's color if owner exist else this color """
997
        return SymbolSvgItem.HOVER_COLOR if self.hover else (
998
            self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color)
999

    
1000
    '''
1001
        @brief  get attributes from svg file
1002
        @author humkyung
1003
        @date   2019.03.08
1004
    '''
1005

    
1006
    def get_attribute(self, attName):
1007
        root = self._document.documentElement()
1008
        node = root.firstChild()
1009
        while not node.isNull():
1010
            if node.isElement():
1011
                element = node.toElement()
1012
                if element.hasAttribute(attName):
1013
                    return element.attribute(attName)
1014

    
1015
                if element.hasChildNodes():
1016
                    att_val = self.recursive_get_attribute(element.firstChild(), attName)
1017
                    if att_val is not None: return att_val
1018

    
1019
            node = node.nextSibling()
1020

    
1021
        return None
1022

    
1023
    '''
1024
        @brief  get recursively attribute
1025
        @author humkyung
1026
        @date   2019.03.08
1027
    '''
1028

    
1029
    def recursive_get_attribute(self, node, attName):
1030
        while not node.isNull():
1031
            if node.isElement():
1032
                element = node.toElement()
1033
                if element.hasAttribute(attName):
1034
                    return element.attribute(attName)
1035

    
1036
                if node.hasChildNodes():
1037
                    att_val = self.recursive_get_attribute(node.firstChild(), attName)
1038
                    if att_val is not None: return att_val
1039

    
1040
            node = node.nextSibling()
1041

    
1042
        return None
1043

    
1044
    '''
1045
        @brief  change attributes
1046
        @author humkyung
1047
        @date   2018.05.10
1048
    '''
1049

    
1050
    def changeAttributes(self, attName, attValue):
1051
        root = self._document.documentElement()
1052
        node = root.firstChild()
1053
        while not node.isNull():
1054
            if node.isElement():
1055
                element = node.toElement()
1056
                if element.hasAttribute(attName):
1057
                    element.setAttribute(attName, attValue)
1058

    
1059
                if element.hasChildNodes():
1060
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
1061

    
1062
            node = node.nextSibling()
1063

    
1064
    '''
1065
        @brief  change attribute
1066
        @author humkyung
1067
        @date   2018.05.10
1068
    '''
1069

    
1070
    def recursiveChangeAttributes(self, node, attName, attValue):
1071
        while not node.isNull():
1072
            if node.isElement():
1073
                element = node.toElement()
1074
                if element.hasAttribute(attName):
1075
                    element.setAttribute(attName, attValue)
1076

    
1077
                if node.hasChildNodes():
1078
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
1079

    
1080
            node = node.nextSibling()
1081

    
1082
    '''
1083
        @brief  draw rect when item is selected
1084
        @author humkyung
1085
        @date   2018.07.07
1086
    '''
1087

    
1088
    def draw_focus_rect(self, painter):
1089
        self.focuspen = QPen(Qt.DotLine)
1090
        self.focuspen.setColor(Qt.black)
1091
        self.focuspen.setWidthF(1.5)
1092
        hilightColor = QColor(255, 0, 0, 127)
1093
        painter.setBrush(QBrush(hilightColor))
1094
        painter.setPen(self.focuspen)
1095
        painter.drawRect(self.boundingRect())
1096

    
1097
    '''
1098
        @brief  override paint(draw connection points)
1099
        @author humkyung
1100
        @date   2018.04.21
1101
    '''
1102

    
1103
    def paint(self, painter, options=None, widget=None):
1104
        from EngineeringAbstractItem import QEngineeringAbstractItem
1105
        from EngineeringTextItem import QEngineeringTextItem
1106

    
1107
        self.setColor(self.getColor())
1108

    
1109
        painter.setClipRect(options.exposedRect)
1110
        QGraphicsSvgItem.paint(self, painter, options, widget)
1111
        for attr in self.attrs:
1112
            if issubclass(type(attr), QEngineeringTextItem):
1113
                color = QEngineeringAbstractItem.HOVER_COLOR if self.hover else (
1114
                    self._owner._color if self._owner else QEngineeringAbstractItem.DEFAULT_COLOR)
1115
                attr.setColor(color)
1116
            elif issubclass(type(attr), SymbolSvgItem):
1117
                attr.setColor(self.getColor())
1118
                attr.update()
1119

    
1120
        if self.isSelected():
1121
            self.draw_focus_rect(painter)
1122

    
1123
    '''
1124
        @brief      Add Svg Item into ImageViewer's Scene
1125
        @author     Jeongwoo
1126
        @date       2018.05.03
1127
        @history    add connectors which's parent is symbol
1128
                    kyouho  2018.07.30  remove connectors logic
1129
    '''
1130

    
1131
    def addSvgItemToScene(self, scene):
1132
        transform = QTransform()
1133

    
1134
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1135
        transform.rotateRadians(-self.angle)
1136
        transform.translate(-self.symbolOrigin[0], -self.symbolOrigin[1])
1137
        transform.scale(self._scale, self._scale)
1138

    
1139
        self.setTransform(transform)
1140
        scene.addItem(self)
1141

    
1142
    '''
1143
        @brief      
1144
        @author     humkyung
1145
        @date       2018.07.27
1146
    '''
1147

    
1148
    def onConnectorPosChaned(self, connector):
1149
        pass
1150

    
1151
    '''
1152
        @brief      set connector
1153
        @author     kyouho
1154
        @date       2018.07.26
1155
    '''
1156

    
1157
    def set_connector(self, uid, index=None):
1158
        from AppDocData import AppDocData
1159

    
1160
        app_doc_data = AppDocData.instance()
1161
        connector = QEngineeringConnectorItem(uid, parent=self, index=index)
1162
        connector.data = app_doc_data.get_nozzle_data(uid)
1163
        connector.setParentItem(self)
1164
        self.connectors.append(connector)
1165

    
1166
    '''
1167
    '''
1168

    
1169
    def refreshConnector(self):
1170
        for connector in self.connectors:
1171
            connector.buildItem()
1172

    
1173
    def deleteSvgItemFromScene(self):
1174
        """ remove self from scene """
1175
        try:
1176
            for conn in self.connectors:
1177
                if conn.connectedItem is not None:
1178
                    conn.connectedItem.connect(None)
1179
        except Exception as ex:
1180
            from App import App
1181
            from AppDocData import MessageType
1182

    
1183
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1184
                                                          sys.exc_info()[-1].tb_lineno)
1185
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1186

    
1187
        self.transfer.onRemoved.emit(self)
1188

    
1189
    '''
1190
        @brief      Return real item position
1191
        @author     Jeongwoo
1192
        @date       2018.05.25
1193
    '''
1194

    
1195
    def boundingRectOnScene(self):
1196
        rect = self.boundingRect()
1197
        rect.moveTo(self.loc[0], self.loc[1])
1198
        return rect
1199

    
1200
    def flipSymbol(self):
1201
        '''
1202
            @brief  remove item when user press delete key
1203
            @author humkyung
1204
            @date   2018.04.23
1205
        '''
1206
        if self.flip is 0:
1207
            self.flip = 1
1208
        else:
1209
            self.flip = 0
1210

    
1211
        currentPoint = self.getCurrentPoint()
1212
        self.reSettingSymbol(currentPoint, self.angle)
1213

    
1214
    '''
1215
        @brief      rotate Symbol
1216
        @author     kyouho
1217
        @date       2018.07.24
1218
    '''
1219

    
1220
    def rotateSymbol(self, angle=None):
1221
        if angle is None:
1222
            # degree 0
1223
            if 0 == self.angle:
1224
                self.angle = 1.57
1225
            # degree 90
1226
            elif (1.57 == self.angle):
1227
                self.angle = 3.14
1228
            # degree 180
1229
            elif 3.14 == self.angle:
1230
                self.angle = 4.71
1231
            # degree 270
1232
            elif 4.71 == self.angle:
1233
                self.angle = 0
1234
            else:
1235
                self.angle = 0
1236

    
1237
            self.size[0], self.size[1] = self.size[1], self.size[0]
1238
        else:
1239
            self.angle = angle
1240

    
1241
        # scene = self.scene()
1242
        # self.scene().removeItem(self)
1243
        # self.addSvgItemToScene(scene)
1244
        currentPoint = self.getCurrentPoint()
1245
        self.reSettingSymbol(currentPoint, self.angle)
1246

    
1247
    '''
1248
        @brief      resetting rotate Symbol
1249
        @author     kyouho
1250
        @date       2018.07.24
1251
    '''
1252

    
1253
    def reSettingSymbol(self, standardPoint, angle):
1254
        transform = QTransform()
1255

    
1256
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1257
        transform.rotateRadians(-angle)
1258
        transform.translate(-standardPoint[0], -standardPoint[1])
1259

    
1260
        if self.flip is 1:
1261
            transform.scale(-1.0, 1.0)
1262
            transform.translate(-self.size[0], 0)
1263

    
1264
        self.setTransform(transform)
1265
        self.reSettingConnetors()
1266

    
1267
    def reSettingConnetors(self):
1268
        for conn in self.connectors:
1269
            conn.sceneConnectPoint = (conn.sceneBoundingRect().center().x(), conn.sceneBoundingRect().center().y())
1270

    
1271
        from EngineeringLineItem import QEngineeringLineItem
1272
        for connector in self.connectors:
1273
            if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
1274
                line = connector.connectedItem
1275
                line.reDrawLine(self, connector.center())
1276
                line.update_arrow()
1277

    
1278
    '''
1279
        @brief      change Conn point 
1280
        @author     kyouho
1281
        @date       2018.07.25
1282
    '''
1283

    
1284
    def changeConnPoint(self):
1285
        if len(self.connectors) == 2:
1286
            conn1Item = self.connectors[0].connectedItem
1287
            conn2Item = self.connectors[1].connectedItem
1288
            self.connectors[0].connectedItem = conn2Item
1289
            self.connectors[1].connectedItem = conn1Item
1290

    
1291
            currentPoint = self.getCurrentPoint()
1292
            self.reSettingSymbol(currentPoint, self.angle)
1293

    
1294
    '''
1295
        @brief      change standard point
1296
        @author     kyouho
1297
        @date       2018.07.24
1298
    '''
1299

    
1300
    def changeStandardPoint(self):
1301
        connPtsCount = len(self.connectors)
1302

    
1303
        if self.currentPointModeIndex < connPtsCount:
1304
            self.currentPointModeIndex += 1
1305
        else:
1306
            self.currentPointModeIndex = 0
1307

    
1308
        currentPoint = self.getCurrentPoint()
1309
        self.reSettingSymbol(currentPoint, self.angle)
1310

    
1311
    '''
1312
        @brief      get standard point
1313
        @author     kyouho
1314
        @date       2018.07.25
1315
    '''
1316

    
1317
    def getCurrentPoint(self):
1318

    
1319
        pointList = []
1320
        pointList.append(self.symbolOrigin)
1321
        for connector in self.connectors:
1322
            pointList.append(connector.connectPoint)
1323

    
1324
        # if type(self) is QEngineeringSpecBreakItem:
1325
        #    self.currentPointModeIndex = 1
1326

    
1327
        return pointList[self.currentPointModeIndex]
1328

    
1329
    '''
1330
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
1331
        @author     kyouho
1332
        @date       18.08.06
1333
    '''
1334

    
1335
    def reCalculationRotatedItem(self):
1336

    
1337
        transform = QTransform()
1338
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1339
        transform.rotateRadians(-self.angle)
1340
        currentPoint = self.getCurrentPoint()
1341
        transform.translate(-currentPoint[0], -currentPoint[1])
1342
        # 시작점을 구하기 위해서
1343
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1344

    
1345
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1346

    
1347
    def resize(self, change):
1348
        """ resize item """
1349
        # Get the smaller side of the rect
1350
        rect = self.sceneBoundingRect()
1351
        loc = QPointF(rect.x(), rect.y())
1352
        self.resetTransform()
1353
        # self.setScale(1)
1354
        rect = self.sceneBoundingRect()
1355
        scale = [(change.width() - loc.x()) / rect.width(), (change.height() - loc.y()) / rect.height()]
1356
        # scale the item
1357
        if scale[0] > 0 and scale[1] > 0:
1358
            self.setPos(loc)
1359
            # self.setScale(scale[0] if scale[0] < scale[1] else scale[1])
1360
            trans = QTransform()
1361
            trans.scale(scale[0] if scale[0] < scale[1] else scale[1], scale[0] if scale[0] < scale[1] else scale[1])
1362
            self.setTransform(trans)
1363
            self.prepareGeometryChange()
1364
            self.update()
1365

    
1366
            self.transfer.on_size_changed.emit(self)
1367

    
1368
    def moveto(self, to, timeLine=5000, rotation=0):
1369
        """Move the item from one position to one other."""
1370

    
1371
        anim = QPropertyAnimation(self, b'pos')
1372
        rect = self.sceneBoundingRect()
1373
        anim.setStartValue(QPointF(0, 0))
1374
        anim.setEndValue(QPointF(100, 10))
1375
        anim.setDuration(10000)
1376
        anim.start()
1377

    
1378

    
1379
def recursiveChangeAttributes(node, attName, attValue):
1380
    while not node.isNull():
1381
        if node.isElement():
1382
            element = node.toElement()
1383
            if element.hasAttribute(attName):
1384
                element.setAttribute(attName, attValue)
1385

    
1386
            if node.hasChildNodes():
1387
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
1388

    
1389
        node = node.nextSibling()
1390

    
1391

    
1392
'''
1393
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1394
    @author     Jeongwoo
1395
    @date       2018.06.18
1396
'''
1397

    
1398

    
1399
class Transfer(QObject):
1400
    on_pos_changed = pyqtSignal(QGraphicsItem)
1401
    on_size_changed = pyqtSignal(QGraphicsItem)
1402
    onRemoved = pyqtSignal(QGraphicsItem)
1403

    
1404
    def __init__(self, parent=None):
1405
        QObject.__init__(self, parent)
1406

    
1407

    
1408
if __name__ == '__main__':
1409
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
1410
    f.open(QIODevice.ReadOnly)
1411
    array = f.readAll()
1412
    document = QDomDocument()
1413
    document.setContent(array)
1414

    
1415
    root = document.documentElement()
1416
    node = root.firstChild()
1417
    while not node.isNull():
1418
        if node.isElement():
1419
            element = node.toElement()
1420
            if element.hasAttribute('fill'):
1421
                element.setAttribute('fill', '#FFFFF')
1422

    
1423
            if element.hasChildNodes():
1424
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
1425

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