1#!/usr/bin/env python
2
3# A game with VTK and tkinter. :)
4
5import sys
6if sys.hexversion < 0x03000000:
7    # for Python2
8    import Tkinter as tkinter
9else:
10    # for Python3
11    import tkinter
12import vtk
13from vtk.tk.vtkTkRenderWindowInteractor import vtkTkRenderWindowInteractor
14
15# Create the pipeline
16puzzle = vtk.vtkSpherePuzzle()
17mapper = vtk.vtkPolyDataMapper()
18mapper.SetInputConnection(puzzle.GetOutputPort())
19actor = vtk.vtkActor()
20actor.SetMapper(mapper)
21
22arrows = vtk.vtkSpherePuzzleArrows()
23mapper2 = vtk.vtkPolyDataMapper()
24mapper2.SetInputConnection(arrows.GetOutputPort())
25actor2 = vtk.vtkActor()
26actor2.SetMapper(mapper2)
27
28renWin = vtk.vtkRenderWindow()
29ren = vtk.vtkRenderer()
30renWin.AddRenderer(ren)
31
32# Add the actors to the renderer, set the background and size
33ren.AddActor(actor)
34ren.AddActor(actor2)
35ren.SetBackground(0.1, 0.2, 0.4)
36
37ren.ResetCamera()
38cam = ren.GetActiveCamera()
39cam.Elevation(-40)
40
41
42## Generate the GUI
43root = tkinter.Tk()
44root.withdraw()
45
46# Define a quit method that exits cleanly.
47def quit(obj=root):
48    obj.quit()
49
50# Create the toplevel window
51top = tkinter.Toplevel(root)
52top.title("Sphere Puzzle")
53top.protocol("WM_DELETE_WINDOW", quit)
54
55# Create some frames
56f1 = tkinter.Frame(top)
57f2 = tkinter.Frame(top)
58
59f1.pack(side="top", anchor="n", expand=1, fill="both")
60f2.pack(side="bottom", anchor="s", expand="t", fill="x")
61
62# Create the Tk render widget, and bind the events
63rw = vtkTkRenderWindowInteractor(f1, width=400, height=400, rw=renWin)
64rw.pack(expand="t", fill="both")
65
66def reset(evt=None):
67    puzzle.Reset()
68    renWin.Render()
69
70# Display some information
71l1 = tkinter.Label(f2, text="Position cursor over the rotation plane.")
72l2 = tkinter.Label(f2, text="Moving pieces will be highlighted.")
73l3 = tkinter.Label(f2, text="Press 'm' to make a move.")
74reset = tkinter.Button(f2, text="Reset", command=reset)
75
76b1 = tkinter.Button(f2, text="Quit", command=quit)
77
78for i in (l1, l2, l3, reset, b1):
79    i.pack(side="top", expand="t", fill="x")
80
81# Done with the GUI.  Create callback functions.
82
83in_piece_rotation = 0
84LastVal = None
85
86# Highlight pieces
87def MotionCallback(obj, event):
88    global in_piece_rotation
89    global LastVal
90    if in_piece_rotation:
91        return
92
93    iren = renWin.GetInteractor()
94    istyle = iren.GetInteractorStyle().GetCurrentStyle()
95
96    # Return if the user is performing interaction
97    if istyle.GetState():
98        return
99
100    # Get mouse position
101    pos = iren.GetEventPosition()
102    x, y = pos
103
104    # Get world point
105    ren.SetDisplayPoint(x, y, ren.GetZ(x, y))
106    ren.DisplayToWorld()
107    pt = ren.GetWorldPoint()
108    val = puzzle.SetPoint(pt[0], pt[1], pt[2])
109
110    if (not LastVal) or val != LastVal:
111        renWin.Render()
112        LastVal = val
113
114# Rotate the puzzle
115def CharCallback(obj, event):
116    iren = renWin.GetInteractor()
117
118    keycode = iren.GetKeyCode()
119    if keycode != "m" and keycode != "M":
120        return
121
122    pos = iren.GetEventPosition()
123    ButtonCallback(pos[0], pos[1])
124
125
126def ButtonCallback(x, y):
127    global in_piece_rotation
128    if in_piece_rotation:
129        return
130    in_piece_rotation = 1
131
132    # Get world point
133    ren.SetDisplayPoint(x, y, ren.GetZ(x,y))
134    ren.DisplayToWorld()
135    pt = ren.GetWorldPoint()
136    x, y, z = pt[:3]
137
138    for i in range(0, 101, 10):
139        puzzle.SetPoint(x, y, z)
140        puzzle.MovePoint(i)
141        renWin.Render()
142        root.update()
143
144    in_piece_rotation = 0
145
146root.update()
147
148# Modify some bindings, use the interactor style 'switch'
149iren = renWin.GetInteractor()
150istyle = vtk.vtkInteractorStyleSwitch()
151
152iren.SetInteractorStyle(istyle)
153istyle.SetCurrentStyleToTrackballCamera()
154
155iren.AddObserver("MouseMoveEvent", MotionCallback)
156iren.AddObserver("CharEvent", CharCallback)
157
158# Shuffle the puzzle
159ButtonCallback(218, 195)
160ButtonCallback(261, 128)
161ButtonCallback(213, 107)
162ButtonCallback(203, 162)
163ButtonCallback(134, 186)
164
165iren.Initialize()
166renWin.Render()
167iren.Start()
168
169root.mainloop()
170