GtkGLExtVTKRenderWindow.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. """
  2. Description:
  3. This provides a VTK widget for pyGtk. This embeds a vtkRenderWindow
  4. inside a GTK widget. This is based on GtkVTKRenderWindow.py.
  5. The extensions here allow the use of gtkglext rather than gtkgl and
  6. pygtk-2 rather than pygtk-0. It requires pygtk-2.0.0 or later.
  7. There is a working example at the bottom.
  8. Credits:
  9. John Hunter <jdhunter@ace.bsd.uchicago.edu> developed and tested
  10. this code based on VTK's GtkVTKRenderWindow.py and extended it to
  11. work with pygtk-2.0.0.
  12. License:
  13. VTK license.
  14. """
  15. import math, sys
  16. import pygtk
  17. pygtk.require('2.0')
  18. import gtk
  19. import gtk.gtkgl
  20. from gtk import gdk
  21. from vtkmodules.vtkRenderingCore import vtkActor, vtkCellPicker, vtkProperty, vtkRenderWindow
  22. class GtkGLExtVTKRenderWindowBase(gtk.gtkgl.DrawingArea):
  23. """ A base class that enables one to embed a vtkRenderWindow into
  24. a pyGTK widget. This class embeds the RenderWindow correctly.
  25. Provided are some empty methods that can be overloaded to provide
  26. a user defined interaction behaviour. The event handling
  27. functions have names that are somewhat similar to the ones in the
  28. vtkInteractorStyle class included with VTK. """
  29. def __init__(self, *args):
  30. gtk.gtkgl.DrawingArea.__init__(self)
  31. self.set_double_buffered(gtk.FALSE)
  32. self._RenderWindow = vtkRenderWindow()
  33. # private attributes
  34. self.__Created = 0
  35. # used by the LOD actors
  36. self._DesiredUpdateRate = 15
  37. self._StillUpdateRate = 0.0001
  38. self.ConnectSignals()
  39. # need this to be able to handle key_press events.
  40. self.set_flags(gtk.CAN_FOCUS)
  41. # default size
  42. self.set_size_request(300, 300)
  43. def ConnectSignals(self):
  44. self.connect("realize", self.OnRealize)
  45. self.connect("expose_event", self.OnExpose)
  46. self.connect("configure_event", self.OnConfigure)
  47. self.connect("button_press_event", self.OnButtonDown)
  48. self.connect("button_release_event", self.OnButtonUp)
  49. self.connect("motion_notify_event", self.OnMouseMove)
  50. self.connect("enter_notify_event", self.OnEnter)
  51. self.connect("leave_notify_event", self.OnLeave)
  52. self.connect("key_press_event", self.OnKeyPress)
  53. self.connect("delete_event", self.OnDestroy)
  54. self.add_events(gdk.EXPOSURE_MASK|
  55. gdk.BUTTON_PRESS_MASK |
  56. gdk.BUTTON_RELEASE_MASK |
  57. gdk.KEY_PRESS_MASK |
  58. gdk.POINTER_MOTION_MASK |
  59. gdk.POINTER_MOTION_HINT_MASK |
  60. gdk.ENTER_NOTIFY_MASK |
  61. gdk.LEAVE_NOTIFY_MASK)
  62. def GetRenderWindow(self):
  63. return self._RenderWindow
  64. def GetRenderer(self):
  65. self._RenderWindow.GetRenderers().InitTraversal()
  66. return self._RenderWindow.GetRenderers().GetNextItem()
  67. def SetDesiredUpdateRate(self, rate):
  68. """Mirrors the method with the same name in
  69. vtkRenderWindowInteractor."""
  70. self._DesiredUpdateRate = rate
  71. def GetDesiredUpdateRate(self):
  72. """Mirrors the method with the same name in
  73. vtkRenderWindowInteractor."""
  74. return self._DesiredUpdateRate
  75. def SetStillUpdateRate(self, rate):
  76. """Mirrors the method with the same name in
  77. vtkRenderWindowInteractor."""
  78. self._StillUpdateRate = rate
  79. def GetStillUpdateRate(self):
  80. """Mirrors the method with the same name in
  81. vtkRenderWindowInteractor."""
  82. return self._StillUpdateRate
  83. def Render(self):
  84. if self.__Created:
  85. self._RenderWindow.Render()
  86. def OnRealize(self, *args):
  87. if self.__Created == 0:
  88. # you can't get the xid without the window being realized.
  89. self.realize()
  90. if sys.platform=='win32':
  91. win_id = str(self.widget.window.handle)
  92. else:
  93. win_id = str(self.widget.window.xid)
  94. self._RenderWindow.SetWindowInfo(win_id)
  95. self.__Created = 1
  96. return gtk.TRUE
  97. def Created(self):
  98. return self.__Created
  99. def OnConfigure(self, widget, event):
  100. self.widget=widget
  101. self._RenderWindow.SetSize(event.width, event.height)
  102. self.Render()
  103. return gtk.TRUE
  104. def OnExpose(self, *args):
  105. self.Render()
  106. return gtk.TRUE
  107. def OnDestroy(self, *args):
  108. self.hide()
  109. del self._RenderWindow
  110. self.destroy()
  111. return gtk.TRUE
  112. def OnButtonDown(self, wid, event):
  113. """Mouse button pressed."""
  114. self._RenderWindow.SetDesiredUpdateRate(self._DesiredUpdateRate)
  115. return gtk.TRUE
  116. def OnButtonUp(self, wid, event):
  117. """Mouse button released."""
  118. self._RenderWindow.SetDesiredUpdateRate(self._StillUpdateRate)
  119. return gtk.TRUE
  120. def OnMouseMove(self, wid, event):
  121. """Mouse has moved."""
  122. return gtk.TRUE
  123. def OnEnter(self, wid, event):
  124. """Entering the vtkRenderWindow."""
  125. return gtk.TRUE
  126. def OnLeave(self, wid, event):
  127. """Leaving the vtkRenderWindow."""
  128. return gtk.TRUE
  129. def OnKeyPress(self, wid, event):
  130. """Key pressed."""
  131. return gtk.TRUE
  132. def OnKeyRelease(self, wid, event):
  133. "Key released."
  134. return gtk.TRUE
  135. class GtkGLExtVTKRenderWindow(GtkGLExtVTKRenderWindowBase):
  136. """ An example of a fully functional GtkGLExtVTKRenderWindow that
  137. is based on the vtkRenderWidget.py provided with the VTK
  138. sources."""
  139. def __init__(self, *args):
  140. GtkGLExtVTKRenderWindowBase.__init__(self)
  141. self._CurrentRenderer = None
  142. self._CurrentCamera = None
  143. self._CurrentZoom = 1.0
  144. self._CurrentLight = None
  145. self._ViewportCenterX = 0
  146. self._ViewportCenterY = 0
  147. self._Picker = vtkCellPicker()
  148. self._PickedAssembly = None
  149. self._PickedProperty = vtkProperty()
  150. self._PickedProperty.SetColor(1, 0, 0)
  151. self._PrePickedProperty = None
  152. self._OldFocus = None
  153. # these record the previous mouse position
  154. self._LastX = 0
  155. self._LastY = 0
  156. def OnButtonDown(self, wid, event):
  157. self._RenderWindow.SetDesiredUpdateRate(self._DesiredUpdateRate)
  158. return self.StartMotion(wid, event)
  159. return gtk.TRUE
  160. def OnButtonUp(self, wid, event):
  161. self._RenderWindow.SetDesiredUpdateRate(self._StillUpdateRate)
  162. return self.EndMotion(wid, event)
  163. return gtk.TRUE
  164. def OnMouseMove(self, wid, event=None):
  165. if ((event.state & gdk.BUTTON1_MASK) == gdk.BUTTON1_MASK):
  166. if ((event.state & gdk.SHIFT_MASK) == gdk.SHIFT_MASK):
  167. m = self.get_pointer()
  168. self.Pan(m[0], m[1])
  169. else:
  170. m = self.get_pointer()
  171. self.Rotate(m[0], m[1])
  172. elif ((event.state & gdk.BUTTON2_MASK) == gdk.BUTTON2_MASK):
  173. m = self.get_pointer()
  174. self.Pan(m[0], m[1])
  175. elif ((event.state & gdk.BUTTON3_MASK) == gdk.BUTTON3_MASK):
  176. m = self.get_pointer()
  177. self.Zoom(m[0], m[1])
  178. else:
  179. return gtk.FALSE
  180. return gtk.TRUE
  181. def OnEnter(self, wid, event=None):
  182. # a render hack because grab_focus blanks the renderwin
  183. self.grab_focus()
  184. w = self.get_pointer()
  185. self.UpdateRenderer(w[0], w[1])
  186. return gtk.TRUE
  187. def OnKeyPress(self, wid, event=None):
  188. #if (event.keyval == gdk.keyval_from_name("q") or
  189. # event.keyval == gdk.keyval_from_name("Q")):
  190. # gtk.mainquit()
  191. if (event.keyval == gdk.keyval_from_name('r') or
  192. event.keyval == gdk.keyval_from_name('R')):
  193. self.Reset()
  194. return gtk.TRUE
  195. elif (event.keyval == gdk.keyval_from_name('w') or
  196. event.keyval == gdk.keyval_from_name('W')):
  197. self.Wireframe()
  198. return gtk.TRUE
  199. elif (event.keyval == gdk.keyval_from_name('s') or
  200. event.keyval == gdk.keyval_from_name('S')):
  201. self.Surface()
  202. return gtk.TRUE
  203. elif (event.keyval == gdk.keyval_from_name('p') or
  204. event.keyval == gdk.keyval_from_name('P')):
  205. m = self.get_pointer()
  206. self.PickActor(m[0], m[1])
  207. return gtk.TRUE
  208. else:
  209. return gtk.FALSE
  210. def GetZoomFactor(self):
  211. return self._CurrentZoom
  212. def SetZoomFactor(self, zf):
  213. self._CurrentZoom = zf
  214. def GetPicker(self):
  215. return self._Picker
  216. def Render(self):
  217. if (self._CurrentLight):
  218. light = self._CurrentLight
  219. light.SetPosition(self._CurrentCamera.GetPosition())
  220. light.SetFocalPoint(self._CurrentCamera.GetFocalPoint())
  221. GtkGLExtVTKRenderWindowBase.Render(self)
  222. def UpdateRenderer(self,x,y):
  223. """
  224. UpdateRenderer will identify the renderer under the mouse and set
  225. up _CurrentRenderer, _CurrentCamera, and _CurrentLight.
  226. """
  227. windowX,windowY = self.widget.window.get_size()
  228. renderers = self._RenderWindow.GetRenderers()
  229. numRenderers = renderers.GetNumberOfItems()
  230. self._CurrentRenderer = None
  231. renderers.InitTraversal()
  232. for i in range(0,numRenderers):
  233. renderer = renderers.GetNextItem()
  234. vx,vy = (0,0)
  235. if (windowX > 1):
  236. vx = float(x)/(windowX-1)
  237. if (windowY > 1):
  238. vy = (windowY-float(y)-1)/(windowY-1)
  239. (vpxmin,vpymin,vpxmax,vpymax) = renderer.GetViewport()
  240. if (vx >= vpxmin and vx <= vpxmax and
  241. vy >= vpymin and vy <= vpymax):
  242. self._CurrentRenderer = renderer
  243. self._ViewportCenterX = float(windowX)*(vpxmax-vpxmin)/2.0\
  244. +vpxmin
  245. self._ViewportCenterY = float(windowY)*(vpymax-vpymin)/2.0\
  246. +vpymin
  247. self._CurrentCamera = self._CurrentRenderer.GetActiveCamera()
  248. lights = self._CurrentRenderer.GetLights()
  249. lights.InitTraversal()
  250. self._CurrentLight = lights.GetNextItem()
  251. break
  252. self._LastX = x
  253. self._LastY = y
  254. def GetCurrentRenderer(self):
  255. if self._CurrentRenderer is None:
  256. renderers = self._RenderWindow.GetRenderers()
  257. numRenderers = renderers.GetNumberOfItems()
  258. renderers.InitTraversal()
  259. for i in range(0,numRenderers):
  260. renderer = renderers.GetNextItem()
  261. break
  262. self._CurrentRenderer = renderer
  263. return self._CurrentRenderer
  264. def GetCurrentCamera(self):
  265. if self._CurrentCamera is None:
  266. renderer = self.GetCurrentRenderer()
  267. self._CurrentCamera = renderer.GetActiveCamera()
  268. return self._CurrentCamera
  269. def StartMotion(self, wid, event=None):
  270. x = event.x
  271. y = event.y
  272. self.UpdateRenderer(x,y)
  273. return gtk.TRUE
  274. def EndMotion(self, wid, event=None):
  275. if self._CurrentRenderer:
  276. self.Render()
  277. return gtk.TRUE
  278. def Rotate(self,x,y):
  279. if self._CurrentRenderer:
  280. self._CurrentCamera.Azimuth(self._LastX - x)
  281. self._CurrentCamera.Elevation(y - self._LastY)
  282. self._CurrentCamera.OrthogonalizeViewUp()
  283. self._LastX = x
  284. self._LastY = y
  285. self._CurrentRenderer.ResetCameraClippingRange()
  286. self.Render()
  287. def Pan(self,x,y):
  288. if self._CurrentRenderer:
  289. renderer = self._CurrentRenderer
  290. camera = self._CurrentCamera
  291. (pPoint0,pPoint1,pPoint2) = camera.GetPosition()
  292. (fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
  293. if (camera.GetParallelProjection()):
  294. renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
  295. renderer.WorldToDisplay()
  296. fx,fy,fz = renderer.GetDisplayPoint()
  297. renderer.SetDisplayPoint(fx-x+self._LastX,
  298. fy+y-self._LastY,
  299. fz)
  300. renderer.DisplayToWorld()
  301. fx,fy,fz,fw = renderer.GetWorldPoint()
  302. camera.SetFocalPoint(fx,fy,fz)
  303. renderer.SetWorldPoint(pPoint0,pPoint1,pPoint2,1.0)
  304. renderer.WorldToDisplay()
  305. fx,fy,fz = renderer.GetDisplayPoint()
  306. renderer.SetDisplayPoint(fx-x+self._LastX,
  307. fy+y-self._LastY,
  308. fz)
  309. renderer.DisplayToWorld()
  310. fx,fy,fz,fw = renderer.GetWorldPoint()
  311. camera.SetPosition(fx,fy,fz)
  312. else:
  313. (fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
  314. # Specify a point location in world coordinates
  315. renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
  316. renderer.WorldToDisplay()
  317. # Convert world point coordinates to display coordinates
  318. dPoint = renderer.GetDisplayPoint()
  319. focalDepth = dPoint[2]
  320. aPoint0 = self._ViewportCenterX + (x - self._LastX)
  321. aPoint1 = self._ViewportCenterY - (y - self._LastY)
  322. renderer.SetDisplayPoint(aPoint0,aPoint1,focalDepth)
  323. renderer.DisplayToWorld()
  324. (rPoint0,rPoint1,rPoint2,rPoint3) = renderer.GetWorldPoint()
  325. if (rPoint3 != 0.0):
  326. rPoint0 = rPoint0/rPoint3
  327. rPoint1 = rPoint1/rPoint3
  328. rPoint2 = rPoint2/rPoint3
  329. camera.SetFocalPoint((fPoint0 - rPoint0) + fPoint0,
  330. (fPoint1 - rPoint1) + fPoint1,
  331. (fPoint2 - rPoint2) + fPoint2)
  332. camera.SetPosition((fPoint0 - rPoint0) + pPoint0,
  333. (fPoint1 - rPoint1) + pPoint1,
  334. (fPoint2 - rPoint2) + pPoint2)
  335. self._LastX = x
  336. self._LastY = y
  337. self.Render()
  338. def Zoom(self,x,y):
  339. if self._CurrentRenderer:
  340. renderer = self._CurrentRenderer
  341. camera = self._CurrentCamera
  342. zoomFactor = math.pow(1.02,(0.5*(self._LastY - y)))
  343. self._CurrentZoom = self._CurrentZoom * zoomFactor
  344. if camera.GetParallelProjection():
  345. parallelScale = camera.GetParallelScale()/zoomFactor
  346. camera.SetParallelScale(parallelScale)
  347. else:
  348. camera.Dolly(zoomFactor)
  349. renderer.ResetCameraClippingRange()
  350. self._LastX = x
  351. self._LastY = y
  352. self.Render()
  353. def Reset(self):
  354. if self._CurrentRenderer:
  355. self._CurrentRenderer.ResetCamera()
  356. self.Render()
  357. def Wireframe(self):
  358. actors = self._CurrentRenderer.GetActors()
  359. numActors = actors.GetNumberOfItems()
  360. actors.InitTraversal()
  361. for i in range(0,numActors):
  362. actor = actors.GetNextItem()
  363. actor.GetProperty().SetRepresentationToWireframe()
  364. self.Render()
  365. def Surface(self):
  366. actors = self._CurrentRenderer.GetActors()
  367. numActors = actors.GetNumberOfItems()
  368. actors.InitTraversal()
  369. for i in range(0,numActors):
  370. actor = actors.GetNextItem()
  371. actor.GetProperty().SetRepresentationToSurface()
  372. self.Render()
  373. def PickActor(self,x,y):
  374. if self._CurrentRenderer:
  375. renderer = self._CurrentRenderer
  376. picker = self._Picker
  377. windowX,windowY = self.widget.window.get_size()
  378. picker.Pick(x,(windowY - y - 1),0.0,renderer)
  379. assembly = picker.GetAssembly()
  380. if (self._PickedAssembly != None and
  381. self._PrePickedProperty != None):
  382. self._PickedAssembly.SetProperty(self._PrePickedProperty)
  383. # release hold of the property
  384. self._PrePickedProperty.UnRegister(self._PrePickedProperty)
  385. self._PrePickedProperty = None
  386. if (assembly != None):
  387. self._PickedAssembly = assembly
  388. self._PrePickedProperty = self._PickedAssembly.GetProperty()
  389. # hold onto the property
  390. self._PrePickedProperty.Register(self._PrePickedProperty)
  391. self._PickedAssembly.SetProperty(self._PickedProperty)
  392. self.Render()
  393. def main():
  394. from vtkmodules.vtkFiltersSources import vtkConeSource
  395. from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer
  396. # load implementations for rendering and interaction factory classes
  397. import vtkmodules.vtkRenderingOpenGL2
  398. import vtkmodules.vtkInteractionStyle
  399. # The main window
  400. window = gtk.Window()
  401. window.set_title("A GtkGLExtVTKRenderWindow Demo!")
  402. window.connect("destroy", gtk.mainquit)
  403. window.connect("delete_event", gtk.mainquit)
  404. window.set_border_width(10)
  405. vtkgtk = GtkGLExtVTKRenderWindow()
  406. vtkgtk.show()
  407. vbox = gtk.VBox(spacing=3)
  408. vbox.show()
  409. vbox.pack_start(vtkgtk)
  410. button = gtk.Button('My Button')
  411. button.show()
  412. vbox.pack_start(button)
  413. window.add(vbox)
  414. window.set_size_request(400, 400)
  415. # The VTK stuff.
  416. cone = vtkConeSource()
  417. cone.SetResolution(80)
  418. coneMapper = vtkPolyDataMapper()
  419. coneMapper.SetInputConnection(cone.GetOutputPort())
  420. #coneActor = vtkLODActor()
  421. coneActor = vtkActor()
  422. coneActor.SetMapper(coneMapper)
  423. coneActor.GetProperty().SetColor(0.5, 0.5, 1.0)
  424. ren = vtkRenderer()
  425. vtkgtk.GetRenderWindow().AddRenderer(ren)
  426. ren.AddActor(coneActor)
  427. # show the main window and start event processing.
  428. window.show()
  429. gtk.mainloop()
  430. if __name__ == "__main__":
  431. main()