1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | ##Copyright 2009-2014 Thomas Paviot (tpaviot@gmail.com) |
---|
4 | ## |
---|
5 | ##This file is part of pythonOCC. |
---|
6 | ## |
---|
7 | ##pythonOCC is free software: you can redistribute it and/or modify |
---|
8 | ##it under the terms of the GNU Lesser General Public License as published by |
---|
9 | ##the Free Software Foundation, either version 3 of the License, or |
---|
10 | ##(at your option) any later version. |
---|
11 | ## |
---|
12 | ##pythonOCC is distributed in the hope that it will be useful, |
---|
13 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | ##GNU Lesser General Public License for more details. |
---|
16 | ## |
---|
17 | ##You should have received a copy of the GNU Lesser General Public License |
---|
18 | ##along with pythonOCC. If not, see <http://www.gnu.org/licenses/>. |
---|
19 | |
---|
20 | from __future__ import print_function |
---|
21 | |
---|
22 | import sys |
---|
23 | from OCC.Display import OCCViewer |
---|
24 | |
---|
25 | HAVE_PYQT4 = False |
---|
26 | HAVE_PYSIDE = False |
---|
27 | try: |
---|
28 | from PyQt4 import QtCore, QtGui, QtOpenGL |
---|
29 | HAVE_PYQT4 = True |
---|
30 | print("Using PyQt4") |
---|
31 | except ImportError: |
---|
32 | from PySide import QtCore, QtGui, QtOpenGL |
---|
33 | HAVE_PYSIDE = True |
---|
34 | print("PyQt4 not found - using PySide") |
---|
35 | |
---|
36 | |
---|
37 | def get_qt_modules(): |
---|
38 | return QtCore, QtGui, QtOpenGL |
---|
39 | |
---|
40 | |
---|
41 | class point(object): |
---|
42 | def __init__(self, obj=None): |
---|
43 | self.x = 0 |
---|
44 | self.y = 0 |
---|
45 | if obj is not None: |
---|
46 | self.set(obj) |
---|
47 | |
---|
48 | def set(self, obj): |
---|
49 | self.x = obj.x() |
---|
50 | self.y = obj.y() |
---|
51 | |
---|
52 | |
---|
53 | class qtBaseViewer(QtOpenGL.QGLWidget): |
---|
54 | ''' The base Qt Widget for an OCC viewer |
---|
55 | ''' |
---|
56 | def __init__(self, parent=None): |
---|
57 | QtOpenGL.QGLWidget.__init__(self, parent) |
---|
58 | self._display = None |
---|
59 | self._inited = False |
---|
60 | |
---|
61 | # enable Mouse Tracking |
---|
62 | self.setMouseTracking(True) |
---|
63 | # Strong focus |
---|
64 | self.setFocusPolicy(QtCore.Qt.WheelFocus) |
---|
65 | |
---|
66 | # required for overpainting the widget |
---|
67 | self.setAttribute(QtCore.Qt.WA_PaintOnScreen) |
---|
68 | self.setAttribute(QtCore.Qt.WA_NoSystemBackground) |
---|
69 | self.setAutoFillBackground(False) |
---|
70 | |
---|
71 | def GetHandle(self): |
---|
72 | ''' returns an the identifier of the GUI widget. |
---|
73 | It must be an integer |
---|
74 | ''' |
---|
75 | win_id = self.winId() ## this returns either an int or voitptr |
---|
76 | if HAVE_PYSIDE: |
---|
77 | ### with PySide, self.winId() does not return an integer |
---|
78 | if sys.platform == "win32": |
---|
79 | pycobject_hwnd = self.winId() |
---|
80 | import ctypes |
---|
81 | ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p |
---|
82 | ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object] |
---|
83 | win_id = ctypes.pythonapi.PyCObject_AsVoidPtr(pycobject_hwnd) |
---|
84 | else: |
---|
85 | win_id = self.winId() |
---|
86 | elif HAVE_PYQT4: |
---|
87 | #win_id = self.winId() |
---|
88 | ## below integer cast may be required because self.winId() can |
---|
89 | ## returns a sip.voitptr according to the PyQt version used |
---|
90 | ## as well as the python version |
---|
91 | if type(win_id) is not int: # cast to int using the int() funtion |
---|
92 | win_id = int(win_id) |
---|
93 | return win_id |
---|
94 | |
---|
95 | def resizeEvent(self, event): |
---|
96 | if self._inited: |
---|
97 | self._display.OnResize() |
---|
98 | |
---|
99 | |
---|
100 | class qtViewer3d(qtBaseViewer): |
---|
101 | def __init__(self, *kargs): |
---|
102 | qtBaseViewer.__init__(self, *kargs) |
---|
103 | self._drawbox = False |
---|
104 | self._zoom_area = False |
---|
105 | self._select_area = False |
---|
106 | self._inited = False |
---|
107 | self._leftisdown = False |
---|
108 | self._middleisdown = False |
---|
109 | self._rightisdown = False |
---|
110 | self._selection = None |
---|
111 | self._drawtext = True |
---|
112 | |
---|
113 | def InitDriver(self): |
---|
114 | self._display = OCCViewer.Viewer3d(self.GetHandle()) |
---|
115 | self._display.Create() |
---|
116 | # background gradient |
---|
117 | self._display.set_bg_gradient_color(206, 215, 222, 128, 128, 128) |
---|
118 | # background gradient |
---|
119 | self._display.display_trihedron() |
---|
120 | self._display.SetModeShaded() |
---|
121 | self._display.EnableAntiAliasing() |
---|
122 | self._inited = True |
---|
123 | # dict mapping keys to functions |
---|
124 | self._SetupKeyMap() |
---|
125 | |
---|
126 | def _SetupKeyMap(self): |
---|
127 | def set_shade_mode(): |
---|
128 | self._display.DisableAntiAliasing() |
---|
129 | self._display.SetModeShaded() |
---|
130 | |
---|
131 | self._key_map = {ord('W'): self._display.SetModeWireFrame, |
---|
132 | ord('S'): set_shade_mode, |
---|
133 | ord('A'): self._display.EnableAntiAliasing, |
---|
134 | ord('B'): self._display.DisableAntiAliasing, |
---|
135 | ord('H'): self._display.SetModeHLR, |
---|
136 | ord('F'): self._display.FitAll, |
---|
137 | ord('G'): self._display.SetSelectionMode |
---|
138 | } |
---|
139 | |
---|
140 | def keyPressEvent(self, event): |
---|
141 | code = event.key() |
---|
142 | if code in self._key_map: |
---|
143 | self._key_map[code]() |
---|
144 | else: |
---|
145 | print('key', code, ' not mapped to any function') |
---|
146 | |
---|
147 | def Test(self): |
---|
148 | if self._inited: |
---|
149 | self._display.Test() |
---|
150 | |
---|
151 | def focusInEvent(self, event): |
---|
152 | if self._inited: |
---|
153 | self._display.Repaint() |
---|
154 | |
---|
155 | def focusOutEvent(self, event): |
---|
156 | if self._inited: |
---|
157 | self._display.Repaint() |
---|
158 | |
---|
159 | def paintEvent(self, event): |
---|
160 | if self._inited: |
---|
161 | self._display.Context.UpdateCurrentViewer() |
---|
162 | # important to allow overpainting of the OCC OpenGL context in Qt |
---|
163 | self.swapBuffers() |
---|
164 | |
---|
165 | if self._drawbox: |
---|
166 | self.makeCurrent() |
---|
167 | painter = QtGui.QPainter(self) |
---|
168 | painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0), 1)) |
---|
169 | rect = QtCore.QRect(*self._drawbox) |
---|
170 | painter.drawRect(rect) |
---|
171 | painter.end() |
---|
172 | self.doneCurrent() |
---|
173 | |
---|
174 | def resizeGL(self, width, height): |
---|
175 | self.setupViewport(width, height) |
---|
176 | |
---|
177 | def ZoomAll(self, evt): |
---|
178 | self._display.FitAll() |
---|
179 | |
---|
180 | def wheelEvent(self, event): |
---|
181 | if event.delta() > 0: |
---|
182 | zoom_factor = 2 |
---|
183 | else: |
---|
184 | zoom_factor = 0.5 |
---|
185 | self._display.Repaint() |
---|
186 | self._display.ZoomFactor(zoom_factor) |
---|
187 | |
---|
188 | def dragMoveEvent(self, event): |
---|
189 | pass |
---|
190 | |
---|
191 | def mousePressEvent(self, event): |
---|
192 | self.setFocus() |
---|
193 | self.dragStartPos = point(event.pos()) |
---|
194 | self._display.StartRotation(self.dragStartPos.x, self.dragStartPos.y) |
---|
195 | |
---|
196 | def mouseReleaseEvent(self, event): |
---|
197 | pt = point(event.pos()) |
---|
198 | modifiers = event.modifiers() |
---|
199 | |
---|
200 | if event.button() == QtCore.Qt.LeftButton: |
---|
201 | pt = point(event.pos()) |
---|
202 | if self._select_area: |
---|
203 | [Xmin, Ymin, dx, dy] = self._drawbox |
---|
204 | self._display.SelectArea(Xmin, Ymin, Xmin+dx, Ymin+dy) |
---|
205 | self._select_area = False |
---|
206 | else: |
---|
207 | # multiple select if shift is pressed |
---|
208 | if modifiers == QtCore.Qt.ShiftModifier: |
---|
209 | self._display.ShiftSelect(pt.x, pt.y) |
---|
210 | else: |
---|
211 | # single select otherwise |
---|
212 | self._display.Select(pt.x, pt.y) |
---|
213 | elif event.button() == QtCore.Qt.RightButton: |
---|
214 | if self._zoom_area: |
---|
215 | [Xmin, Ymin, dx, dy] = self._drawbox |
---|
216 | self._display.ZoomArea(Xmin, Ymin, Xmin+dx, Ymin+dy) |
---|
217 | self._zoom_area = False |
---|
218 | |
---|
219 | def DrawBox(self, event): |
---|
220 | tolerance = 2 |
---|
221 | pt = point(event.pos()) |
---|
222 | dx = pt.x - self.dragStartPos.x |
---|
223 | dy = pt.y - self.dragStartPos.y |
---|
224 | if abs(dx) <= tolerance and abs(dy) <= tolerance: |
---|
225 | return |
---|
226 | self._drawbox = [self.dragStartPos.x, self.dragStartPos.y, dx, dy] |
---|
227 | self.update() |
---|
228 | |
---|
229 | def mouseMoveEvent(self, evt): |
---|
230 | pt = point(evt.pos()) |
---|
231 | buttons = int(evt.buttons()) |
---|
232 | modifiers = evt.modifiers() |
---|
233 | # ROTATE |
---|
234 | if (buttons == QtCore.Qt.LeftButton and not modifiers == QtCore.Qt.ShiftModifier): |
---|
235 | dx = pt.x - self.dragStartPos.x |
---|
236 | dy = pt.y - self.dragStartPos.y |
---|
237 | self._display.Rotation(pt.x, pt.y) |
---|
238 | self._drawbox = False |
---|
239 | # DYNAMIC ZOOM |
---|
240 | elif (buttons == QtCore.Qt.RightButton and not modifiers == QtCore.Qt.ShiftModifier): |
---|
241 | self._display.Repaint() |
---|
242 | self._display.DynamicZoom(abs(self.dragStartPos.x), abs(self.dragStartPos.y), abs(pt.x), abs(pt.y)) |
---|
243 | self.dragStartPos.x = pt.x |
---|
244 | self.dragStartPos.y = pt.y |
---|
245 | self._drawbox = False |
---|
246 | # PAN |
---|
247 | elif buttons == QtCore.Qt.MidButton: |
---|
248 | dx = pt.x - self.dragStartPos.x |
---|
249 | dy = pt.y - self.dragStartPos.y |
---|
250 | self.dragStartPos.x = pt.x |
---|
251 | self.dragStartPos.y = pt.y |
---|
252 | self._display.Pan(dx, -dy) |
---|
253 | self._drawbox = False |
---|
254 | # DRAW BOX |
---|
255 | # ZOOM WINDOW |
---|
256 | elif (buttons == QtCore.Qt.RightButton and modifiers == QtCore.Qt.ShiftModifier): |
---|
257 | self._zoom_area = True |
---|
258 | self.DrawBox(evt) |
---|
259 | # SELECT AREA |
---|
260 | elif (buttons == QtCore.Qt.LeftButton and modifiers == QtCore.Qt.ShiftModifier): |
---|
261 | self._select_area = True |
---|
262 | self.DrawBox(evt) |
---|
263 | else: |
---|
264 | self._drawbox = False |
---|
265 | self._display.MoveTo(pt.x, pt.y) |
---|
266 | |
---|
267 | |
---|
268 | def Test3d(): |
---|
269 | class AppFrame(QtGui.QWidget): |
---|
270 | def __init__(self, parent=None): |
---|
271 | QtGui.QWidget.__init__(self, parent) |
---|
272 | self.setWindowTitle(self.tr("qtDisplay3d sample")) |
---|
273 | self.resize(640, 480) |
---|
274 | self.canva = qtViewer3d(self) |
---|
275 | mainLayout = QtGui.QHBoxLayout() |
---|
276 | mainLayout.addWidget(self.canva) |
---|
277 | mainLayout.setContentsMargins(0, 0, 0, 0) |
---|
278 | self.setLayout(mainLayout) |
---|
279 | |
---|
280 | def runTests(self): |
---|
281 | self.canva._display.Test() |
---|
282 | |
---|
283 | app = QtGui.QApplication(sys.argv) |
---|
284 | frame = AppFrame() |
---|
285 | frame.show() |
---|
286 | frame.canva.InitDriver() |
---|
287 | frame.runTests() |
---|
288 | sys.exit(app.exec_()) |
---|
289 | |
---|
290 | if __name__ == "__main__": |
---|
291 | Test3d() |
---|
292 | |
---|
293 | |
---|