hytos / HYTOS / HYTOS / Shapes / SymbolSvgItem.py @ 62fd5ea0
이력 | 보기 | 이력해설 | 다운로드 (48.8 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 EngineeringConnectorItem import QEngineeringConnectorItem |
16 |
from EngineeringAbstractItem import QEngineeringAbstractItem |
17 |
from EngineeringConnectorItem import QEngineeringConnectorItem |
18 |
from UserInputAttribute import UserInputAttribute |
19 |
from Resizer import Resizer |
20 |
|
21 |
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem): |
22 |
""" This is symbolsvgitem class """
|
23 |
|
24 |
clicked = pyqtSignal(QGraphicsSvgItem) |
25 |
ZVALUE = 50
|
26 |
HOVER_COLOR = 'url(#hover)'
|
27 |
|
28 |
'''
|
29 |
@history 18.04.11 Jeongwoo Add Variable (Name, Type)
|
30 |
18.05.11 Jeongwoo Declare variable self.color
|
31 |
18.05.25 Jeongwoo Call setColor() method
|
32 |
18.05.30 Jeongwoo Add self variables (parentSymbol, childSymbol)
|
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(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable|QGraphicsItem.ItemIsMovable|QGraphicsItem.ItemSendsGeometryChanges)
|
42 |
|
43 |
self.dbUid = None |
44 |
self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid, version=4) |
45 |
self.name = '' |
46 |
self.category = '' |
47 |
self.type = '' |
48 |
self.angle = 0 |
49 |
self._scale = 1 |
50 |
self.origin = None |
51 |
self.loc = None |
52 |
self.size = None |
53 |
self._owner = None |
54 |
self.parentSymbol = '' |
55 |
self.childSymbol = '' |
56 |
self.hasInstrumentLabel = 0 |
57 |
self.flip = flip
|
58 |
# attributeType uid
|
59 |
self.attribute = '' |
60 |
self._properties = {SymbolProp(None, 'Supplied By', 'String'):None} |
61 |
|
62 |
self.setAcceptDrops(True) |
63 |
self.setAcceptHoverEvents(True) |
64 |
self.setAcceptedMouseButtons(Qt.LeftButton)
|
65 |
self.setAcceptTouchEvents(True) |
66 |
|
67 |
self.currentCursor = 0 |
68 |
self.transfer = Transfer()
|
69 |
|
70 |
try:
|
71 |
f = QFile(path) |
72 |
f.open(QIODevice.ReadOnly) |
73 |
array = f.readAll() |
74 |
self._document = QDomDocument()
|
75 |
self._document.setContent(array)
|
76 |
self._renderer = QSvgRenderer(self._document.toByteArray()) |
77 |
self.setSharedRenderer(self._renderer) |
78 |
|
79 |
self._color = self.get_attribute('fill') |
80 |
except Exception as ex: |
81 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
82 |
finally:
|
83 |
f.close() |
84 |
|
85 |
self.setZValue(SymbolSvgItem.ZVALUE)
|
86 |
|
87 |
def __str__(self): |
88 |
""" return string represent uuid """
|
89 |
return str(self.uid) |
90 |
|
91 |
'''
|
92 |
@breif getter owner
|
93 |
@author humkyung
|
94 |
@date 2018.05.10
|
95 |
'''
|
96 |
@property
|
97 |
def owner(self): |
98 |
import uuid |
99 |
|
100 |
if self._owner and type(self._owner) is uuid.UUID: |
101 |
matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._owner)] |
102 |
if matches: self._owner = matches[0] |
103 |
|
104 |
if type(self._owner) is not uuid.UUID and type(self._owner) is not str: |
105 |
return self._owner |
106 |
else:
|
107 |
self._owner = None |
108 |
return None |
109 |
|
110 |
'''
|
111 |
@brief setter owner
|
112 |
@author humkyung
|
113 |
@date 2018.05.10
|
114 |
@history 2018.05.17 Jeongwoo Add Calling setColor if self._owner is None or not
|
115 |
'''
|
116 |
@owner.setter
|
117 |
def owner(self, value): |
118 |
self._owner = value
|
119 |
|
120 |
if self._owner is None: |
121 |
self._color = self.DEFAULT_COLOR |
122 |
self.setColor(self._color) |
123 |
|
124 |
@property
|
125 |
def properties(self): |
126 |
""" getter of properties """
|
127 |
import uuid |
128 |
|
129 |
for prop,value in self._properties.items(): |
130 |
try:
|
131 |
if prop.is_selectable and type(value) is uuid.UUID and self.scene(): |
132 |
matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)] |
133 |
if matches: self._properties[prop] = matches[0] |
134 |
|
135 |
if prop.Expression:
|
136 |
item = self._properties[prop] # assign item |
137 |
self._properties[prop] = eval(prop.Expression) |
138 |
except Exception as ex: |
139 |
from App import App |
140 |
|
141 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
142 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
143 |
|
144 |
return self._properties |
145 |
|
146 |
@properties.setter
|
147 |
def properties(self, value): |
148 |
""" setter of properties """
|
149 |
self._properties = value
|
150 |
|
151 |
def set_property(self, property, value): |
152 |
""" set property with given value """
|
153 |
if issubclass(type(value), QEngineeringAbstractItem): self.add_assoc_item(value, 0) |
154 |
matches = [prop for prop,_ in self._properties.items() if prop.Attribute == property] |
155 |
if matches: self._properties[matches[0]] = value |
156 |
|
157 |
def prop(self, name): |
158 |
""" return the value of given property with name """
|
159 |
matches = [(prop,value) for prop,value in self.properties.items() if prop.Attribute == name] |
160 |
if matches: return matches[0][1] |
161 |
|
162 |
return None |
163 |
|
164 |
@property
|
165 |
def Size(self): |
166 |
""" return valve's size """
|
167 |
from QEngineeringSizeTextItem import QEngineeringSizeTextItem |
168 |
|
169 |
matches = [assoc for assoc in self.associations() if type(assoc) is QEngineeringSizeTextItem] |
170 |
if matches:
|
171 |
return matches[0].text() |
172 |
else:
|
173 |
return None |
174 |
|
175 |
def includes(self, pt, margin=0): |
176 |
""" return True if symbol contains given point else return False """
|
177 |
rect = self.sceneBoundingRect()
|
178 |
allowed_error = 0.1
|
179 |
|
180 |
if abs(rect.x() - 0) <= allowed_error and abs(rect.y() - 0) <= allowed_error: |
181 |
# when first recognition step, symbols are not in scene(not yet added) therefore cannot use scenebounding rect
|
182 |
minX = self.loc[0] - margin |
183 |
minY = self.loc[1] - margin |
184 |
maxX = minX + self.size[0] + margin |
185 |
maxY = minY + self.size[1] + margin |
186 |
else:
|
187 |
minX = rect.x() - margin |
188 |
minY = rect.y() - margin |
189 |
maxX = minX + rect.width() + margin |
190 |
maxY = minY + rect.height() + margin |
191 |
|
192 |
#print([minX, minY, maxX, maxY])
|
193 |
|
194 |
return True if (pt[0] >= minX and pt[0] <= maxX and pt[1] >= minY and pt[1] <= maxY) else False |
195 |
|
196 |
def toSql(self): |
197 |
""" convert valve data to sql query """
|
198 |
import uuid |
199 |
from AppDocData import AppDocData |
200 |
|
201 |
res = [] |
202 |
appDocData = AppDocData.instance() |
203 |
|
204 |
rect = self.sceneBoundingRect()
|
205 |
|
206 |
cols = ['UID', 'Drawings_UID', 'Symbols_UID', 'X', 'Y', 'Rotation', 'Scale'] |
207 |
values = ['?','?','?', '?', '?', '?', '?'] |
208 |
param = [str(self.uid), str(appDocData.activeDrawing.UID), str(self.dbUid), rect.left(), rect.top(), str(self.angle), self.transform().m11()] |
209 |
sql = 'insert or replace into Components({}) values({})'.format(','.join(cols), ','.join(values)) |
210 |
res.append((sql, tuple(param)))
|
211 |
|
212 |
# save connectors to database
|
213 |
index = 1
|
214 |
for connector in self.connectors: |
215 |
res.extend(connector.toSql(index)) |
216 |
index += 1
|
217 |
# up to here
|
218 |
|
219 |
return res
|
220 |
|
221 |
'''
|
222 |
@brief build symbol item
|
223 |
@author humkyung
|
224 |
@date 2018.05.02
|
225 |
@history 2018.05.09 Jeongwoo Clear self.connectors
|
226 |
2018.05.30 Jeongwoo Add parameters (parentSymbol, childSymbol)
|
227 |
'''
|
228 |
def buildItem(self, name, _type, angle, scale, loc, origin, connPts, dbUid=None, pointsUids=None): |
229 |
try:
|
230 |
self.name = name
|
231 |
self.type = _type
|
232 |
self.angle = angle
|
233 |
self._scale = scale
|
234 |
self.loc = loc
|
235 |
|
236 |
docData = AppDocData.instance() |
237 |
if dbUid is None: |
238 |
symbolInfo = docData.getSymbolByQuery('name', name)
|
239 |
else:
|
240 |
symbolInfo = docData.getSymbolByQuery('UID', dbUid)
|
241 |
|
242 |
self.dbUid = symbolInfo.uid
|
243 |
self.category = symbolInfo.sCategory
|
244 |
originalPoint = symbolInfo.getOriginalPoint().split(',')
|
245 |
self.symbolOrigin = [float(originalPoint[0]), float(originalPoint[1])] |
246 |
|
247 |
# setting connectors
|
248 |
connectionPoints = symbolInfo.getConnectionPoint().split('/')
|
249 |
for index in range(len(connectionPoints)): |
250 |
if connectionPoints[index] == '': |
251 |
break
|
252 |
tokens = connectionPoints[index].split(',')
|
253 |
|
254 |
direction = 'AUTO'
|
255 |
symbol_idx = '0'
|
256 |
|
257 |
if len(tokens) == 2: |
258 |
x = float(tokens[0]) |
259 |
y = float(tokens[1]) |
260 |
elif len(tokens) == 3: |
261 |
direction = tokens[0]
|
262 |
x = float(tokens[1]) |
263 |
y = float(tokens[2]) |
264 |
elif len(tokens) == 4: |
265 |
direction = tokens[0]
|
266 |
x = float(tokens[1]) |
267 |
y = float(tokens[2]) |
268 |
symbol_idx = tokens[3]
|
269 |
|
270 |
if pointsUids:
|
271 |
self.setConnector(pointsUids[index], index+1) |
272 |
else:
|
273 |
self.setConnector(None, index+1) |
274 |
|
275 |
self.connectors[index].direction = direction
|
276 |
self.connectors[index].symbol_idx = symbol_idx
|
277 |
self.connectors[index].setPos((x, y))
|
278 |
self.connectors[index].connectPoint = (x, y)
|
279 |
|
280 |
|
281 |
tooltip = '<b>{}</b><br>{}={}'.format(str(self.uid), self.type, self.name) |
282 |
self.setToolTip(tooltip)
|
283 |
except Exception as ex: |
284 |
from App import App |
285 |
|
286 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
287 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
288 |
|
289 |
'''
|
290 |
@brief return bounding box of symbol
|
291 |
@author humkyung
|
292 |
@date 2018.04.08
|
293 |
'''
|
294 |
def rect(self): |
295 |
return self.sceneBoundingRect() |
296 |
|
297 |
'''
|
298 |
@brief return true if line is able to connect symbol
|
299 |
@author humkyung
|
300 |
@date 2018.04.13
|
301 |
'''
|
302 |
def is_connectable(self, item, toler=10): |
303 |
#from EngineeringLineItem import QEngineeringLineItem
|
304 |
|
305 |
'''
|
306 |
if False:#type(item) is QEngineeringLineItem:
|
307 |
line = item
|
308 |
start_pt = line.startPoint()
|
309 |
end_pt = line.endPoint()
|
310 |
for connector in self.connectors:
|
311 |
dx = connector.sceneConnectPoint[0] - (start_pt[0])
|
312 |
dy = connector.sceneConnectPoint[1] - (start_pt[1])
|
313 |
if (math.sqrt(dx*dx + dy*dy) < toler): return True
|
314 |
dx = connector.sceneConnectPoint[0] - (end_pt[0])
|
315 |
dy = connector.sceneConnectPoint[1] - (end_pt[1])
|
316 |
if (math.sqrt(dx*dx + dy*dy) < toler): return True
|
317 |
elif True:#issubclass(type(item), SymbolSvgItem):
|
318 |
'''
|
319 |
for connector in self.connectors: |
320 |
for iConnector in item.connectors: |
321 |
dx = connector.sceneConnectPoint[0] - iConnector.sceneConnectPoint[0] |
322 |
dy = connector.sceneConnectPoint[1] - iConnector.sceneConnectPoint[1] |
323 |
if (math.sqrt(dx*dx + dy*dy) < toler): return True |
324 |
|
325 |
return False |
326 |
|
327 |
'''
|
328 |
@author humkyung
|
329 |
@date 2018.07.03
|
330 |
'''
|
331 |
def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT): |
332 |
""" check if given item is connected to self """
|
333 |
|
334 |
_connectors = [connector for connector in self.connectors if (connector.connectedItem == item and (connector._connected_at == at if at else True))] |
335 |
return len(_connectors) > 0 |
336 |
|
337 |
def next_connected(self, lhs, rhs): |
338 |
""" check given two item's are next connected(ex: 0-1, 2-3) """
|
339 |
|
340 |
lhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == lhs] |
341 |
rhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == rhs] |
342 |
if lhs_matches and rhs_matches: |
343 |
return (lhs_matches[0] in [0,1] and rhs_matches[0] in [0,1]) or (lhs_matches[0] in [2,3] and rhs_matches[0] in [2,3]) |
344 |
|
345 |
return False |
346 |
|
347 |
'''
|
348 |
@brief connect line and symbol is able to be connected and return line
|
349 |
@author humkyung
|
350 |
@date 2018.04.16
|
351 |
@history humkyung 2018.05.08 check if symbol is possible to be connected
|
352 |
Jeongwoo 2018.05.15 Connect each symbol and line
|
353 |
'''
|
354 |
def connect_if_possible(self, obj, toler=10): |
355 |
from shapely.geometry import Point |
356 |
from EngineeringLineItem import QEngineeringLineItem |
357 |
|
358 |
res = [] |
359 |
try:
|
360 |
if type(obj) is QEngineeringLineItem: |
361 |
startPt = obj.startPoint() |
362 |
endPt = obj.endPoint() |
363 |
for i in range(len(self.connectors)): |
364 |
if (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler): |
365 |
if self.connectors[i].connectedItem is None: |
366 |
self.connectors[i].connect(obj)
|
367 |
if obj.connectors[0].connectedItem is None: |
368 |
obj.connectors[0].connect(self) |
369 |
|
370 |
res.append(obj) |
371 |
if (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler): |
372 |
if self.connectors[i].connectedItem is None: |
373 |
self.connectors[i].connect(obj)
|
374 |
if obj.connectors[1].connectedItem is None: |
375 |
obj.connectors[1].connect(self) |
376 |
|
377 |
res.append(obj) |
378 |
elif issubclass(type(obj), SymbolSvgItem): |
379 |
for i in range(len(self.connectors)): |
380 |
for j in range(len(obj.connectors)): |
381 |
_pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1]) |
382 |
if (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler): |
383 |
if self.connectors[i].connectedItem is None: |
384 |
self.connectors[i].connect(obj)
|
385 |
if obj.connectors[j].connectedItem is None: |
386 |
obj.connectors[j].connect(self)
|
387 |
|
388 |
res.append(obj) |
389 |
except Exception as ex: |
390 |
from App import App |
391 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
392 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
393 |
|
394 |
return res
|
395 |
|
396 |
'''
|
397 |
@brief disconnect connector item
|
398 |
@author kyouho
|
399 |
@date 2018.08.30
|
400 |
'''
|
401 |
def disconnectedItemAtConnector(self, connector): |
402 |
for conn in self.connectors: |
403 |
if conn.isOverlapConnector(connector):
|
404 |
conn.connectedItem = None
|
405 |
|
406 |
'''
|
407 |
@brief get connection point close to given point in tolerance
|
408 |
@author humkyung
|
409 |
@dat
|
410 |
'''
|
411 |
def getConnectionPointCloseTo(self, pt, toler=10): |
412 |
import math |
413 |
|
414 |
for connector in self.connectors: |
415 |
dx = connector.sceneConnectPoint[0] - pt[0] |
416 |
dy = connector.sceneConnectPoint[1] - pt[1] |
417 |
if math.sqrt(dx*dx + dy*dy) < toler: return connPt |
418 |
|
419 |
return None |
420 |
|
421 |
'''
|
422 |
@brief return center of symbol
|
423 |
@author humkyung
|
424 |
@date 2018.04.08
|
425 |
'''
|
426 |
def center(self): |
427 |
return self.sceneBoundingRect().center() |
428 |
|
429 |
'''
|
430 |
@brief highlight connector and attribute
|
431 |
@authro humkyung
|
432 |
@date 2018.05.02
|
433 |
'''
|
434 |
def hoverEnterEvent(self, event): |
435 |
from Resizer import Resizer |
436 |
|
437 |
self.highlight(True) |
438 |
|
439 |
""" create a resizer """
|
440 |
resizer = Resizer.instance() |
441 |
resizer.connected = self
|
442 |
resizerWidth = resizer.rect.width() / 2
|
443 |
rect = self.sceneBoundingRect()
|
444 |
resizerOffset = QPointF(resizerWidth, resizerWidth) |
445 |
resizer.setPos(rect.bottomRight() - resizerOffset) |
446 |
if resizer.receivers(resizer.resizeSignal) > 0: resizer.resizeSignal.disconnect() |
447 |
resizer.resizeSignal.connect(self.resize)
|
448 |
try:
|
449 |
self.transfer.on_pos_changed.disconnect(resizer.on_symbol_pos_changed)
|
450 |
except Exception as ex: |
451 |
pass
|
452 |
self.transfer.on_pos_changed.connect(resizer.on_symbol_pos_changed)
|
453 |
resizer.setVisible(True)
|
454 |
if not resizer.scene(): self.scene().addItem(resizer) |
455 |
|
456 |
'''
|
457 |
@brief unhighlight connector and attribute
|
458 |
@author humkyung
|
459 |
@date 2018.05.02
|
460 |
@history kyouho 2018.07.18 edit ArrowCursor
|
461 |
'''
|
462 |
def hoverLeaveEvent(self, event): |
463 |
self.highlight(False) |
464 |
|
465 |
def highlight(self, flag): |
466 |
""" highlight/unhighlight the symbol """
|
467 |
|
468 |
try:
|
469 |
self.hover = flag
|
470 |
self.setZValue(QEngineeringAbstractItem.HOVER_ZVALUE) if flag else self.setZValue(SymbolSvgItem.ZVALUE) |
471 |
self.update()
|
472 |
|
473 |
#for assoc in self.associations():
|
474 |
# assoc.highlight(flag)
|
475 |
except Exception as ex: |
476 |
from App import App |
477 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
478 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
479 |
|
480 |
'''
|
481 |
@brief set highlight
|
482 |
@author kyouho
|
483 |
@date 2018.08.27
|
484 |
'''
|
485 |
def setHightlight(self): |
486 |
self.setColor('url(#hover)') |
487 |
self.update()
|
488 |
|
489 |
'''
|
490 |
@brief unset highlight
|
491 |
@author kyouho
|
492 |
@date 2018.08.27
|
493 |
'''
|
494 |
def unsetHightlight(self): |
495 |
self.setColor('url(#normal)') |
496 |
self.update()
|
497 |
|
498 |
'''
|
499 |
@brief change cursor to CrossCursor if mouse point is close to connection point
|
500 |
@author humkyung
|
501 |
@date 2018.04.28
|
502 |
'''
|
503 |
def hoverMoveEvent(self, event): |
504 |
pass
|
505 |
|
506 |
'''
|
507 |
@brief Mouse Press Event
|
508 |
@author Jeongwoo
|
509 |
@date 18.04.11
|
510 |
@history kyouho 2018.07.18 add isClick logic
|
511 |
'''
|
512 |
def mousePressEvent(self, event): |
513 |
if event.buttons() == Qt.LeftButton:
|
514 |
self.clicked.emit(self) |
515 |
|
516 |
'''
|
517 |
@brief call on_pos_changed signal
|
518 |
@author humkyung
|
519 |
@date 19.07.17
|
520 |
'''
|
521 |
def mouseReleaseEvent(self, event): |
522 |
super().mouseReleaseEvent(event)
|
523 |
|
524 |
def itemChange(self, change, value): |
525 |
""" call signals when item's position is changed """
|
526 |
if change == QGraphicsItem.ItemPositionHasChanged:
|
527 |
self.transfer.on_pos_changed.emit(self) |
528 |
return value
|
529 |
|
530 |
return super().itemChange(change, value) |
531 |
|
532 |
def removeSelfAttr(self, attributeName): |
533 |
target = None
|
534 |
for attr in self.attrs: |
535 |
if attr.Attribute == attributeName:
|
536 |
target = attr |
537 |
break
|
538 |
|
539 |
if target:
|
540 |
del self.attrs[attr] |
541 |
|
542 |
'''
|
543 |
@brief Check Overlap
|
544 |
@author kyouho
|
545 |
@date 18.07.17
|
546 |
'''
|
547 |
def isOverlapItemAndPoint(self, item, point): |
548 |
x = point.x() |
549 |
y = point.y() |
550 |
loc = item.loc |
551 |
size = item.size |
552 |
|
553 |
if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y: |
554 |
return True |
555 |
else:
|
556 |
return False |
557 |
|
558 |
'''
|
559 |
@brief remove item when user press delete key
|
560 |
@author humkyung
|
561 |
@date 2018.04.23
|
562 |
@history 2018.05.17 Jeongwoo Add if-statement and move 'break'
|
563 |
2018.05.25 Jeongwoo Seperate delete item method
|
564 |
'''
|
565 |
def keyPressEvent(self, event): |
566 |
if not self.isSelected(): return |
567 |
|
568 |
if event.key() == Qt.Key_Delete:
|
569 |
self.deleteSvgItemFromScene()
|
570 |
elif event.key() == Qt.Key_QuoteLeft:
|
571 |
self.mouseDoubleClickEvent(event)
|
572 |
|
573 |
|
574 |
'''
|
575 |
@brief connect attribute
|
576 |
@author humkyung
|
577 |
@date 2018.05.02
|
578 |
@history humkyung 2018.05.09 append only nearest size attribute
|
579 |
'''
|
580 |
def connectAttribute(self, attributes, clear=True): |
581 |
import math |
582 |
from EngineeringTextItem import QEngineeringTextItem |
583 |
from QEngineeringSizeTextItem import QEngineeringSizeTextItem |
584 |
from EngineeringInstrumentItem import QEngineeringInstrumentItem |
585 |
from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem |
586 |
|
587 |
try:
|
588 |
if clear:
|
589 |
self.clear_attr_and_assoc_item()
|
590 |
|
591 |
configs = AppDocData.instance().getConfigs('Range', 'Detection Ratio') |
592 |
ratio = float(configs[0].value) if 1 == len(configs) else 1.5 |
593 |
|
594 |
dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width()) * ratio |
595 |
center = self.sceneBoundingRect().center()
|
596 |
|
597 |
minDist = None
|
598 |
selected = None
|
599 |
for attr in attributes: |
600 |
# size text and operation code text will find onwer themselves in findowner method
|
601 |
if False:# type(attr) is QEngineeringSizeTextItem or type(attr) is QEngineeringValveOperCodeTextItem: |
602 |
dx = attr.center().x() - center.x() |
603 |
dy = attr.center().y() - center.y() |
604 |
length = math.sqrt(dx*dx + dy*dy) |
605 |
if (length < dist) and (minDist is None or length < minDist): |
606 |
minDist = length |
607 |
selected = attr |
608 |
elif type(attr) is QEngineeringInstrumentItem: |
609 |
if not attr.is_connected: |
610 |
dx = attr.center().x() - center.x() |
611 |
dy = attr.center().y() - center.y() |
612 |
if math.sqrt(dx*dx + dy*dy) < dist:
|
613 |
if self.add_assoc_item(attr): |
614 |
attr.owner = self
|
615 |
|
616 |
if selected is not None: |
617 |
if self.add_assoc_item(selected): |
618 |
selected.owner = self
|
619 |
|
620 |
except Exception as ex: |
621 |
from App import App |
622 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
623 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
624 |
|
625 |
'''
|
626 |
@brief Double click event, Show rotate symbol dialog
|
627 |
@author euisung
|
628 |
@date 2019.04.16
|
629 |
'''
|
630 |
def mouseDoubleClickEvent(self, event): |
631 |
func_map = [ |
632 |
(('Equipment - [ Pressure Drop ]', 'Air Fin Cooler', 'Air Fin Cooler'), self.show_AirFinCooler), |
633 |
(('Equipment - [ Pressure Drop ]', 'Filter', ('Horizontal','Vertical')), self.show_Filter), |
634 |
(('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('Double Pipe','Horizontal','Vertical','Kettle')), self.show_ShlTubHeatExchanger), |
635 |
(('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('Plate')), self.show_PlateHeatExchanger), |
636 |
(('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('Coil')), self.show_Coil), |
637 |
(('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('Equipment')), self.show_DP_Equipment), |
638 |
(('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('Reactor')), self.show_Reactor), |
639 |
(('Equipment - [ Pressure Drop ]', 'Strainer', ('Horizontal T','Vertical T')), self.show_Strainer_T), |
640 |
(('Equipment - [ Pressure Drop ]', 'Strainer', ('Horizontal Y','Vertical Y')), self.show_Strainer_Y), |
641 |
(('Equipment - [ Pressurized ]', 'Battery Limit', None), self.show_BatteryLimit), |
642 |
(('Equipment - [ Pressurized ]', 'Column', ('Tray')), self.show_Tray), |
643 |
(('Equipment - [ Pressurized ]', 'Column', ('Single Packed')), self.show_SinglePacked), |
644 |
(('Equipment - [ Pressurized ]', 'Column', ('Dual Packed')), self.show_DualPacked), |
645 |
(('Equipment - [ Pressurized ]', 'Drum', ('Horizontal')), self.show_Drum_Horizontal), |
646 |
(('Equipment - [ Pressurized ]', 'Drum', ('Vertical')), self.show_Drum_Vertical), |
647 |
(('Equipment - [ Pressurized ]', 'Miscellaneous', ('Equipment')), self.show_Equipment), |
648 |
(('Equipment - [ Pressurized ]', 'Tank', ('Ball')), self.show_Ball), |
649 |
(('Equipment - [ Pressurized ]', 'Tank', ('Cone Roof')), self.show_ConeRoof), |
650 |
(('Equipment - [ Rotating ]', 'Compressor', ('Left','Right')), self.show_Compressor), |
651 |
(('Equipment - [ Rotating ]', 'Pump', ('Horizontal Left','Horizontal Right','Vertical')), self.show_Pump), |
652 |
(('Instrument', 'Valve', ('Horizontal Control','Vertical Control')), self.show_ValveControl), |
653 |
(('Instrument', 'Valve', ('Horizontal Manual','Vertical Manual')), self.show_ValveManual), |
654 |
(('Instrument', 'Line Splitter', ('Line Splitter')), self.show_LineSplitter), |
655 |
(('Instrument', 'Flowmeter', ('Horizontal Orifice','Horizontal Others','Horizontal Venturi','Vertical Orifice','Vertical Others','Vertical Venturi')), self.show_Flowmeter), |
656 |
(('Instrument', 'Reducer', ('Down','Left','Right','Up')), self.show_Reducer) |
657 |
] |
658 |
|
659 |
connectedItems = [connector for connector in self.connectors if connector.connectedItem is not None] |
660 |
if len(connectedItems) < 1: |
661 |
|
662 |
msg = QMessageBox() |
663 |
msg.setIcon(QMessageBox.Information) |
664 |
msg.setText(self.tr('Connect Line before Data input')) |
665 |
msg.setWindowTitle(self.tr("Notice")) |
666 |
msg.setStandardButtons(QMessageBox.Ok) |
667 |
msg.exec_() |
668 |
return
|
669 |
|
670 |
matches = [func for func in func_map if func[0][0] == self.category and func[0][1] == self.type and (func[0][2] is None or self.name in func[0][2])] |
671 |
if matches: matches[0][1]() |
672 |
|
673 |
def show_AirFinCooler(self): |
674 |
from AirFinCooler import QAirFinCooler |
675 |
|
676 |
dialog = QAirFinCooler() |
677 |
dialog.showDialog(self)
|
678 |
|
679 |
def show_Filter(self): |
680 |
from Filter import QFilter |
681 |
|
682 |
dialog = QFilter() |
683 |
dialog.showDialog(self)
|
684 |
|
685 |
def show_Coil(self): |
686 |
from Coil import QCoil |
687 |
|
688 |
dialog = QCoil() |
689 |
dialog.showDialog(self)
|
690 |
|
691 |
def show_DP_Equipment(self): |
692 |
from DP_Equipment import QDP_Equipment |
693 |
|
694 |
dialog = QDP_Equipment() |
695 |
dialog.showDialog(self)
|
696 |
|
697 |
def show_Reactor(self): |
698 |
from Reactor import QReactor |
699 |
|
700 |
dialog = QReactor() |
701 |
dialog.showDialog(self)
|
702 |
|
703 |
def show_Strainer_T(self): |
704 |
from Strainer_T import QStrainer_T |
705 |
|
706 |
dialog = QStrainer_T() |
707 |
dialog.showDialog(self)
|
708 |
|
709 |
def show_Strainer_Y(self): |
710 |
from Strainer_Y import QStrainer_Y |
711 |
|
712 |
dialog = QStrainer_Y() |
713 |
dialog.showDialog(self)
|
714 |
|
715 |
def show_BatteryLimit(self): |
716 |
from BatteryLimit import QBatteryLimit |
717 |
|
718 |
dialog = QBatteryLimit() |
719 |
dialog.showDialog(self)
|
720 |
|
721 |
def show_Tray(self): |
722 |
from Tray import QTray |
723 |
|
724 |
dialog = QTray() |
725 |
dialog.showDialog(self)
|
726 |
|
727 |
def show_SinglePacked(self): |
728 |
from SinglePacked import QSinglePacked |
729 |
|
730 |
dialog = QSinglePacked() |
731 |
dialog.showDialog(self)
|
732 |
|
733 |
def show_DualPacked(self): |
734 |
from DualPacked import QDualPacked |
735 |
|
736 |
dialog = QDualPacked() |
737 |
dialog.showDialog(self)
|
738 |
|
739 |
def show_Drum_Horizontal(self): |
740 |
from Drum_Horizontal import QDrum_Horizontal |
741 |
|
742 |
dialog = QDrum_Horizontal() |
743 |
dialog.showDialog(self)
|
744 |
|
745 |
def show_Drum_Vertical(self): |
746 |
from Drum_Vertical import QDrum_Vertical |
747 |
|
748 |
dialog = QDrum_Vertical() |
749 |
dialog.showDialog(self)
|
750 |
|
751 |
def show_PlateHeatExchanger(self): |
752 |
from PlateHeatExchanger import QPlateHeatExchanger |
753 |
|
754 |
dialog = QPlateHeatExchanger() |
755 |
dialog.showDialog(self)
|
756 |
|
757 |
def show_Equipment(self): |
758 |
from Equipment import QEquipment |
759 |
|
760 |
dialog = QEquipment() |
761 |
dialog.showDialog(self)
|
762 |
|
763 |
def show_Ball(self): |
764 |
from Ball import QBall |
765 |
|
766 |
dialog = QBall() |
767 |
dialog.showDialog(self)
|
768 |
|
769 |
def show_ShlTubHeatExchanger(self): |
770 |
from ShlTubHeatExchanger import QShlTubHeatExchanger |
771 |
|
772 |
dialog = QShlTubHeatExchanger() |
773 |
dialog.showDialog(self)
|
774 |
|
775 |
def show_ConeRoof(self): |
776 |
from ConeRoof import QConeRoof |
777 |
|
778 |
dialog = QConeRoof() |
779 |
dialog.showDialog(self)
|
780 |
|
781 |
def show_DomeRoof(self): |
782 |
from DomeRoof import QDomeRoof |
783 |
|
784 |
dialog = QDomeRoof() |
785 |
dialog.showDialog(self)
|
786 |
|
787 |
def show_Compressor(self): |
788 |
from Compressor import QCompressor |
789 |
|
790 |
dialog = QCompressor() |
791 |
dialog.showDialog(self)
|
792 |
|
793 |
def show_Pump(self): |
794 |
from Pump import QPump |
795 |
|
796 |
dialog = QPump() |
797 |
dialog.showDialog(self)
|
798 |
|
799 |
def show_ValveControl(self): |
800 |
from Valve_Control import QValve_Control |
801 |
|
802 |
dialog = QValve_Control() |
803 |
dialog.showDialog(self)
|
804 |
|
805 |
def show_ValveManual(self): |
806 |
from Valve_Manual import QValve_Manual |
807 |
|
808 |
dialog = QValve_Manual() |
809 |
dialog.showDialog(self)
|
810 |
|
811 |
def show_LineSplitter(self): |
812 |
from LineSplitter import QLineSplitter |
813 |
|
814 |
dialog = QLineSplitter() |
815 |
dialog.showDialog(self)
|
816 |
|
817 |
def show_Flowmeter(self): |
818 |
from Flowmeter import QFlowmeter |
819 |
|
820 |
dialog = QFlowmeter() |
821 |
dialog.showDialog(self)
|
822 |
|
823 |
def show_Reducer(self): |
824 |
from Reducer import QReducer |
825 |
|
826 |
dialog = QReducer() |
827 |
dialog.showDialog(self)
|
828 |
|
829 |
@staticmethod
|
830 |
def fromDatabase(componentInfos): |
831 |
""" create a componenet from database """
|
832 |
item = None
|
833 |
|
834 |
try:
|
835 |
uid = componentInfos[0][0] # uid@Components |
836 |
dbUid = componentInfos[0][2] # Symbol_UID@Components |
837 |
category = componentInfos[0][3] # Category@SymbolType |
838 |
_type = componentInfos[0][4] # Type@SymbolType |
839 |
name = componentInfos[0][5] # Name@Symbols |
840 |
originalPoint = componentInfos[0][6] # OriginalPoint@Symbols |
841 |
x = componentInfos[0][7] # X@Components |
842 |
y = componentInfos[0][8] # Y@Components |
843 |
angle = componentInfos[0][9] # Rotation@Components |
844 |
scale = componentInfos[0][10] # Scale@Components |
845 |
|
846 |
pt = [] |
847 |
pt.append(float(x))
|
848 |
pt.append(float(y))
|
849 |
|
850 |
origin = [float(x) for x in str(originalPoint).split(',')] |
851 |
|
852 |
connPts = [] |
853 |
|
854 |
pointsUids = [] |
855 |
for componentInfo in componentInfos: |
856 |
pointsUid = componentInfo[11] # uid@Points |
857 |
pointsUids.append(pointsUid) |
858 |
|
859 |
appDocData = AppDocData.instance() |
860 |
project = appDocData.getCurrentProject() |
861 |
svgFilePath = os.path.join(project.getSvgFilePath(), category, _type, name + '.svg')
|
862 |
if os.path.isfile(svgFilePath):
|
863 |
item = SymbolSvgItem.createItem(_type, svgFilePath, uid) |
864 |
item.setVisible(False)
|
865 |
item.buildItem(name, _type, float(angle), float(scale), pt, origin, connPts, dbUid, pointsUids) |
866 |
|
867 |
for area in appDocData.getAreaList(): |
868 |
if area.contains(pt):
|
869 |
item.area = area.name |
870 |
break
|
871 |
|
872 |
except Exception as ex: |
873 |
from App import App |
874 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
875 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
876 |
|
877 |
return item
|
878 |
|
879 |
'''
|
880 |
@brief create item corresponding to given type
|
881 |
@author humkyung
|
882 |
@date 2018.05.02
|
883 |
@history 2018.05.08 Jeongwoo Change type name (Piping OPC''S → Piping OPC's)
|
884 |
humkyung 2018.05.10 change symbol's color to blue
|
885 |
humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
|
886 |
'''
|
887 |
@staticmethod
|
888 |
def createItem(type, path, uid=None, owner=None, flip=0): |
889 |
from QEngineeringOPCItem import QEngineeringOPCItem |
890 |
from EngineeringEquipmentItem import QEngineeringEquipmentItem |
891 |
from EngineeringInstrumentItem import QEngineeringInstrumentItem |
892 |
from EngineeringNozzleItem import QEngineeringNozzleItem |
893 |
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem |
894 |
from EngineeringReducerItem import QEngineeringReducerItem |
895 |
from EngineeringErrorItem import QEngineeringErrorItem |
896 |
from EngineeringEndBreakItem import QEngineeringEndBreakItem |
897 |
from EngineeringStreamlineItem import QEngineeringStreamlineItem |
898 |
from AppDocData import AppDocData |
899 |
import uuid |
900 |
|
901 |
docData = AppDocData.instance() |
902 |
|
903 |
item = None
|
904 |
cateogry = docData.getSymbolCategoryByType(type)
|
905 |
if type == "Piping OPC's": |
906 |
item = QEngineeringOPCItem(path, uid, flip=flip) |
907 |
elif cateogry == 'Equipment': |
908 |
item = QEngineeringEquipmentItem(path, uid, flip=flip) |
909 |
elif cateogry == 'Instrumentation': |
910 |
item = QEngineeringInstrumentItem(path, uid, flip=flip) |
911 |
#elif type == 'Nozzles':
|
912 |
# item = QEngineeringNozzleItem(path, uid, flip=flip)
|
913 |
elif type == 'Segment Breaks': |
914 |
item = QEngineeringSpecBreakItem(path, uid, flip=flip) |
915 |
elif type == 'Reducers': |
916 |
item = QEngineeringReducerItem(path, uid, flip=flip) |
917 |
elif type == 'Error': |
918 |
item = QEngineeringErrorItem(path, uid, flip=flip) |
919 |
elif type == 'End Break': |
920 |
item = QEngineeringEndBreakItem(path, uid, flip=flip) |
921 |
elif type == 'Line': |
922 |
item = QEngineeringFlowMarkItem(path, uid, flip=flip) |
923 |
elif type == 'Steam Line': |
924 |
item = QEngineeringStreamlineItem(uid) |
925 |
else:
|
926 |
item = SymbolSvgItem(path, uid, flip=flip) |
927 |
|
928 |
if owner is not None: |
929 |
item.owner = uuid.UUID(owner, version=4)
|
930 |
|
931 |
return item
|
932 |
|
933 |
'''
|
934 |
@brief change svg's color
|
935 |
@author humkyung
|
936 |
@date 2018.05.10
|
937 |
@history 2018.05.11 Jeongwoo Override QEngineeringAbstractItem's
|
938 |
humkyung 2018.05.13 update after change color
|
939 |
'''
|
940 |
def setColor(self, color): |
941 |
self.changeAttributes('fill', color) |
942 |
self.changeAttributes('stroke', color) |
943 |
self.renderer().load(self._document.toByteArray()) |
944 |
self.update()
|
945 |
|
946 |
def getColor(self): |
947 |
""" return hover color if mouse is over otherwise reutrn owner's color if owner exist else this color """
|
948 |
return SymbolSvgItem.HOVER_COLOR if self.hover else (self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color) |
949 |
|
950 |
'''
|
951 |
@brief get attributes from svg file
|
952 |
@author humkyung
|
953 |
@date 2019.03.08
|
954 |
'''
|
955 |
def get_attribute(self, attName): |
956 |
root = self._document.documentElement()
|
957 |
node = root.firstChild() |
958 |
while not node.isNull(): |
959 |
if node.isElement():
|
960 |
element = node.toElement() |
961 |
if element.hasAttribute(attName):
|
962 |
return element.attribute(attName)
|
963 |
|
964 |
if element.hasChildNodes():
|
965 |
att_val = self.recursive_get_attribute(element.firstChild(), attName)
|
966 |
if att_val is not None: return att_val |
967 |
|
968 |
node = node.nextSibling() |
969 |
|
970 |
return None |
971 |
|
972 |
'''
|
973 |
@brief get recursively attribute
|
974 |
@author humkyung
|
975 |
@date 2019.03.08
|
976 |
'''
|
977 |
def recursive_get_attribute(self, node, attName): |
978 |
while not node.isNull(): |
979 |
if node.isElement():
|
980 |
element = node.toElement() |
981 |
if element.hasAttribute(attName):
|
982 |
return element.attribute(attName)
|
983 |
|
984 |
if node.hasChildNodes():
|
985 |
att_val = self.recursive_get_attribute(node.firstChild(), attName)
|
986 |
if att_val is not None: return att_val |
987 |
|
988 |
node = node.nextSibling() |
989 |
|
990 |
return None |
991 |
|
992 |
'''
|
993 |
@brief change attributes
|
994 |
@author humkyung
|
995 |
@date 2018.05.10
|
996 |
'''
|
997 |
def changeAttributes(self, attName, attValue): |
998 |
root = self._document.documentElement()
|
999 |
node = root.firstChild() |
1000 |
while not node.isNull(): |
1001 |
if node.isElement():
|
1002 |
element = node.toElement() |
1003 |
if element.hasAttribute(attName):
|
1004 |
element.setAttribute(attName, attValue) |
1005 |
|
1006 |
if element.hasChildNodes():
|
1007 |
recursiveChangeAttributes(element.firstChild(), attName, attValue) |
1008 |
|
1009 |
node = node.nextSibling() |
1010 |
|
1011 |
'''
|
1012 |
@brief change attribute
|
1013 |
@author humkyung
|
1014 |
@date 2018.05.10
|
1015 |
'''
|
1016 |
def recursiveChangeAttributes(self, node, attName, attValue): |
1017 |
while not node.isNull(): |
1018 |
if node.isElement():
|
1019 |
element = node.toElement() |
1020 |
if element.hasAttribute(attName):
|
1021 |
element.setAttribute(attName, attValue) |
1022 |
|
1023 |
if node.hasChildNodes():
|
1024 |
recursiveChangeAttributes(node.firstChild(), attName, attValue) |
1025 |
|
1026 |
node = node.nextSibling() |
1027 |
|
1028 |
'''
|
1029 |
@brief draw rect when item is selected
|
1030 |
@author humkyung
|
1031 |
@date 2018.07.07
|
1032 |
'''
|
1033 |
def drawFocusRect(self, painter): |
1034 |
self.focuspen = QPen(Qt.DotLine)
|
1035 |
self.focuspen.setColor(Qt.black)
|
1036 |
self.focuspen.setWidthF(1.5) |
1037 |
hilightColor = QColor(255, 0, 0, 127) |
1038 |
painter.setBrush(QBrush(hilightColor)) |
1039 |
painter.setPen(self.focuspen)
|
1040 |
painter.drawRect(self.boundingRect())
|
1041 |
|
1042 |
'''
|
1043 |
@brief override paint(draw connection points)
|
1044 |
@author humkyung
|
1045 |
@date 2018.04.21
|
1046 |
'''
|
1047 |
def paint(self, painter, options=None, widget=None): |
1048 |
from EngineeringAbstractItem import QEngineeringAbstractItem |
1049 |
from EngineeringTextItem import QEngineeringTextItem |
1050 |
|
1051 |
self.setColor(self.getColor()) |
1052 |
|
1053 |
painter.setClipRect(options.exposedRect) |
1054 |
QGraphicsSvgItem.paint(self, painter, options, widget)
|
1055 |
for attr in self.attrs: |
1056 |
if issubclass(type(attr), QEngineeringTextItem): |
1057 |
color = QEngineeringAbstractItem.HOVER_COLOR if self.hover else (self._owner._color if self._owner else QEngineeringAbstractItem.DEFAULT_COLOR) |
1058 |
attr.setColor(color) |
1059 |
elif issubclass(type(attr), SymbolSvgItem): |
1060 |
attr.setColor(self.getColor())
|
1061 |
attr.update() |
1062 |
|
1063 |
if self.isSelected(): |
1064 |
self.drawFocusRect(painter)
|
1065 |
|
1066 |
'''
|
1067 |
@brief Add Svg Item into ImageViewer's Scene
|
1068 |
@author Jeongwoo
|
1069 |
@date 2018.05.03
|
1070 |
@history add connectors which's parent is symbol
|
1071 |
kyouho 2018.07.30 remove connectors logic
|
1072 |
'''
|
1073 |
def addSvgItemToScene(self, scene): |
1074 |
transform = QTransform() |
1075 |
|
1076 |
transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1]) |
1077 |
transform.rotateRadians(-self.angle)
|
1078 |
transform.translate(-self.symbolOrigin[0], -self.symbolOrigin[1]) |
1079 |
transform.scale(self._scale, self._scale) |
1080 |
|
1081 |
self.setTransform(transform)
|
1082 |
scene.addItem(self)
|
1083 |
|
1084 |
'''
|
1085 |
@brief
|
1086 |
@author humkyung
|
1087 |
@date 2018.07.27
|
1088 |
'''
|
1089 |
def onConnectorPosChaned(self, connector): |
1090 |
pass
|
1091 |
|
1092 |
'''
|
1093 |
@brief set connector
|
1094 |
@author kyouho
|
1095 |
@date 2018.07.26
|
1096 |
'''
|
1097 |
def setConnector(self, uid, index=None): |
1098 |
from AppDocData import AppDocData |
1099 |
|
1100 |
app_doc_data = AppDocData.instance() |
1101 |
connector = QEngineeringConnectorItem(uid, parent=self, index=index)
|
1102 |
connector.nozzle_data = app_doc_data.get_nozzle_data(uid) |
1103 |
connector.setParentItem(self)
|
1104 |
self.connectors.append(connector)
|
1105 |
|
1106 |
'''
|
1107 |
'''
|
1108 |
def refreshConnector(self): |
1109 |
for connector in self.connectors: |
1110 |
connector.buildItem() |
1111 |
|
1112 |
def deleteSvgItemFromScene(self): |
1113 |
""" remove self from scene """
|
1114 |
try:
|
1115 |
for conn in self.connectors: |
1116 |
if conn.connectedItem is not None: |
1117 |
conn.connectedItem.connect(None)
|
1118 |
except Exception as ex: |
1119 |
from App import App |
1120 |
from AppDocData import MessageType |
1121 |
|
1122 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
1123 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
1124 |
|
1125 |
self.transfer.onRemoved.emit(self) |
1126 |
|
1127 |
'''
|
1128 |
@brief Return real item position
|
1129 |
@author Jeongwoo
|
1130 |
@date 2018.05.25
|
1131 |
'''
|
1132 |
def boundingRectOnScene(self): |
1133 |
rect = self.boundingRect()
|
1134 |
rect.moveTo(self.loc[0], self.loc[1]) |
1135 |
return rect
|
1136 |
|
1137 |
def flipSymbol(self): |
1138 |
'''
|
1139 |
@brief remove item when user press delete key
|
1140 |
@author humkyung
|
1141 |
@date 2018.04.23
|
1142 |
'''
|
1143 |
if self.flip is 0: |
1144 |
self.flip = 1 |
1145 |
else:
|
1146 |
self.flip = 0 |
1147 |
|
1148 |
currentPoint = self.getCurrentPoint()
|
1149 |
self.reSettingSymbol(currentPoint, self.angle) |
1150 |
|
1151 |
'''
|
1152 |
@brief rotate Symbol
|
1153 |
@author kyouho
|
1154 |
@date 2018.07.24
|
1155 |
'''
|
1156 |
def rotateSymbol(self, angle=None): |
1157 |
if angle is None: |
1158 |
#degree 0
|
1159 |
if 0 == self.angle: |
1160 |
self.angle = 1.57 |
1161 |
#degree 90
|
1162 |
elif (1.57 == self.angle): |
1163 |
self.angle = 3.14 |
1164 |
#degree 180
|
1165 |
elif 3.14 == self.angle: |
1166 |
self.angle = 4.71 |
1167 |
#degree 270
|
1168 |
elif 4.71 == self.angle : |
1169 |
self.angle = 0 |
1170 |
else:
|
1171 |
self.angle = 0 |
1172 |
|
1173 |
self.size[0], self.size[1] = self.size[1], self.size[0] |
1174 |
else:
|
1175 |
self.angle = angle
|
1176 |
|
1177 |
#scene = self.scene()
|
1178 |
#self.scene().removeItem(self)
|
1179 |
#self.addSvgItemToScene(scene)
|
1180 |
currentPoint = self.getCurrentPoint()
|
1181 |
self.reSettingSymbol(currentPoint, self.angle) |
1182 |
|
1183 |
'''
|
1184 |
@brief resetting rotate Symbol
|
1185 |
@author kyouho
|
1186 |
@date 2018.07.24
|
1187 |
'''
|
1188 |
def reSettingSymbol(self, standardPoint, angle): |
1189 |
transform = QTransform() |
1190 |
|
1191 |
transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1]) |
1192 |
transform.rotateRadians(-angle) |
1193 |
transform.translate(-standardPoint[0], -standardPoint[1]) |
1194 |
|
1195 |
if self.flip is 1: |
1196 |
transform.scale(-1.0, 1.0) |
1197 |
transform.translate(-self.size[0], 0) |
1198 |
|
1199 |
self.setTransform(transform)
|
1200 |
self.reSettingConnetors()
|
1201 |
|
1202 |
def reSettingConnetors(self): |
1203 |
for conn in self.connectors: |
1204 |
conn.sceneConnectPoint = (conn.sceneBoundingRect().center().x(), conn.sceneBoundingRect().center().y()) |
1205 |
|
1206 |
from EngineeringLineItem import QEngineeringLineItem |
1207 |
for connector in self.connectors: |
1208 |
if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem: |
1209 |
line = connector.connectedItem |
1210 |
line.reDrawLine(self, connector.center())
|
1211 |
line.update_arrow() |
1212 |
|
1213 |
'''
|
1214 |
@brief change Conn point
|
1215 |
@author kyouho
|
1216 |
@date 2018.07.25
|
1217 |
'''
|
1218 |
def changeConnPoint(self): |
1219 |
if len(self.connectors) == 2: |
1220 |
|
1221 |
conn1Item = self.connectors[0].connectedItem |
1222 |
conn2Item = self.connectors[1].connectedItem |
1223 |
self.connectors[0].connectedItem = conn2Item |
1224 |
self.connectors[1].connectedItem = conn1Item |
1225 |
|
1226 |
currentPoint = self.getCurrentPoint()
|
1227 |
self.reSettingSymbol(currentPoint, self.angle) |
1228 |
|
1229 |
'''
|
1230 |
@brief change standard point
|
1231 |
@author kyouho
|
1232 |
@date 2018.07.24
|
1233 |
'''
|
1234 |
def changeStandardPoint(self): |
1235 |
connPtsCount = len(self.connectors) |
1236 |
|
1237 |
if self.currentPointModeIndex < connPtsCount: |
1238 |
self.currentPointModeIndex += 1 |
1239 |
else:
|
1240 |
self.currentPointModeIndex = 0 |
1241 |
|
1242 |
currentPoint = self.getCurrentPoint()
|
1243 |
self.reSettingSymbol(currentPoint, self.angle) |
1244 |
|
1245 |
'''
|
1246 |
@brief get standard point
|
1247 |
@author kyouho
|
1248 |
@date 2018.07.25
|
1249 |
'''
|
1250 |
def getCurrentPoint(self): |
1251 |
#from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
|
1252 |
|
1253 |
pointList = [] |
1254 |
pointList.append(self.symbolOrigin)
|
1255 |
for connector in self.connectors: |
1256 |
pointList.append(connector.connectPoint) |
1257 |
|
1258 |
#if type(self) is QEngineeringSpecBreakItem:
|
1259 |
# self.currentPointModeIndex = 1
|
1260 |
|
1261 |
return pointList[self.currentPointModeIndex] |
1262 |
|
1263 |
'''
|
1264 |
@brief 심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
|
1265 |
@author kyouho
|
1266 |
@date 18.08.06
|
1267 |
'''
|
1268 |
def reCalculationRotatedItem(self): |
1269 |
|
1270 |
transform = QTransform() |
1271 |
transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1]) |
1272 |
transform.rotateRadians(-self.angle)
|
1273 |
currentPoint = self.getCurrentPoint()
|
1274 |
transform.translate(-currentPoint[0], -currentPoint[1]) |
1275 |
# 시작점을 구하기 위해서
|
1276 |
goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1])) |
1277 |
|
1278 |
self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()] |
1279 |
|
1280 |
def resize(self, change): |
1281 |
""" resize item """
|
1282 |
# Get the smaller side of the rect
|
1283 |
rect = self.sceneBoundingRect()
|
1284 |
loc = QPointF(rect.x(), rect.y()) |
1285 |
self.resetTransform()
|
1286 |
#self.setScale(1)
|
1287 |
rect = self.sceneBoundingRect()
|
1288 |
scale = [(change.width() - loc.x())/rect.width(), (change.height() - loc.y())/rect.height()] |
1289 |
#scale the item
|
1290 |
if scale[0] > 0 and scale[1] > 0: |
1291 |
self.setPos(loc)
|
1292 |
#self.setScale(scale[0] if scale[0] < scale[1] else scale[1])
|
1293 |
trans = QTransform() |
1294 |
trans.scale(scale[0] if scale[0] < scale[1] else scale[1],scale[0] if scale[0] < scale[1] else scale[1]) |
1295 |
self.setTransform(trans)
|
1296 |
self.prepareGeometryChange()
|
1297 |
self.update()
|
1298 |
|
1299 |
self.transfer.on_size_changed.emit(self) |
1300 |
|
1301 |
def moveto(self, to, timeLine = 5000, rotation = 0): |
1302 |
"""Move the item from one position to one other."""
|
1303 |
|
1304 |
anim = QPropertyAnimation(self, b'pos') |
1305 |
rect = self.sceneBoundingRect()
|
1306 |
anim.setStartValue(QPointF(0, 0)) |
1307 |
anim.setEndValue(QPointF(100,10)) |
1308 |
anim.setDuration(10000)
|
1309 |
anim.start() |
1310 |
|
1311 |
def recursiveChangeAttributes(node, attName, attValue): |
1312 |
while not node.isNull(): |
1313 |
if node.isElement():
|
1314 |
element = node.toElement() |
1315 |
if element.hasAttribute(attName):
|
1316 |
element.setAttribute(attName, attValue) |
1317 |
|
1318 |
if node.hasChildNodes():
|
1319 |
recursiveChangeAttributes(node.firstChild(), attName, attValue) |
1320 |
|
1321 |
node = node.nextSibling() |
1322 |
|
1323 |
'''
|
1324 |
@brief The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
|
1325 |
@author Jeongwoo
|
1326 |
@date 2018.06.18
|
1327 |
'''
|
1328 |
class Transfer(QObject): |
1329 |
on_pos_changed = pyqtSignal(QGraphicsItem) |
1330 |
on_size_changed = pyqtSignal(QGraphicsItem) |
1331 |
onRemoved = pyqtSignal(QGraphicsItem) |
1332 |
|
1333 |
def __init__(self, parent = None): |
1334 |
QObject.__init__(self, parent)
|
1335 |
|
1336 |
|
1337 |
if __name__ == '__main__': |
1338 |
f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
|
1339 |
f.open(QIODevice.ReadOnly) |
1340 |
array = f.readAll() |
1341 |
document = QDomDocument() |
1342 |
document.setContent(array) |
1343 |
|
1344 |
root = document.documentElement() |
1345 |
node = root.firstChild() |
1346 |
while not node.isNull(): |
1347 |
if node.isElement():
|
1348 |
element = node.toElement() |
1349 |
if element.hasAttribute('fill'): |
1350 |
element.setAttribute('fill', '#FFFFF') |
1351 |
|
1352 |
if element.hasChildNodes():
|
1353 |
recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF') |
1354 |
|
1355 |
node = node.nextSibling() |