프로젝트

일반

사용자정보

통계
| 개정판:

hytos / HYTOS / HYTOS / Shapes / EngineeringConnectorItem.py @ 4aa060ea

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

1
# coding: utf-8
2
""" This is engineering connector item module """
3

    
4
import os.path
5
import copy, sys
6
try:
7
    from PyQt5.QtCore import *
8
    from PyQt5.QtGui import *
9
    from PyQt5.QtWidgets import *
10
except ImportError:
11
    try:
12
        from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR
13
        from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog
14
    except ImportError:
15
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
16

    
17
from EngineeringAbstractItem import QEngineeringAbstractItem
18

    
19
class NozzleData:
20
    """ this is nozzle data class """
21

    
22
    def __init__(self):
23
        """ constructor """
24
        self.pressure = None
25
        self.pressure_drop = None
26
        self.elevation = None
27
        self.over_design_cv = None
28

    
29
    def parse(self, row):
30
        """ parse given row """
31

    
32
        if row['Pressure']:
33
            self.pressure = float(row['Pressure'])
34
        if row['Pressure_Drop']:
35
            self.pressure_drop = float(row['Pressure_Drop'])
36
        if row['Elevation']:
37
            self.elevation = float(row['Elevation'])
38
        if row['Over_Design_CV']:
39
            self.over_design_cv = float(row['Over_Design_CV'])
40

    
41
"""
42
    A {ConnectorItem} is the graphical representation of a {Symbol.Connectors}.
43
"""
44
class QEngineeringConnectorItem(QGraphicsEllipseItem):
45
    """ This is engineering connector item class """
46
    SMALL_SIZE = 10
47
    BIG_SIZE = 16
48
    HIGHLIGHT = '#BC4438'
49

    
50
    AXIS_MODE = 0
51
    FREE_MODE = 1
52

    
53
    '''
54
        @brief  
55
        @author 
56
        @date   
57
        @history        humkyung 2018.07.27 add member for connectedItem
58
                        humkyung 2018.09.03 remove code to add connector item
59
    '''
60
    def __init__(self, uid=None, parent=None, index=-1):
61
        import uuid
62
        from SymbolSvgItem import SymbolSvgItem
63

    
64
        QGraphicsEllipseItem.__init__(self, parent)
65

    
66
        self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid, version=4)
67
        self.parent = parent
68
        self.buildItem()
69
        self._direction = 'AUTO'
70
        self._symbol_idx = '0'
71
        self._connectedItem = None
72
        self._connected_at = QEngineeringAbstractItem.CONNECTED_AT_PT      # default value is connected at pt
73
        self.connectPoint = None
74
        self._hoverItem = None
75
        self._data = None
76

    
77
        self.setAcceptHoverEvents(True)
78
        self.transfer = Transfer()
79

    
80
        self._drawing_mode = QEngineeringConnectorItem.AXIS_MODE
81

    
82
        if type(parent) is SymbolSvgItem:
83
            """ setup label for connector index """
84
            self._font = QFont('Arial', QEngineeringConnectorItem.SMALL_SIZE)
85
            self._font.setPointSizeF(5)
86

    
87
        self._conn_index = index
88

    
89
    def __repr__(self):
90
        """ return string represent parent item and connector index """
91
        return '{}_N{}'.format(self.parentItem().name, self._conn_index)
92

    
93
    @staticmethod
94
    def find_connector(uid):
95
        """ find a connector which has given uid """
96
        from App import App 
97
        import uuid
98

    
99
        res = None
100
        if type(uid) is uuid.UUID or type(uid) is str:
101
            scene = App.mainWnd().graphicsView.scene
102
            matches = [x for x in scene.items() if hasattr(x, 'uid') and str(x.uid) == str(uid)]
103
            res = matches[0] if matches else None
104

    
105
        return res
106

    
107
    @property
108
    def data(self):
109
        """ getter of nozzle data """
110
        return self._data
111

    
112
    @data.setter
113
    def data(self, value):
114
        """ setter of nozzle data """
115
        self._data = value
116

    
117
    @property
118
    def elevation(self):
119
        """ return elevation """
120
        return self.data.elevation
121

    
122
    @property
123
    def press_drop(self):
124
        return None
125

    
126
    @property
127
    def connectedItem(self):
128
        """ getter of connectedItem """
129
        import uuid
130

    
131
        if self.scene() and (type(self._connectedItem) is uuid.UUID or type(self._connectedItem) is str):
132
            matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._connectedItem)]
133
            if matches:
134
                self._connectedItem = matches[0]
135
            else:
136
                self._connectedItem = None
137

    
138
        return self._connectedItem
139
        
140
    @connectedItem.setter
141
    def connectedItem(self, value):
142
        """ setter of connectedItem """
143
        self._connectedItem = value
144

    
145
    '''
146
        @brief      getter of direction
147
        @author     humkyung
148
        @date       2018.09.01
149
    '''
150
    @property
151
    def direction(self):
152
        return self._direction
153

    
154
    '''
155
        @brief      setter of direction
156
        @author     humkyung
157
        @date       2018.09.01
158
    '''
159
    @direction.setter
160
    def direction(self, value):
161
        self._direction = value
162
    
163
    @property
164
    def symbol_idx(self):
165
        """ """
166
        return self._symbol_idx
167

    
168
    @symbol_idx.setter
169
    def symbol_idx(self, value):
170
        """ setter of symbol_idx """
171
        self._symbol_idx = value
172

    
173
    @property
174
    def spec_break(self):
175
        """ getter of spec break """
176
        return self._spec_break
177

    
178
    '''
179
        @brief      return direction vector
180
        @author     humkyung
181
        @date       2018.09.01
182
    '''
183
    def dir(self):
184
        if self._direction == 'LEFT':
185
            return (-1, 0)
186
        elif self._direction == 'RIGHT':
187
            return (1, 0)
188
        elif self._direction == 'UP':
189
            return (0, -1)
190
        elif self._direction == 'DOWN':
191
            return (0, 1)
192

    
193
        return None
194

    
195
    '''
196
        @brief  build connector item
197
        @author humkyung
198
        @date   2018.05.02
199
    '''
200
    def buildItem(self):
201
        color = Qt.blue
202
        self.setBrush(color)
203
        if self.parent is not None:
204
            self.setZValue(self.parent.zValue() + 1)
205

    
206
    '''
207
        @brief      return center of connector
208
        @author     humkyung
209
        @date       2018.07.23
210
    '''
211
    def center(self):
212
        pt = self.sceneBoundingRect().center()
213
        return (pt.x(), pt.y())
214
        
215
    '''
216
        @brief  set position of connector
217
        @author humkyung
218
        @date   2018.05.02
219
    '''
220
    def setPos(self, pos):
221
        self._loc = [pos[0], pos[1]] 
222
        self.setRect(self._loc[0] - round(self.SMALL_SIZE*0.5), self._loc[1] - round(self.SMALL_SIZE*0.5), self.SMALL_SIZE, self.SMALL_SIZE)
223
        self.update()
224

    
225
        if hasattr(self, '_label'):
226
            """ set label positon at center of connector """
227
            self._label.setPos(QPointF(self._loc[0] - self._label.boundingRect().width()*0.5, self._loc[1] - self._label.boundingRect().height()*0.5))
228
    
229
    def connect(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
230
        """ connect to given item where given position """
231

    
232
        if item:
233
            self.connectedItem = item
234
            self._connected_at = at
235
        else:
236
            self.connectedItem = None
237

    
238
        self.setBrush(Qt.yellow) if self.connectedItem else self.setBrush(Qt.blue)
239

    
240
    '''
241
        @brief  highlight connector
242
        @authro humkyung
243
        @date   2018.05.09
244
    '''
245
    def hoverEnterEvent(self, event):
246
        try:
247
            self.highlight(True)
248
        finally:
249
            QApplication.setOverrideCursor(Qt.CrossCursor)
250

    
251
    '''
252
        @brief  unhighlight connector
253
        @author humkyung
254
        @date   2018.05.09
255
    '''
256
    def hoverLeaveEvent(self, event):
257
        try:
258
            self.highlight(False)
259
        finally:
260
            QApplication.restoreOverrideCursor()
261

    
262
    def highlight(self, flag):
263
        if flag:
264
            self.setRect(self._loc[0] - round(self.BIG_SIZE*0.5), self._loc[1] - round(self.BIG_SIZE*0.5), self.BIG_SIZE, self.BIG_SIZE)
265
            c = QColor()
266
            c.setNamedColor(QEngineeringConnectorItem.HIGHLIGHT)
267
            self.setPen(Qt.red)
268
            self.setBrush(c)
269
            if hasattr(self, '_label'):
270
                font = self._label.font()
271
                font.setBold(True)
272
                self._label.setFont(font)
273
        else:
274
            self.setRect(self._loc[0] - round(self.SMALL_SIZE*0.5), self._loc[1] - round(self.SMALL_SIZE*0.5), self.SMALL_SIZE, self.SMALL_SIZE)
275
            self.setPen(Qt.black)
276
            self.setBrush(Qt.yellow) if self.connectedItem else self.setBrush(Qt.blue)
277
            if hasattr(self, '_label'):
278
                font = self._label.font()
279
                font.setBold(False)
280
                self._label.setFont(font)
281

    
282
        if self.parentItem(): self.setZValue(self.parentItem().zValue() + 1)
283
        if self.scene() and self.scene().sceneRect().contains(self.sceneBoundingRect()):
284
            self.update()
285
            if self.scene(): self.scene().update()
286

    
287
    '''
288
        @brief      
289
        @author     humkyung
290
        @date       2018.07.27
291
    '''
292
    def mousePressEvent(self, event):
293
        if self.parentItem() is not None:
294
            if event.buttons() == Qt.LeftButton:
295
                self._savedPos = self._loc
296
                self._savedConnectedItem = self.connectedItem
297
                
298
        QGraphicsEllipseItem.mousePressEvent(self, event)
299

    
300
    '''
301
        @brief      
302
        @author     humkyung
303
        @date       2018.07.27
304
        @history    humkyung 2018.08.23 unhighlight item if underitem exists
305
    '''
306
    def mouseReleaseEvent(self, event):
307
        import shapely
308
        from SymbolSvgItem import SymbolSvgItem
309
        from EngineeringArrowItem import QEngineeringArrowItem
310
        from EngineeringTextItem import QEngineeringTextItem
311

    
312
        try:            
313
            if self.parentItem() is not None and self._savedPos is not None:
314
                items = [item for item in self.scene().items(event.scenePos()) if item is not self and item is not self.parentItem() and \
315
                    (issubclass(type(item), SymbolSvgItem) or issubclass(type(item), QEngineeringTextItem) or type(item) is QEngineeringConnectorItem)]
316

    
317
                if items and type(items[0]) is QEngineeringConnectorItem:
318
                    self.setPos(items[0].center())
319
                    
320
                    """ disconnect alreay connected item """
321
                    if self.connectedItem is not None:
322
                        self.connectedItem.connect(None)
323

    
324
                    """ connect each other """
325
                    self.connect(items[0])
326
                    items[0].connect(self)
327
                else:
328
                    pt = [event.scenePos().x(), event.scenePos().y()]
329
                    
330
                    self.setPos(pt)
331
                    if self.connectedItem is not None:
332
                        self.connectedItem.connect(None)
333

    
334
                    self.connect(None)
335

    
336
                ## unhighlight underitem
337
                if hasattr(self, '_underItem') and self._underItem is not None:
338
                    self._underItem.highlight(False)
339
                ## up to here
340

    
341
                for symbol in [self.parentItem() for self in items if type(self.parentItem()) is SymbolSvgItem]:
342
                    symbol.transfer.on_pos_changed.connect(self.parent.on_symbol_pos_changed)
343

    
344
            if self.parentItem() is not None:
345
                self._savedPos = None 
346
                self._savedConnectedItem = None
347
                self.transfer.onPosChanged.emit(self)                
348
        finally:
349
            #self.ungrabKeyboard()
350
            pass
351

    
352
        QGraphicsEllipseItem.mouseReleaseEvent(self, event)
353

    
354
    '''
355
        @brief      move connector's position while mouse drag
356
        @author     humkyung
357
        @date       2018.07.27
358
        @history    humkyung 2018.08.23 hightlight underitem
359
    '''
360
    def mouseMoveEvent(self, event):
361
        import shapely
362
        from SymbolSvgItem import SymbolSvgItem
363
        from EngineeringArrowItem import QEngineeringArrowItem
364
        from EngineeringTextItem import QEngineeringTextItem
365

    
366
        if self.parentItem() is not None and self._savedPos is not None:
367
            if event.buttons() == Qt.LeftButton:
368
                items = [item for item in self.scene().items(event.scenePos()) if item is not self and item is not self.parent and \
369
                    (issubclass(type(item), SymbolSvgItem) or issubclass(type(item), QEngineeringTextItem) or type(item) is QEngineeringConnectorItem)]
370
                ## highlight underitem
371
                if len(items) > 0:
372
                    if not hasattr(self, '_underItem') or self._underItem is not items[0]:
373
                        if hasattr(self, '_underItem') and self._underItem is not None:
374
                            self._underItem.highlight(False)
375

    
376
                        self._underItem = items[0]
377
                        self._underItem.highlight(True)
378
                elif hasattr(self, '_underItem') and self._underItem is not None:
379
                    self._underItem.hoverLeaveEvent(event)
380
                    self._underItem = None
381
                ## up to here
382

    
383
                if items and type(items[0]) is QEngineeringConnectorItem:
384
                    self.setPos(items[0].center())
385
                else:
386
                    pt = [event.scenePos().x(), event.scenePos().y()]
387
                    
388
                    self.setPos(pt)
389

    
390
                self.update()
391

    
392
        QGraphicsEllipseItem.mouseMoveEvent(self, event)
393

    
394

    
395
    def hasConnectedItem(self):
396
        if self.connectedItem is not None:
397
            return True
398
        
399
        return False
400
    '''
401
        @brief      reject if user press Escape key
402
        @author     humkyung
403
        @date       2018.07.27
404
    '''
405
    def keyPressEvent(self, event):
406
        if event.key() == Qt.Key_Escape:
407
            if hasattr(self, '_savedPos') and self._savedPos is not None:
408
                self.setPos(self._savedPos)
409
                self.connectedItem = self._savedConnectedItem
410
                self._savedPos = None
411
                self.update()
412
        elif event.key() == Qt.Key_A:
413
            self._drawing_mode = QEngineeringConnectorItem.AXIS_MODE
414
        elif event.key() == Qt.Key_F:
415
            self._drawing_mode = QEngineeringConnectorItem.FREE_MODE
416

    
417
        QGraphicsEllipseItem.keyPressEvent(self, event)
418

    
419
    '''
420
        @brief  override paint(draw connection points)
421
        @author humkyung
422
        @date   2018.04.21
423
    '''
424
    def paint(self, painter, options=None, widget=None):
425
        from SymbolSvgItem import SymbolSvgItem
426

    
427
        QGraphicsEllipseItem.paint(self, painter, options, widget)
428
        if type(self.parentItem()) is SymbolSvgItem:
429
            painter.setFont(self._font)
430
            painter.drawText(self.boundingRect(), str(self._conn_index), QTextOption(Qt.AlignCenter))
431

    
432
    '''
433
        @brief      check Overlap
434
        @author     kyouho
435
        @date       2018.08.30
436
    '''
437
    def isOverlapConnector(self, conn, toler = 10):
438
        from shapely.geometry import Point
439

    
440
        x1 = self.center()[0]
441
        y1 = self.center()[1]
442
        x2 = conn.center()[0]
443
        y2 = conn.center()[1]
444

    
445
        if Point(x1, y1).distance(Point(x2, y2)) < toler:
446
            return True
447
        else:
448
            return False
449

    
450
    def parse_xml(self, node):
451
        """ parse given node """
452
        import uuid
453

    
454
        try:
455
            if 'UID' in node.attrib: self.uid = uuid.UUID(node.attrib['UID'], version=4)
456

    
457
            if 'CONNECTED_AT' in node.attrib:
458
                self._connected_at = QEngineeringAbstractItem.CONNECTED_AT_PT if node.attrib['CONNECTED_AT'] == '0' else QEngineeringAbstractItem.CONNECTED_AT_BODY
459
            else:
460
                self._connected_at = QEngineeringAbstractItem.CONNECTED_AT_PT
461

    
462
            connectedItemStr = node.find('CONNECTEDITEM').text
463
            connectPointStr = node.find('CONNECTPOINT').text.split(',')
464
            sceneConnectPointStr = node.find('SCENECONNECTPOINT').text.split(',')
465

    
466
            self._connectedItem = uuid.UUID(connectedItemStr, version=4) if connectedItemStr != 'None' else None
467
            self.connectPoint = (float(connectPointStr[0]), float(connectPointStr[1]))
468
            self.sceneConnectPoint = (float(sceneConnectPointStr[0]), float(sceneConnectPointStr[1]))
469

    
470
            self.setBrush(Qt.yellow) if self._connectedItem else self.setBrush(Qt.blue)
471
        except Exception as ex:
472
            from App import App 
473
            from AppDocData import MessageType
474

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

    
478
    def toSql(self, index):
479
        """ generate sql string to save connectors to database """
480
        res = []
481

    
482
        cols = ['UID', 'Components_UID', '[Index]', 'X', 'Y']
483
        values = ['?', '?', '?', '?', '?']
484
       
485
        param = [str(self.uid), str(self.parent.uid), index, self.center()[0], self.center()[1]]        
486
        sql = 'insert or replace into Points({}) values({})'.format(','.join(cols), ','.join(values))
487
        res.append((sql, tuple(param)))
488

    
489
        cols = ['Points_UID', 'Pressure', 'Pressure_Drop', 'Elevation', 'Over_Design_CV']
490
        values = ['?', '?', '?', '?', '?']
491
        if self.data:
492

    
493
            pressure = self.data.pressure
494
            if pressure is None:
495
                pressure = None
496
            else:
497
                pressure = float(pressure)
498

    
499
            pressure_drop = self.data.pressure_drop
500
            if pressure_drop is None:
501
                pressure_drop = None
502
            else:
503
                pressure_drop = float(pressure_drop)
504

    
505
            elevation = self.data.elevation
506
            if elevation is None:
507
                elevation = None
508
            else:
509
                elevation = float(elevation)
510

    
511
            over_design_cv = self.data.over_design_cv
512
            if over_design_cv is None:
513
                over_design_cv = None
514
            else:
515
                over_design_cv = float(over_design_cv)
516

    
517

    
518
            param = [str(self.uid), pressure, pressure_drop, elevation, over_design_cv]
519
            sql = 'insert or replace into Nozzles({}) values({})'.format(','.join(cols), ','.join(values))
520
            res.append((sql, tuple(param)))
521

    
522
        return res
523

    
524
'''
525
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
526
    @author     Jeongwoo
527
    @date       2018.06.18
528
'''
529
class Transfer(QObject):
530
    onPosChanged = pyqtSignal(QGraphicsItem)
531
    onRemoved = pyqtSignal(QGraphicsItem)
532

    
533
    def __init__(self, parent = None):
534
        QObject.__init__(self, parent)
클립보드 이미지 추가 (최대 크기: 500 MB)