<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">2016-06-27 11:08 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">2016-06-27 9:48 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>2016-06-27 9:09 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>2016-06-26 13:31 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>2016-06-26 13:06 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br></span><span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><div><div><div><div><div><div><div><div>Hi,<br><br>In my quest to create a PyQt5 widget based on QOpenGLWidget for showing/interacting with VTK, I now have something that seems to work (including the whole thing as a runnable example below).<br></div></div></div></div></div></div></div></div></div></div></div></blockquote><div><br></div></span><div>It was a little too early to say "seems to work": When trying to show one of the volumes I need to render, I get<br><br>(gui) [estan@pyret orexplore.gui]$ python -m orexplore.gui.main<br>enabling depth test<br>ERROR: In /home/estan/Blandat/vtk-python3/src/VTK-7.0.0/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx, line 1682<br>vtkGenericOpenGLRenderWindow (0x308c3f0): Hardware does not support the number of textures defined.<br><br>Segmentation fault (core dumped)<br>(gui) [estan@pyret orexplore.gui]$<br><br></div><div>on my Sandybridge laptop :/<br><br></div><div>Anyone know if I'd be able to use the old OpenGL backend here?<span><font color="#888888"><br></font></span></div></div></div></div></blockquote><div><br></div></span><div>I can now confirm that I'm getting the same error on my Haswell work laptop (which is using the OpenGL2 backend) :( Anyone know if there's a way to solve this or what I should look into?<br><br>The volume I'm trying to render is not particularly big (2000x120x120, float), and it renders fine if I use a QGLWidget to back my VTK widget instead of QOpenGLWidget. So I'm suspecting it might have something to do with how I set up my QOpenGLWidget.<br></div></div></div></div></blockquote><div><br></div></span><div>I tried printing the number of texture units in my StartEvent handler with<br><br>    print(self.renderWindow.GetTextureUnitManager().GetNumberOfTextureUnits())<br><br></div><div>and it print 0, so I think something must definitely be wrong with how I initialize things?<span><font color="#888888"><br></font></span></div></div></div></div></blockquote><div><br></div></span><div>I've now tried from C++, with the QVTKWidget3 class from this StackOverflow poster:<br><br>    <a href="http://stackoverflow.com/a/26946040/252857" target="_blank">http://stackoverflow.com/a/26946040/252857</a><br><br></div><div>which was the inspiration for my own QOpenGLWidget-based PyQt5 widget, and I:<br><br></div><div>- Get the same crash on OpenGLInitState as I mentioned in the start of this thread<br><br></div><div>- If I comment the call to OpenGLInitState, I instead get the following crash in VTK when paintGL is called:<span class=""><br><br>(gdb) bt<br>#0  0x0000000000000000 in ?? ()<br></span>#1  0x00007ffff7692efd in vtkOpenGLRenderWindow::ActivateTexture(vtkTextureObject*) () from /opt/VTK-7.0.0/lib/libvtkRenderingOpenGL2-7.0.so.1<br>#2  0x00007ffff76d72c8 in vtkTextureObject::Create3DFromRaw(unsigned int, unsigned int, unsigned int, int, int, void*) ()<br>   from /opt/VTK-7.0.0/lib/libvtkRenderingOpenGL2-7.0.so.1<br>#3  0x00007ffff7ba8485 in vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::LoadVolume(vtkRenderer*, vtkImageData*, vtkVolumeProperty*, vtkDataArray*, int) ()<br>   from /opt/VTK-7.0.0/lib/libvtkRenderingVolumeOpenGL2-7.0.so.1<br>#4  0x00007ffff7bb123d in vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer*, vtkVolume*) () from /opt/VTK-7.0.0/lib/libvtkRenderingVolumeOpenGL2-7.0.so.1<br>#5  0x00007ffff5ac1615 in vtkGPUVolumeRayCastMapper::Render(vtkRenderer*, vtkVolume*) () from /opt/VTK-7.0.0/lib/libvtkRenderingVolume-7.0.so.1<br>#6  0x00007ffff5361331 in vtkVolume::RenderVolumetricGeometry(vtkViewport*) () from /opt/VTK-7.0.0/lib/libvtkRenderingCore-7.0.so.1<br>#7  0x00007ffff7694376 in vtkOpenGLRenderer::UpdateGeometry() () from /opt/VTK-7.0.0/lib/libvtkRenderingOpenGL2-7.0.so.1<br>#8  0x00007ffff7694030 in vtkOpenGLRenderer::DeviceRender() () from /opt/VTK-7.0.0/lib/libvtkRenderingOpenGL2-7.0.so.1<br>#9  0x00007ffff5341017 in vtkRenderer::Render() () from /opt/VTK-7.0.0/lib/libvtkRenderingCore-7.0.so.1<br>#10 0x00007ffff533d4c5 in vtkRendererCollection::Render() () from /opt/VTK-7.0.0/lib/libvtkRenderingCore-7.0.so.1<br>#11 0x00007ffff534705e in vtkRenderWindow::DoStereoRender() () from /opt/VTK-7.0.0/lib/libvtkRenderingCore-7.0.so.1<br>#12 0x00007ffff534923b in vtkRenderWindow::Render() () from /opt/VTK-7.0.0/lib/libvtkRenderingCore-7.0.so.1<br>#13 0x00007ffff7693031 in vtkOpenGLRenderWindow::Render() () from /opt/VTK-7.0.0/lib/libvtkRenderingOpenGL2-7.0.so.1<br>#14 0x00007ffff534ca09 in vtkRenderWindowInteractor::Render() () from /opt/VTK-7.0.0/lib/libvtkRenderingCore-7.0.so.1<br>#15 0x00000000004079dd in QVTKWidget3::paintGL() ()<br>#16 0x00007ffff6e1fdad in QOpenGLWidgetPrivate::invokeUserPaint (this=0x6c77f0) at kernel/qopenglwidget.cpp:812<br>#17 0x00007ffff6e00f88 in QWidget::event (this=0x7fffffffdba0, event=0x7fffffffd080) at kernel/qwidget.cpp:9044<br>#18 0x00007ffff6dbe05c in QApplicationPrivate::notify_helper (this=this@entry=0x643990, receiver=receiver@entry=0x7fffffffdba0, e=e@entry=0x7fffffffd080)<br>    at kernel/qapplication.cpp:3716<br>#19 0x00007ffff6dc3516 in QApplication::notify (this=0x7fffffffdb90, receiver=0x7fffffffdba0, e=0x7fffffffd080) at kernel/qapplication.cpp:3499<br>#20 0x00007ffff64cb62b in QCoreApplication::notifyInternal (this=0x7fffffffdb90, receiver=receiver@entry=0x7fffffffdba0, event=event@entry=0x7fffffffd080)<br>    at kernel/qcoreapplication.cpp:965<br>#21 0x00007ffff6df9a79 in QCoreApplication::sendSpontaneousEvent (event=0x7fffffffd080, receiver=<optimized out>)<br>    at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:227<br>#22 QWidgetPrivate::sendPaintEvent (this=this@entry=0x6c77f0, toBePainted=...) at kernel/qwidget.cpp:5625<br>#23 0x00007ffff6dfa0c1 in QWidgetPrivate::drawWidget (this=0x6c77f0, pdev=0xcc8ea0, rgn=..., offset=..., flags=flags@entry=5, <br>    sharedPainter=sharedPainter@entry=0x0, backingStore=0x808d20) at kernel/qwidget.cpp:5565<br>#24 0x00007ffff6dcb8aa in QWidgetBackingStore::doSync (this=this@entry=0x808d20) at kernel/qwidgetbackingstore.cpp:1226<br>#25 0x00007ffff6dcc0a2 in QWidgetBackingStore::sync (this=0x808d20, exposedWidget=0x7fffffffdba0, exposedRegion=...) at kernel/qwidgetbackingstore.cpp:954<br>#26 0x00007ffff6e1da43 in QWidgetWindow::event (this=0x6b3a30, event=0x7fffffffd7d0) at kernel/qwidgetwindow.cpp:255<br>#27 0x00007ffff6dbe05c in QApplicationPrivate::notify_helper (this=this@entry=0x643990, receiver=receiver@entry=0x6b3a30, e=e@entry=0x7fffffffd7d0)<br>    at kernel/qapplication.cpp:3716<br>#28 0x00007ffff6dc3516 in QApplication::notify (this=0x7fffffffdb90, receiver=0x6b3a30, e=0x7fffffffd7d0) at kernel/qapplication.cpp:3499<br>#29 0x00007ffff64cb62b in QCoreApplication::notifyInternal (this=0x7fffffffdb90, receiver=receiver@entry=0x6b3a30, event=event@entry=0x7fffffffd7d0)<br>    at kernel/qcoreapplication.cpp:965<br>#30 0x00007ffff680e4ec in QCoreApplication::sendSpontaneousEvent (event=0x7fffffffd7d0, receiver=0x6b3a30)<br>    at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:227<br>#31 QGuiApplicationPrivate::processExposeEvent (e=0xc55c10) at kernel/qguiapplication.cpp:2663<br>#32 0x00007ffff680f25d in QGuiApplicationPrivate::processWindowSystemEvent (e=e@entry=0xc55c10) at kernel/qguiapplication.cpp:1658<br>#33 0x00007ffff67f2f38 in QWindowSystemInterface::sendWindowSystemEvents (flags=...) at kernel/qwindowsysteminterface.cpp:625<br>#34 0x00007ffff7ec0070 in userEventSourceDispatch (source=<optimized out>) at eventdispatchers/qeventdispatcher_glib.cpp:70<br>#35 0x00007ffff0643127 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0<br>#36 0x00007ffff0643380 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0<br>#37 0x00007ffff064342c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0<br>#38 0x00007ffff6521a7f in QEventDispatcherGlib::processEvents (this=0x6966d0, flags=...) at kernel/qeventdispatcher_glib.cpp:418<br>#39 0x00007ffff64c8dea in QEventLoop::exec (this=this@entry=0x7fffffffda90, flags=..., flags@entry=...) at kernel/qeventloop.cpp:204<br>#40 0x00007ffff64d0e8c in QCoreApplication::exec () at kernel/qcoreapplication.cpp:1229<br>#41 0x00000000004066e1 in main ()<br><br></div><div>I noticed the crash is in ActivateTexture. Could this be due to the same texture unit problem I saw when using my Python widget?<span class=""><font color="#888888"><br></font></span></div></div></div></div></blockquote><div><br></div><div>I've now made a minimal C++ test case. It uses the QVTKWidget3 class from [1] <a href="http://stackoverflow.com/a/26946040/252857">http://stackoverflow.com/a/26946040/252857</a> , but exhibits the same crashing behavior as my (similar) Python widget.<br><br></div><div>The test case can be downloaded via<br><br>    <a href="https://dl.dropboxusercontent.com/u/22350696/test_vtkwidget3.tar.bz2">https://dl.dropboxusercontent.com/u/22350696/test_vtkwidget3.tar.bz2</a><br><br></div><div>and includes a test volume.<br><br></div><div>Build and run the test case with<br><br>mkdir build<br>cd build<br>cmake ..<br>make<br>./TestVTKWidget3 ../volume.vtk<br><br>By default, the test case uses a plain render window, and works fine.<br><br></div><div>But if you uncomment<br><br># Uncomment to try out QVTKWidget3<br># add_definitions(-DUSE_QVTKWIDGET3)<br><br></div><div>in CMakeLists.txt and rebuild, it will instead use QVTKWidget3 from the above StackOverflow.<br><br></div><div>In this mode the test case either:<br><br></div><div>- Crashes in vtkOpenGLRenderWindow::ActivateTexture, if the OpenGLInitState call in QVTKWidget3 is commented<br></div><div>- Crashes in OpenGLInitState if it is uncommented<br><br></div><div>I would be very grateful if someone could run this test case and see if they can reproduce (preferably on Intel graphics).<br><br></div><div>Elvis<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><span class=""><font color="#888888"><br></font></span></div><span class=""><font color="#888888"><div>Elvis<br><br></div></font></span><div><div class="h5"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><span><font color="#888888"><br></font></span></div><span><font color="#888888"><div>Elvis<br> <br></div></font></span><div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>What I'm doing to configure it is simply:<span><br><br>        # Request OpenGL 3.2 compatibility profile and enable multi-sampling<br></span>        surfaceFormat = QSurfaceFormat.defaultFormat()<span><br>        surfaceFormat.setMajorVersion(3)<br>        surfaceFormat.setMinorVersion(2)<br>        surfaceFormat.setProfile(QSurfaceFormat.CompatibilityProfile)<br>        surfaceFormat.setSamples(8)<br>        self.setFormat(surfaceFormat)<br></span></div><div><br></div><div>The whole reason I'm trying to get QOpenGLWidget working is that QGLWidget does not have a setFormat in PyQt5, since it doesn't wrap functions marked "obsolete" in Qt, and this prevents me from enabling multi-sampling.<br></div><div><br></div><div>Very grateful for any advice from experts on the OpenGL2 backend, as I really need to get this working and move on.<br><br></div><div>I'm attaching my vtk_widget2.py, which shows how I set up rendering into the QOpenGLWidget. Rendering of the cone example at the bottom works, it's just when I'm trying volume rendering using vtkGPUVolumeRayCastMapper that I get the above error.<span><font color="#888888"><br></font></span></div><span><font color="#888888"><div><br></div><div>Elvis<br><br></div></font></span><div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><span><font color="#888888"><br></font></span></div><span><font color="#888888"><div>Elvis<br> <br></div></font></span><div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><div><div><div><div><div><div><div><div><br></div>I do however have two problems (indicated by "FIXME:"s in the code below):<br><br></div>1. When I try to call vtkOpenGLRenderWindow.OpenGLInitState when handling the render window StartEvent (commented out below), similar to how QVTKWidget2 does, I get a segmentation fault:<br><br>(gdb) bt<br>#0  0x0000000000000000 in ?? ()<br>#1  0x00007fffd8ad13b9 in vtkOpenGLRenderWindow::OpenGLInitState() () from /usr/lib/libvtkRenderingOpenGL2.so.1<br>#2  0x00007fffd8de8479 in ?? () from /usr/lib/libvtkRenderingOpenGL2Python35D.so.1<br>#3  0x00007ffff79ba5e9 in PyCFunction_Call () from /usr/lib/libpython3.5m.so.1.0<br>#4  0x00007ffff7a325f1 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#5  0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#6  0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#7  0x00007ffff799db98 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#8  0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#9  0x00007ffff7989d64 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#10 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#11 0x00007ffff7a2a457 in PyEval_CallObjectWithKeywords () from /usr/lib/libpython3.5m.so.1.0<br>#12 0x00007fffe8d905a0 in vtkPythonCommand::Execute(vtkObject*, unsigned long, void*) () from /usr/lib/libvtkWrappingPython35Core.so.1<br>#13 0x00007fffe89ac196 in ?? () from /usr/lib/libvtkCommonCore.so.1<br>#14 0x00007fffdf022a0f in vtkRenderWindow::Render() () from /usr/lib/libvtkRenderingCore.so.1<br>#15 0x00007fffd8ad4461 in vtkOpenGLRenderWindow::Render() () from /usr/lib/libvtkRenderingOpenGL2.so.1<br>#16 0x00007fffdf027498 in vtkRenderWindowInteractor::Start() () from /usr/lib/libvtkRenderingCore.so.1<br>#17 0x00007fffdf3ee789 in ?? () from /usr/lib/libvtkRenderingCorePython35D.so.1<br>#18 0x00007ffff79ba5e9 in PyCFunction_Call () from /usr/lib/libpython3.5m.so.1.0<br>#19 0x00007ffff7a325f1 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#20 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#21 0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#22 0x00007ffff799db98 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#23 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#24 0x00007ffff7989d64 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#25 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#26 0x00007ffff79cfa10 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#27 0x00007ffff79cdde6 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#28 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#29 0x00007ffff7a2c4bc in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#30 0x00007ffff7a32942 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#31 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#32 0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#33 0x00007ffff7a33aeb in PyEval_EvalCode () from /usr/lib/libpython3.5m.so.1.0<br>#34 0x00007ffff7a2802d in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#35 0x00007ffff79ba5e9 in PyCFunction_Call () from /usr/lib/libpython3.5m.so.1.0<br>#36 0x00007ffff7a325f1 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#37 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#38 0x00007ffff7a306e0 in PyEval_EvalFrameEx () from /usr/lib/libpython3.5m.so.1.0<br>#39 0x00007ffff7a339e2 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#40 0x00007ffff7a33ac3 in PyEval_EvalCodeEx () from /usr/lib/libpython3.5m.so.1.0<br>#41 0x00007ffff799db98 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#42 0x00007ffff79730da in PyObject_Call () from /usr/lib/libpython3.5m.so.1.0<br>#43 0x00007ffff7a6af01 in ?? () from /usr/lib/libpython3.5m.so.1.0<br>#44 0x00007ffff7a6b7dc in Py_Main () from /usr/lib/libpython3.5m.so.1.0<br>#45 0x0000000000400ae7 in main ()<br>(gdb)<br><br></div>Sorry for the lack of debugging symbols, but before I recompile VTK with debugging symbols, I thought I'd ask if anyone has an idea what may be the reason for the crash? I haven't seen any adverse effects from not calling this function, but I suspect something is broken? (how can I test?)<br><br></div>2. I can't seem to find a way to properly implement the WindowIsCurrentEvent, WindowIsDirectEvent and WindowSupportsOpenGLEvent render window events. E.g. (from below):<br><br>    def _onWindowIsCurrentEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowIsDirectEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowSupportsOpenGLEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br></div>The callData is a bool* and the handler is expected to write a bool to the pointed memory. I can't see that there's any way to do this from Python (is it possible with ctypes somehow?).<br><br></div>So far I haven't seen any adverse effects from not implementing these three events correctly, but expect something to be broken..?<br><br></div>Thankful for any advice on these two issues, and it would be great if someone could try out the example, with the<br><br>    # self.renderWindow.OpenGLInitState()  # FIXME: Segfaults :(<br><br></div>line uncommented, to confirm the segfault I'm seeing.<br><br></div>Cheers,<br></div>Elvis<br><br><br>from PyQt5.QtCore import Qt, QTimer, QEvent, QSize<br>from PyQt5.QtGui import QSurfaceFormat<br>from PyQt5.QtWidgets import QWidget, QOpenGLWidget<br><br>from vtk import vtkGenericOpenGLRenderWindow<br>from vtk import vtkGenericRenderWindowInteractor<br>from vtk import vtkCommand<br>from vtk import vtkRenderer<br><br>from vtk import VTK_CURSOR_DEFAULT, VTK_CURSOR_ARROW, VTK_CURSOR_SIZENE<br>from vtk import VTK_CURSOR_SIZENW, VTK_CURSOR_SIZESW, VTK_CURSOR_SIZESE<br>from vtk import VTK_CURSOR_SIZENS, VTK_CURSOR_SIZEWE, VTK_CURSOR_SIZEALL<br>from vtk import VTK_CURSOR_HAND, VTK_CURSOR_CROSSHAIR<br><br><br>class VTKWidget(QOpenGLWidget):<br><br>    def __init__(self, surfaceFormat=QSurfaceFormat.defaultFormat(), *args, **kwargs):<br>        super().__init__(*args, **kwargs)<br><br>        # Request OpenGL 3.2 compatibility profile and enable multi-sampling<br>        surfaceFormat.setMajorVersion(3)<br>        surfaceFormat.setMinorVersion(2)<br>        surfaceFormat.setProfile(QSurfaceFormat.CompatibilityProfile)<br>        surfaceFormat.setSamples(8)<br>        self.setFormat(surfaceFormat)<br><br>        # Create render window<br>        self.renderWindow = vtkGenericOpenGLRenderWindow()<br>        self.renderWindow.SetSize(self.width(), self.height())<br>        self.renderWindow.SetPosition(self.x(), self.y())<br><br>        self.renderWindow.AddObserver(vtkCommand.StartEvent,<br>                                      self._onStartEvent)<br>        self.renderWindow.AddObserver(vtkCommand.EndEvent,<br>                                      self._onEndEvent)<br>        self.renderWindow.AddObserver(vtkCommand.CursorChangedEvent,<br>                                      self._onCursorChangedEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowMakeCurrentEvent,<br>                                      self._onWindowMakeCurrentEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowIsCurrentEvent,<br>                                      self._onWindowIsCurrentEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowFrameEvent,<br>                                      self._onWindowFrameEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowIsDirectEvent,<br>                                      self._onWindowIsDirectEvent)<br>        self.renderWindow.AddObserver(vtkCommand.WindowSupportsOpenGLEvent,<br>                                      self._onWindowSupportsOpenGLEvent)<br><br>        # Create interactor<br>        self.interactor = vtkGenericRenderWindowInteractor()<br>        self.interactor.SetRenderWindow(self.renderWindow)<br>        self.interactor.SetSize(self.width(), self.height())<br>        self.interactor.AddObserver(vtkCommand.CreateTimerEvent,<br>                                    lambda *_: self._timer.start(10))<br>        self.interactor.AddObserver(vtkCommand.DestroyTimerEvent,<br>                                    lambda *_: self._timer.stop())<br>        self.interactor.Start()<br><br>        # Create renderer<br>        self.renderer = vtkRenderer()<br>        self.renderWindow.AddRenderer(self.renderer)<br><br>        # Timer for the interactor<br>        self._timer = QTimer(self)<br>        self._timer.timeout.connect(self.interactor.TimerEvent)<br><br>        # Some tracked input state<br>        self._pressedButton = Qt.NoButton<br>        self._lastMouseX = 0<br>        self._lastMouseY = 0<br>        self._lastModifiers = Qt.NoModifier<br>        self._lastButtons = Qt.NoButton<br>        self._wheelDelta = 0<br><br>        # Finalize render window before we're destroyed<br>        self._hidden = QWidget(self)<br>        self._hidden.hide()<br>        self._hidden.destroyed.connect(self.renderWindow.Finalize)<br><br>    #<br>    # Handle VTK render window events<br>    #<br><br>    def _onStartEvent(self, *_):<br>        self.makeCurrent()<br>        self.renderWindow.PushState()<br>        # self.renderWindow.OpenGLInitState()  # FIXME: Segfaults :(<br><br>    def _onEndEvent(self, *_):<br>        self.renderWindow.PopState()<br><br>    def _onWindowMakeCurrentEvent(self, *_):<br>        pass  # Handled automatically by QOpenGLWidget<br><br>    def _onWindowIsCurrentEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowIsDirectEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowSupportsOpenGLEvent(self, sender, event, callData):<br>        callData = True  # FIXME: This won't work...<br><br>    def _onWindowFrameEvent(self, *_):<br>        if self.renderWindow.GetSwapBuffers():<br>            self.update()<br><br>    def _onCursorChangedEvent(self):<br><br>        def showCursor():<br>            vtkCursor = self.renderWindow.GetCurrentCursor()<br>            qtCursor = VTKWidget._cursors.get(vtkCursor, Qt.ArrowCursor)<br>            self.setCursor(qtCursor)<br><br>        # Defer until cursor has actually changed<br>        QTimer.singleShot(0, showCursor)<br><br>    #<br>    # Implement QOpenGLWidget functions<br>    #<br><br>    def initializeGL(self):<br>        self.renderWindow.OpenGLInitContext()<br><br>    def paintGL(self):<br>        self.interactor.Render()<br><br>    def resizeGL(self, width, height):<br>        self.renderWindow.SetSize(width, height)<br>        self.interactor.SetSize(width, height)<br>        self.interactor.ConfigureEvent()<br><br>    #<br>    # Handle QWidget events<br>    #<br><br>    def closeEvent(self, _):<br>        self.renderWindow.Finalize()<br><br>    def sizeHint(self):<br>        return QSize(400, 400)<br><br>    def moveEvent(self, event):<br>        super().moveEvent(event)<br>        self.renderWindow.SetPosition(self.x(), self.y())<br><br>    def enterEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, chr(0), 0, None)<br>        self.interactor.EnterEvent()<br><br>    def leaveEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, chr(0), 0, None)<br>        self.interactor.LeaveEvent()<br><br>    def mousePressEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        repeat = 1 if event.type() == QEvent.MouseButtonDblClick else 0<br>        self.interactor.SetEventInformationFlipY(event.x(), event.y(), ctrl, shift,<br>                                                 chr(0), repeat, None)<br><br>        self._pressedButton = event.button()<br><br>        if self._pressedButton == Qt.LeftButton:<br>            self.interactor.LeftButtonPressEvent()<br>        elif self._pressedButton == Qt.RightButton:<br>            self.interactor.RightButtonPressEvent()<br>        elif self._pressedButton == Qt.MidButton:<br>            self.interactor.MiddleButtonPressEvent()<br><br>    def mouseReleaseEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(event.x(), event.y(), ctrl, shift,<br>                                                 chr(0), 0, None)<br><br>        if self._pressedButton == Qt.LeftButton:<br>            self.interactor.LeftButtonReleaseEvent()<br>        elif self._pressedButton == Qt.RightButton:<br>            self.interactor.RightButtonReleaseEvent()<br>        elif self._pressedButton == Qt.MidButton:<br>            self.interactor.MiddleButtonReleaseEvent()<br><br>        self._pressedButton = Qt.NoButton<br><br>    def mouseMoveEvent(self, event):<br>        self._lastModifiers = event.modifiers()<br>        self._lastButtons = event.buttons()<br>        self._lastMouseX = event.x()<br>        self._lastMouseY = event.y()<br><br>        ctrl, shift = self._modifiers(event)<br>        self.interactor.SetEventInformationFlipY(event.x(), event.y(), ctrl, shift,<br>                                                 chr(0), 0, None)<br>        self.interactor.MouseMoveEvent()<br><br>    def keyPressEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        key = str(event.text()) if event.key() < 256 else chr(0)<br>        keySym = VTKWidget._qtKeyToKeySymbol(event.key())<br><br>        if shift and len(keySym) == 1 and keySym.isalpha():<br>            keySym = keySym.upper()<br><br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, key, 0, keySym)<br>        self.interactor.KeyPressEvent()<br>        self.interactor.CharEvent()<br><br>    def keyReleaseEvent(self, event):<br>        ctrl, shift = self._modifiers(event)<br>        key = chr(event.key()) if event.key() < 256 else chr(0)<br><br>        self.interactor.SetEventInformationFlipY(self._lastMouseX, self._lastMouseY,<br>                                                 ctrl, shift, key, 0, None)<br>        self.interactor.KeyReleaseEvent()<br><br>    def wheelEvent(self, event):<br>        self._wheelDelta += event.angleDelta().y()<br><br>        if self._wheelDelta >= 120:<br>            self.interactor.MouseWheelForwardEvent()<br>            self._wheelDelta = 0<br>        elif self._wheelDelta <= -120:<br>            self.interactor.MouseWheelBackwardEvent()<br>            self._wheelDelta = 0<br><br>    def _modifiers(self, event):<br>        ctrl = shift = False<br><br>        if hasattr(event, 'modifiers'):<br>            if event.modifiers() & Qt.ShiftModifier:<br>                shift = True<br>            if event.modifiers() & Qt.ControlModifier:<br>                ctrl = True<br>        else:<br>            if self._lastModifiers & Qt.ShiftModifier:<br>                shift = True<br>            if self._lastModifiers & Qt.ControlModifier:<br>                ctrl = True<br><br>        return ctrl, shift<br><br>    @classmethod<br>    def _qtKeyToKeySymbol(cls, key):<br>        if key not in VTKWidget._keySymbols:<br>            return None<br>        return VTKWidget._keySymbols[key]<br><br>    # Maps VTK cursors to Qt cursors<br>    _cursors = {<br>        VTK_CURSOR_DEFAULT: Qt.ArrowCursor,<br>        VTK_CURSOR_ARROW: Qt.ArrowCursor,<br>        VTK_CURSOR_SIZENE: Qt.SizeBDiagCursor,<br>        VTK_CURSOR_SIZENW: Qt.SizeFDiagCursor,<br>        VTK_CURSOR_SIZESW: Qt.SizeBDiagCursor,<br>        VTK_CURSOR_SIZESE: Qt.SizeFDiagCursor,<br>        VTK_CURSOR_SIZENS: Qt.SizeVerCursor,<br>        VTK_CURSOR_SIZEWE: Qt.SizeHorCursor,<br>        VTK_CURSOR_SIZEALL: Qt.SizeAllCursor,<br>        VTK_CURSOR_HAND: Qt.PointingHandCursor,<br>        VTK_CURSOR_CROSSHAIR: Qt.CrossCursor<br>    }<br><br>    # Maps Qt keys to VTK key symbols<br>    _keySymbols = {<br>        Qt.Key_Backspace: 'BackSpace',<br>        Qt.Key_Tab: 'Tab',<br>        Qt.Key_Backtab: 'Tab',<br>        # Qt.Key_Clear : 'Clear',<br>        Qt.Key_Return: 'Return',<br>        Qt.Key_Enter: 'Return',<br>        Qt.Key_Shift: 'Shift_L',<br>        Qt.Key_Control: 'Control_L',<br>        Qt.Key_Alt: 'Alt_L',<br>        Qt.Key_Pause: 'Pause',<br>        Qt.Key_CapsLock: 'Caps_Lock',<br>        Qt.Key_Escape: 'Escape',<br>        Qt.Key_Space: 'space',<br>        # Qt.Key_Prior : 'Prior',<br>        # Qt.Key_Next : 'Next',<br>        Qt.Key_End: 'End',<br>        Qt.Key_Home: 'Home',<br>        Qt.Key_Left: 'Left',<br>        Qt.Key_Up: 'Up',<br>        Qt.Key_Right: 'Right',<br>        Qt.Key_Down: 'Down',<br>        Qt.Key_SysReq: 'Snapshot',<br>        Qt.Key_Insert: 'Insert',<br>        Qt.Key_Delete: 'Delete',<br>        Qt.Key_Help: 'Help',<br>        Qt.Key_0: '0',<br>        Qt.Key_1: '1',<br>        Qt.Key_2: '2',<br>        Qt.Key_3: '3',<br>        Qt.Key_4: '4',<br>        Qt.Key_5: '5',<br>        Qt.Key_6: '6',<br>        Qt.Key_7: '7',<br>        Qt.Key_8: '8',<br>        Qt.Key_9: '9',<br>        Qt.Key_A: 'a',<br>        Qt.Key_B: 'b',<br>        Qt.Key_C: 'c',<br>        Qt.Key_D: 'd',<br>        Qt.Key_E: 'e',<br>        Qt.Key_F: 'f',<br>        Qt.Key_G: 'g',<br>        Qt.Key_H: 'h',<br>        Qt.Key_I: 'i',<br>        Qt.Key_J: 'j',<br>        Qt.Key_K: 'k',<br>        Qt.Key_L: 'l',<br>        Qt.Key_M: 'm',<br>        Qt.Key_N: 'n',<br>        Qt.Key_O: 'o',<br>        Qt.Key_P: 'p',<br>        Qt.Key_Q: 'q',<br>        Qt.Key_R: 'r',<br>        Qt.Key_S: 's',<br>        Qt.Key_T: 't',<br>        Qt.Key_U: 'u',<br>        Qt.Key_V: 'v',<br>        Qt.Key_W: 'w',<br>        Qt.Key_X: 'x',<br>        Qt.Key_Y: 'y',<br>        Qt.Key_Z: 'z',<br>        Qt.Key_Asterisk: 'asterisk',<br>        Qt.Key_Plus: 'plus',<br>        Qt.Key_Minus: 'minus',<br>        Qt.Key_Period: 'period',<br>        Qt.Key_Slash: 'slash',<br>        Qt.Key_F1: 'F1',<br>        Qt.Key_F2: 'F2',<br>        Qt.Key_F3: 'F3',<br>        Qt.Key_F4: 'F4',<br>        Qt.Key_F5: 'F5',<br>        Qt.Key_F6: 'F6',<br>        Qt.Key_F7: 'F7',<br>        Qt.Key_F8: 'F8',<br>        Qt.Key_F9: 'F9',<br>        Qt.Key_F10: 'F10',<br>        Qt.Key_F11: 'F11',<br>        Qt.Key_F12: 'F12',<br>        Qt.Key_F13: 'F13',<br>        Qt.Key_F14: 'F14',<br>        Qt.Key_F15: 'F15',<br>        Qt.Key_F16: 'F16',<br>        Qt.Key_F17: 'F17',<br>        Qt.Key_F18: 'F18',<br>        Qt.Key_F19: 'F19',<br>        Qt.Key_F20: 'F20',<br>        Qt.Key_F21: 'F21',<br>        Qt.Key_F22: 'F22',<br>        Qt.Key_F23: 'F23',<br>        Qt.Key_F24: 'F24',<br>        Qt.Key_NumLock: 'Num_Lock',<br>        Qt.Key_ScrollLock: 'Scroll_Lock'<br>    }<br><br>def example():<br>    #<br>    # Try out VTKWidget by showing a couple of cones<br>    #<br>    from sys import argv, exit<br>    from PyQt5.QtWidgets import QApplication, QVBoxLayout<br>    from vtk import vtkConeSource, vtkPolyDataMapper, vtkActor<br><br>    app = QApplication(argv)<br><br>    layout = QVBoxLayout()<br><br>    for i in range(2):<br>        widget = VTKWidget()<br><br>        coneSource = vtkConeSource()<br>        coneSource.SetResolution(8)<br><br>        coneMapper = vtkPolyDataMapper()<br>        coneMapper.SetInputConnection(coneSource.GetOutputPort())<br><br>        coneActor = vtkActor()<br>        coneActor.SetMapper(coneMapper)<br><br>        widget.renderer.AddActor(coneActor)<br><br>        layout.addWidget(widget)<br><br>    container = QWidget()<br>    container.setLayout(layout)<br>    container.show()<br><br>    exit(app.exec_())<br><br><br>if __name__ == '__main__':<br>    example()<br><br></div>
</blockquote></div></div></div><br></div></div>
</blockquote></div></div></div><br></div></div>
</blockquote></div></div></div><br></div></div>
</blockquote></div></div></div><br></div></div>
</blockquote></div><br></div></div>