GtkVTKRenderWindow.py 18 KB

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