hytos / HYTOS / HYTOS / Shapes / EngineeringDimensionItem.py @ 759bdc98
이력 | 보기 | 이력해설 | 다운로드 (11.4 KB)
1 |
# coding: utf-8
|
---|---|
2 |
import os.path |
3 |
import copy |
4 |
import sys |
5 |
|
6 |
try:
|
7 |
from PyQt5.QtCore import Qt, QPointF, QRectF, pyqtSignal, QObject, QT_VERSION_STR, QRect |
8 |
from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QBrush, QPen, QTransform, QFont, QColor, QFontMetricsF |
9 |
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QGraphicsItem, QAbstractGraphicsShapeItem, \ |
10 |
QGraphicsPathItem
|
11 |
except ImportError: |
12 |
try:
|
13 |
from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QRect, QObject, QT_VERSION_STR |
14 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QFont, \ |
15 |
QColor, QFontMetricsF |
16 |
except ImportError: |
17 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
18 |
|
19 |
from AppDocData import * |
20 |
from EngineeringAbstractItem import QEngineeringAbstractItem |
21 |
|
22 |
|
23 |
class QEngineeringDimensionItem(QGraphicsPathItem, QEngineeringAbstractItem): |
24 |
selected_change = pyqtSignal(QGraphicsItem) |
25 |
|
26 |
ARROW_SIZE = 10
|
27 |
DIMENSION_DEPTH = 30
|
28 |
HIGHLIGHT = '#BC4438'
|
29 |
ZVALUE = 210
|
30 |
|
31 |
def __init__(self, uid=None, pts=None): |
32 |
import uuid |
33 |
|
34 |
QGraphicsPathItem.__init__(self, None) |
35 |
QEngineeringAbstractItem.__init__(self)
|
36 |
|
37 |
self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid, version=4) |
38 |
self.type = 'Dimension' |
39 |
self.loc = None |
40 |
self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable)
|
41 |
self.setAcceptHoverEvents(True) |
42 |
self.setAcceptTouchEvents(True) |
43 |
|
44 |
self._selected_idx = None |
45 |
self.setPath(self.create_path(pts)) |
46 |
self.setBrush(Qt.black)
|
47 |
|
48 |
self.transfer = Transfer()
|
49 |
self.setZValue(QEngineeringDimensionItem.ZVALUE)
|
50 |
|
51 |
def __str__(self): |
52 |
""" return string represent uuid """
|
53 |
return str(self.uid) |
54 |
|
55 |
@property
|
56 |
def pos(self): |
57 |
"""return dimension position"""
|
58 |
path = self.mapToScene(self.path()) |
59 |
return [QPointF(path.elementAt(0).x, path.elementAt(0).y), QPointF(path.elementAt(1).x, path.elementAt(1).y)] |
60 |
|
61 |
def set_pos(self, pts): |
62 |
"""set dimension positions"""
|
63 |
|
64 |
if pts and 2 == len(pts): |
65 |
self.setPath(self.create_path(pts)) |
66 |
|
67 |
def create_path(self, pts): |
68 |
"""create a path"""
|
69 |
import math |
70 |
from EngineeringConnectorItem import QEngineeringConnectorItem |
71 |
|
72 |
#self.resetTransform()
|
73 |
path = QPainterPath() |
74 |
if pts:
|
75 |
if 1 == len(pts): |
76 |
pts.append(QPointF(pts[0].x() + 10, pts[0].y() + 10)) |
77 |
|
78 |
path.moveTo(pts[0])
|
79 |
path.lineTo(pts[1])
|
80 |
|
81 |
dx = pts[1].x() - pts[0].x() |
82 |
dy = pts[1].y() - pts[0].y() |
83 |
length = math.sqrt(dx*dx + dy*dy) |
84 |
if length:
|
85 |
_dir = [dx / length, dy / length] |
86 |
|
87 |
arrow_size = QEngineeringDimensionItem.ARROW_SIZE * 0.25
|
88 |
|
89 |
perpendicular = (-_dir[1], _dir[0]) |
90 |
polygon = QPolygonF() |
91 |
polygon.append(QPointF( |
92 |
pts[1].x() - _dir[0] * QEngineeringDimensionItem.ARROW_SIZE + perpendicular[0] * arrow_size, |
93 |
pts[1].y() - _dir[1] * QEngineeringDimensionItem.ARROW_SIZE + perpendicular[1] * arrow_size)) |
94 |
polygon.append(QPointF( |
95 |
pts[1].x() - _dir[0] * QEngineeringDimensionItem.ARROW_SIZE - perpendicular[0] * arrow_size, |
96 |
pts[1].y() - _dir[1] * QEngineeringDimensionItem.ARROW_SIZE - perpendicular[1] * arrow_size)) |
97 |
polygon.append(pts[1])
|
98 |
polygon.append(polygon[0])
|
99 |
|
100 |
path.addPolygon(polygon) |
101 |
|
102 |
polygon = QPolygonF() |
103 |
polygon.append(QPointF( |
104 |
pts[0].x() + _dir[0] * QEngineeringDimensionItem.ARROW_SIZE + perpendicular[0] * arrow_size, |
105 |
pts[0].y() + _dir[1] * QEngineeringDimensionItem.ARROW_SIZE + perpendicular[1] * arrow_size)) |
106 |
polygon.append(QPointF( |
107 |
pts[0].x() + _dir[0] * QEngineeringDimensionItem.ARROW_SIZE - perpendicular[0] * arrow_size, |
108 |
pts[0].y() + _dir[1] * QEngineeringDimensionItem.ARROW_SIZE - perpendicular[1] * arrow_size)) |
109 |
polygon.append(pts[0])
|
110 |
polygon.append(polygon[0])
|
111 |
|
112 |
path.moveTo(pts[0].x() - perpendicular[0]*5, pts[0].y() - perpendicular[1]*5) |
113 |
path.lineTo(pts[0].x() + perpendicular[0]*QEngineeringDimensionItem.DIMENSION_DEPTH, |
114 |
pts[0].y() + perpendicular[1]*QEngineeringDimensionItem.DIMENSION_DEPTH) |
115 |
|
116 |
path.moveTo(pts[1].x() - perpendicular[0]*5, pts[1].y() - perpendicular[1]*5) |
117 |
path.lineTo(pts[1].x() + perpendicular[0] * QEngineeringDimensionItem.DIMENSION_DEPTH, |
118 |
pts[1].y() + perpendicular[1] * QEngineeringDimensionItem.DIMENSION_DEPTH) |
119 |
|
120 |
path.addPolygon(polygon) |
121 |
|
122 |
path.addEllipse(pts[0], 4, 4) |
123 |
path.addEllipse(pts[1], 4, 4) |
124 |
|
125 |
"""
|
126 |
if not self.connectors:
|
127 |
conn = QEngineeringConnectorItem(uid=None, parent=self, index=0)
|
128 |
conn.setFlags(
|
129 |
QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable)
|
130 |
conn.transfer.onPosChanged.connect(self.on_connector_pos_changed)
|
131 |
self.connectors.append(conn)
|
132 |
conn = QEngineeringConnectorItem(uid=None, parent=self, index=1)
|
133 |
conn.setFlags(
|
134 |
QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable)
|
135 |
conn.transfer.onPosChanged.connect(self.on_connector_pos_changed)
|
136 |
self.connectors.append(conn)
|
137 |
|
138 |
self.connectors[0].setPos((self._pts[0].x(), self._pts[0].y()))
|
139 |
self.connectors[1].setPos((self._pts[1].x(), self._pts[1].y()))
|
140 |
"""
|
141 |
|
142 |
return path
|
143 |
|
144 |
"""
|
145 |
def on_connector_pos_changed(self, conn):
|
146 |
#rebuild stream line
|
147 |
self._pts[conn._conn_index] = QPointF(conn.center()[0], conn.center()[1])
|
148 |
self.setPath(self.create_path())
|
149 |
"""
|
150 |
|
151 |
'''
|
152 |
@brief hover event
|
153 |
@authro humkyung
|
154 |
@date
|
155 |
'''
|
156 |
|
157 |
def hoverEnterEvent(self, event): |
158 |
self.highlight(True) |
159 |
|
160 |
def hoverLeaveEvent(self, event): |
161 |
self.highlight(False) |
162 |
|
163 |
def highlight(self, flag): |
164 |
"""highlight dimension"""
|
165 |
if flag:
|
166 |
_pen = self.pen()
|
167 |
_pen.setColor(QColor(QEngineeringAbstractItem.HOVER_COLOR)) |
168 |
else:
|
169 |
_pen = self.pen()
|
170 |
_pen.setColor(Qt.black) |
171 |
|
172 |
self.setPen(_pen)
|
173 |
self.update()
|
174 |
|
175 |
def hoverMoveEvent(self, event): |
176 |
pass
|
177 |
|
178 |
def mousePressEvent(self, event): |
179 |
import math |
180 |
|
181 |
if event.buttons() == Qt.LeftButton:
|
182 |
toler = 5
|
183 |
|
184 |
pos = event.scenePos() |
185 |
|
186 |
path = self.mapToScene(self.path()) |
187 |
pts = [QPointF(path.elementAt(0).x, path.elementAt(0).y), QPointF(path.elementAt(1).x, path.elementAt(1).y)] |
188 |
|
189 |
dx = pts[0].x() - pos.x()
|
190 |
dy = pts[0].y() - pos.y()
|
191 |
if math.sqrt(dx * dx + dy * dy) < toler:
|
192 |
self._selected_idx = 0 |
193 |
return
|
194 |
|
195 |
dx = pts[1].x() - pos.x()
|
196 |
dy = pts[1].y() - pos.y()
|
197 |
if math.sqrt(dx * dx + dy * dy) < toler:
|
198 |
self._selected_idx = 1 |
199 |
return
|
200 |
|
201 |
super(QEngineeringDimensionItem, self).mousePressEvent(event) |
202 |
|
203 |
def mouseMoveEvent(self, event): |
204 |
"""reshape dimension"""
|
205 |
|
206 |
if event.buttons() == Qt.LeftButton and (self._selected_idx == 0 or self._selected_idx == 1): |
207 |
path = self.mapToScene(self.path()) |
208 |
pts = [QPointF(path.elementAt(0).x, path.elementAt(0).y), QPointF(path.elementAt(1).x, path.elementAt(1).y)] |
209 |
pts[self._selected_idx] = event.scenePos()
|
210 |
self.setPath(self.create_path(pts)) |
211 |
return
|
212 |
|
213 |
super(QEngineeringDimensionItem, self).mouseMoveEvent(event) |
214 |
|
215 |
def mouseReleaseEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: |
216 |
self._selected_idx = None |
217 |
super(QEngineeringDimensionItem, self).mouseReleaseEvent(event) |
218 |
|
219 |
def itemChange(self, change, value): |
220 |
if change == QGraphicsItem.ItemSelectedChange:
|
221 |
pass
|
222 |
return value
|
223 |
|
224 |
def setColor(self, color): |
225 |
pass
|
226 |
|
227 |
@staticmethod
|
228 |
def fromDatabase(componentInfos): |
229 |
""" create a callout from database """
|
230 |
from PlaceDimensionCommand import PlaceDimensionCommand |
231 |
|
232 |
item = None
|
233 |
|
234 |
try:
|
235 |
uid = componentInfos[0]['Comp_UID'] # uid@Components |
236 |
tag_no = componentInfos[0]['Name'] # name@Components |
237 |
index = componentInfos[0]['Comp_Index'] |
238 |
dbUid = componentInfos[0]['Symbols_UID'] # Symbol_UID@Components |
239 |
category = componentInfos[0]['Category'] # Category@SymbolType |
240 |
_type = componentInfos[0]['Type'] # Type@SymbolType |
241 |
name = componentInfos[0]['Symbol_Name'] # Name@Symbols |
242 |
originalPoint = componentInfos[0]['OriginalPoint'] # OriginalPoint@Symbols |
243 |
x = componentInfos[0]['Comp_X'] # X@Components |
244 |
y = componentInfos[0]['Comp_Y'] # Y@Components |
245 |
angle = componentInfos[0]['Rotation'] # Rotation@Components |
246 |
scale = componentInfos[0]['Scale'] # Scale@Components |
247 |
|
248 |
pt = QPointF(float(x), float(y)) |
249 |
item = PlaceDimensionCommand.create_item(pt) |
250 |
except Exception as ex: |
251 |
from App import App |
252 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
253 |
sys.exc_info()[-1].tb_lineno)
|
254 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
255 |
|
256 |
return item
|
257 |
|
258 |
def toSql(self): |
259 |
"""convert callout data to sql query"""
|
260 |
from AppDocData import AppDocData |
261 |
|
262 |
""" generate sql string to save label to database """
|
263 |
res = [] |
264 |
|
265 |
try:
|
266 |
cols = ['UID', 'Symbols_UID', 'Name', 'X', 'Y'] |
267 |
values = ['?', "(select uid from Symbols where Name='Callout')", '?', '?', '?'] |
268 |
|
269 |
param = [str(self.uid), self.toHtml(), self.pos().x(), self.pos().y()] |
270 |
sql = f"insert or replace into Components({','.join(cols)}) values({','.join(values)})"
|
271 |
res.append((sql, tuple(param)))
|
272 |
|
273 |
cols, values = ['UID', 'Components_UID', '[Index]', 'X', 'Y'], ['?', '?', '?', '?', '?'] |
274 |
param = [str(self.uid), str(self.uid), 0, self.pos().x(), self.pos().y()] |
275 |
sql = 'insert or replace into Points({}) values({})'.format(','.join(cols), ','.join(values)) |
276 |
res.append((sql, tuple(param)))
|
277 |
|
278 |
except Exception as ex: |
279 |
from App import App |
280 |
from AppDocData import MessageType |
281 |
|
282 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
283 |
sys.exc_info()[-1].tb_lineno)
|
284 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
285 |
|
286 |
return res
|
287 |
|
288 |
'''
|
289 |
@brief The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
|
290 |
@author Jeongwoo
|
291 |
@date 2018.06.18
|
292 |
'''
|
293 |
|
294 |
|
295 |
class Transfer(QObject): |
296 |
onRemoved = pyqtSignal(QGraphicsItem) |
297 |
|
298 |
def __init__(self, parent=None): |
299 |
QObject.__init__(self, parent)
|