Visualization.py 9.69 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# -*- coding: utf-8 -*-
"""
$Id$

Copyright 2008-2009 Lode Leroy

This file is part of PyCAM.

PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PyCAM.  If not, see <http://www.gnu.org/licenses/>.
"""

23 24
from pycam.Geometry.utils import sqrt

lode_leroy's avatar
lode_leroy committed
25
import math
sumpfralle's avatar
sumpfralle committed
26
import sys
lode_leroy's avatar
lode_leroy committed
27

sumpfralle's avatar
sumpfralle committed
28 29 30
import OpenGL.GL as GL
import OpenGL.GLU as GLU
import OpenGL.GLUT as GLUT
lode_leroy's avatar
lode_leroy committed
31 32

from OpenGL.constant import Constant
sumpfralle's avatar
sumpfralle committed
33 34
GLUT_WHEEL_UP = Constant('GLUT_WHEEL_UP', 3)
GLUT_WHEEL_DOWN = Constant('GLUT_WHEEL_DOWN', 4)
lode_leroy's avatar
lode_leroy committed
35 36 37


_DrawCurrentSceneFunc = None
lode_leroy's avatar
lode_leroy committed
38
_KeyHandlerFunc = None
lode_leroy's avatar
lode_leroy committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

# Some api in the chain is translating the keystrokes to this octal string
# so instead of saying: ESCAPE = 27, we use the following.
ESCAPE = '\033'

# Number of the glut window.
window = 0

# Rotations for cube.
xrot = 110
yrot = 180
zrot = 250
scale = 0.5
xdist = 0
ydist = -1.0
zdist = -8.0

texture_num = 2
lode_leroy's avatar
lode_leroy committed
57
light = 1
sumpfralle's avatar
sumpfralle committed
58 59
shade_model = GL.GL_FLAT
polygon_mode = GL.GL_FILL
lode_leroy's avatar
lode_leroy committed
60 61 62 63
width = 320
height = 200

# A general OpenGL initialization function.  Sets all of the initial parameters.
sumpfralle's avatar
sumpfralle committed
64 65
def InitGL(Width, Height):
    # We call this right after our OpenGL window is created.
lode_leroy's avatar
lode_leroy committed
66 67 68 69
    global width, height
    width = Width
    height = Height

sumpfralle's avatar
sumpfralle committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    # This Will Clear The Background Color To Black
    GL.glClearColor(0.0, 0.0, 0.0, 0.0)
    # Enables Clearing Of The Depth Buffer
    GL.glClearDepth(1.0)
    # The Type Of Depth Test To Do
    GL.glDepthFunc(GL.GL_LESS)
    # Enables Depth Testing
    GL.glEnable(GL.GL_DEPTH_TEST)
    # Enables Smooth Color Shading
#    GL.glShadeModel(GL.GL_SMOOTH)
    # Enables Flat Color Shading
#    GL.glShadeModel(GL.GL_FLAT)
    GL.glShadeModel(shade_model)

    GL.glMatrixMode(GL.GL_PROJECTION)
    # Reset The Projection Matrix
    GL.glLoadIdentity()

    # Calculate The Aspect Ratio Of The Window
    GLU.gluPerspective(60.0, float(Width)/float(Height), 0.1, 100.0)

    # Setup The Ambient Light
    GL.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, (0.5, 0.5, 0.5, 1.0))
    # Setup The Diffuse Light
    GL.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, (1.0, 1.0, 1.0, 1.0))
    # Position The Light
    GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, (-10.0, 0.0, 0.0, 1.0))
    # Enable Light One
    GL.glEnable(GL.GL_LIGHT0)

    GL.glMatrixMode(GL.GL_MODELVIEW)
    GL.glMaterial(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, (0.1, 0.1, 0.1, 1.0))
#    GL.glMaterial(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, (0.5))

    GL.glPolygonMode(GL.GL_FRONT_AND_BACK, polygon_mode)
lode_leroy's avatar
lode_leroy committed
105 106

def ReSizeGLScene(Width, Height):
sumpfralle's avatar
sumpfralle committed
107 108
    # Prevent A Divide By Zero If The Window Is Too Small
    if Height == 0:
lode_leroy's avatar
lode_leroy committed
109 110 111 112 113 114
        Height = 1

    global width, height
    width = Width
    height = Height

sumpfralle's avatar
sumpfralle committed
115 116 117 118 119 120
    # Reset The Current Viewport And Perspective Transformation
    GL.glViewport(0, 0, Width, Height)
    GL.glMatrixMode(GL.GL_PROJECTION)
    GL.glLoadIdentity()
    GLU.gluPerspective(60.0, float(Width)/float(Height), 0.1, 100.0)
    GL.glMatrixMode(GL.GL_MODELVIEW)
lode_leroy's avatar
lode_leroy committed
121 122 123 124 125

# The main drawing function.
def DrawGLScene():
    global xrot, yrot, zrot, scale, xdist, ydist, zdist, light

sumpfralle's avatar
sumpfralle committed
126 127 128 129
    # Clear The Screen And The Depth Buffer
    GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
    GL.glLoadIdentity()					# Reset The View
    GL.glTranslatef(xdist, ydist, zdist)			# Move Into The Screen
lode_leroy's avatar
lode_leroy committed
130

sumpfralle's avatar
sumpfralle committed
131 132 133 134
    GL.glRotatef(xrot, 1.0, 0.0, 0.0)			# Rotate The Cube On It's X Axis
    GL.glRotatef(yrot, 0.0, 1.0, 0.0)			# Rotate The Cube On It's Y Axis
    GL.glRotatef(zrot, 0.0, 0.0, 1.0)			# Rotate The Cube On It's Z Axis
    GL.glScalef(scale, scale, scale)
lode_leroy's avatar
lode_leroy committed
135
    if light:
sumpfralle's avatar
sumpfralle committed
136
        GL.glEnable(GL.GL_LIGHTING)
lode_leroy's avatar
lode_leroy committed
137
    else:
sumpfralle's avatar
sumpfralle committed
138
        GL.glDisable(GL.GL_LIGHTING)
lode_leroy's avatar
lode_leroy committed
139 140 141 142

    if _DrawCurrentSceneFunc:
        _DrawCurrentSceneFunc()

sumpfralle's avatar
sumpfralle committed
143 144 145
    # Since this is double buffered, swap the buffers to display what just got
    # drawn.
    GLUT.glutSwapBuffers()
lode_leroy's avatar
lode_leroy committed
146 147 148

# The function called whenever a key is pressed
def keyPressed(key, x, y):
lode_leroy's avatar
lode_leroy committed
149
    global light, polygon_mode, shade_model
lode_leroy's avatar
lode_leroy committed
150
    global xrot, yrot, zrot
lode_leroy's avatar
lode_leroy committed
151 152
    global _KeyHandlerFunc

sumpfralle's avatar
sumpfralle committed
153 154
    key = key.upper()
    if (key == ESCAPE) or (key == 'Q'):
lode_leroy's avatar
lode_leroy committed
155 156 157 158 159
        # If escape is pressed, kill everything.
        sys.exit()
    elif key == 'S':
        light = not light
    elif key == '=':
sumpfralle's avatar
sumpfralle committed
160
        print "rot=<%g,%g,%g>" % (xrot, yrot, zrot)
lode_leroy's avatar
lode_leroy committed
161 162 163 164
    elif key == 'I':
        xrot = 110
        yrot = 180
        zrot = 250
lode_leroy's avatar
lode_leroy committed
165
    elif key == 'T': # top
sumpfralle's avatar
sumpfralle committed
166 167 168
        xrot = 0
        yrot = 0
        zrot = 0
lode_leroy's avatar
lode_leroy committed
169
    elif key == 'F': # front
sumpfralle's avatar
sumpfralle committed
170 171 172
        xrot = -90
        yrot = 0
        zrot = 0
lode_leroy's avatar
lode_leroy committed
173
    elif key == 'R': # right
sumpfralle's avatar
sumpfralle committed
174 175 176
        xrot = -90
        yrot = 0
        zrot = -90
lode_leroy's avatar
lode_leroy committed
177
    elif key == 'L': # left
sumpfralle's avatar
sumpfralle committed
178 179 180
        xrot = -90
        yrot = 0
        zrot = +90
lode_leroy's avatar
lode_leroy committed
181
    elif key == 'M':
sumpfralle's avatar
sumpfralle committed
182 183
        if shade_model == GL.GL_SMOOTH:
            shade_model = GL.GL_FLAT
lode_leroy's avatar
lode_leroy committed
184
        else:
sumpfralle's avatar
sumpfralle committed
185 186
            shade_model = GL.GL_SMOOTH
        GL.glShadeModel(shade_model)
lode_leroy's avatar
lode_leroy committed
187
    elif key == 'P':
sumpfralle's avatar
sumpfralle committed
188 189
        if polygon_mode == GL.GL_FILL:
            polygon_mode = GL.GL_LINE
lode_leroy's avatar
lode_leroy committed
190
        else:
sumpfralle's avatar
sumpfralle committed
191 192
            polygon_mode = GL.GL_FILL
        GL.glPolygonMode(GL.GL_FRONT_AND_BACK, polygon_mode)
lode_leroy's avatar
lode_leroy committed
193 194
    elif _KeyHandlerFunc:
        _KeyHandlerFunc(key, x, y)
lode_leroy's avatar
lode_leroy committed
195

196
class mouseState(object):
lode_leroy's avatar
lode_leroy committed
197 198
    button = None
    state = None
sumpfralle's avatar
sumpfralle committed
199 200
    x = 0
    y = 0
lode_leroy's avatar
lode_leroy committed
201 202 203

def mousePressed(button, state, x, y):
    global xrot, yrot, zrot, xdist, ydist, zdist, scale
sumpfralle's avatar
sumpfralle committed
204
    if button == GLUT_WHEEL_DOWN:
lode_leroy's avatar
lode_leroy committed
205
        scale *= 1.1
sumpfralle's avatar
sumpfralle committed
206
    elif button == GLUT_WHEEL_UP:
lode_leroy's avatar
lode_leroy committed
207 208 209 210
        scale /= 1.1

    mouseState.button = button
    mouseState.state = state
sumpfralle's avatar
sumpfralle committed
211 212
    mouseState.x = float(x)
    mouseState.y = float(y)
lode_leroy's avatar
lode_leroy committed
213 214 215 216 217 218 219

def mouseMoved(x, y):
    global xrot, yrot, zrot, xdist, ydist, zdist, scale
    global width, height
    x = float(x)
    y = float(y)
    a1 = math.atan2(mouseState.y-height/2.0, mouseState.x-width/2.0)
220
    r1 = sqrt((mouseState.y - height / 2.0) ** 2 \
sumpfralle's avatar
sumpfralle committed
221
            + (mouseState.x - width / 2.0) ** 2)
lode_leroy's avatar
lode_leroy committed
222
    a2 = math.atan2(y-height/2.0, x-width/2.0)
223
    r2 = sqrt((y - height / 2.0) ** 2 + (x - width / 2.0) ** 2)
sumpfralle's avatar
sumpfralle committed
224 225
    if (mouseState.button == GLUT.GLUT_LEFT_BUTTON) \
            or (mouseState.button == GLUT.GLUT_RIGHT_BUTTON):
lode_leroy's avatar
lode_leroy committed
226 227 228
        a3 = math.acos(mouseState.x/width-0.5)
        a4 = math.acos(x/width-0.5)
        zrot = zrot - (a4-a3)*180/math.pi*2
sumpfralle's avatar
sumpfralle committed
229
    if mouseState.button == GLUT.GLUT_RIGHT_BUTTON:
lode_leroy's avatar
lode_leroy committed
230 231
        a3 = math.acos(mouseState.y/height-0.5)
        a4 = math.acos(y/height-0.5)
sumpfralle's avatar
sumpfralle committed
232
        if x > width / 2.0:
lode_leroy's avatar
lode_leroy committed
233 234 235
            yrot = yrot + (a4-a3)*180/math.pi*2
        else:
            yrot = yrot - (a4-a3)*180/math.pi*2
sumpfralle's avatar
sumpfralle committed
236
    if mouseState.button == GLUT.GLUT_LEFT_BUTTON:
lode_leroy's avatar
lode_leroy committed
237 238 239
        a3 = math.acos(mouseState.y/width-0.5)
        a4 = math.acos(y/width-0.5)
        xrot = xrot - (a4-a3)*180/math.pi*2
sumpfralle's avatar
sumpfralle committed
240 241
    mouseState.x = x
    mouseState.y = y
lode_leroy's avatar
lode_leroy committed
242

sumpfralle's avatar
sumpfralle committed
243 244
def Visualization(title, drawScene=DrawGLScene, width=320, height=200,
        handleKey=None):
lode_leroy's avatar
lode_leroy committed
245
    global window, _DrawCurrentSceneFunc, _KeyHandlerFunc
sumpfralle's avatar
sumpfralle committed
246
    GLUT.glutInit(sys.argv)
lode_leroy's avatar
lode_leroy committed
247 248

    _DrawCurrentSceneFunc = drawScene
lode_leroy's avatar
lode_leroy committed
249 250 251 252

    if handleKey:
        _KeyHandlerFunc = handleKey

lode_leroy's avatar
lode_leroy committed
253 254 255 256 257
    # Select type of Display mode:
    #  Double buffer
    #  RGBA color
    # Alpha components supported
    # Depth buffer
sumpfralle's avatar
sumpfralle committed
258 259
    GLUT.glutInitDisplayMode(GLUT.GLUT_RGBA | GLUT.GLUT_DOUBLE \
            | GLUT.GLUT_DEPTH)
lode_leroy's avatar
lode_leroy committed
260 261

    # get a 640 x 480 window
sumpfralle's avatar
sumpfralle committed
262
    GLUT.glutInitWindowSize(640, 480)
lode_leroy's avatar
lode_leroy committed
263 264

    # the window starts at the upper left corner of the screen
sumpfralle's avatar
sumpfralle committed
265
    GLUT.glutInitWindowPosition(0, 0)
lode_leroy's avatar
lode_leroy committed
266

sumpfralle's avatar
sumpfralle committed
267 268 269 270 271
    # Okay, like the C version we retain the window id to use when closing, but
    # for those of you new to Python (like myself), remember this assignment
    # would make the variable local and not global if it weren't for the global
    # declaration at the start of main.
    window = GLUT.glutCreateWindow(title)
lode_leroy's avatar
lode_leroy committed
272

sumpfralle's avatar
sumpfralle committed
273 274 275 276 277
    # Register the drawing function with glut, BUT in Python land, at least
    # using PyOpenGL, we need to set the function pointer and invoke a function
    # to actually register the callback, otherwise it would be very much like
    # the C version of the code.
    GLUT.glutDisplayFunc(DrawGLScene)
lode_leroy's avatar
lode_leroy committed
278 279

    # Uncomment this line to get full screen.
sumpfralle's avatar
sumpfralle committed
280
    # GLUT.glutFullScreen()
lode_leroy's avatar
lode_leroy committed
281 282

    # When we are doing nothing, redraw the scene.
sumpfralle's avatar
sumpfralle committed
283
    GLUT.glutIdleFunc(DrawGLScene)
lode_leroy's avatar
lode_leroy committed
284 285

    # Register the function called when our window is resized.
sumpfralle's avatar
sumpfralle committed
286
    GLUT.glutReshapeFunc(ReSizeGLScene)
lode_leroy's avatar
lode_leroy committed
287 288

    # Register the function called when the keyboard is pressed.
sumpfralle's avatar
sumpfralle committed
289
    GLUT.glutKeyboardFunc(keyPressed)
lode_leroy's avatar
lode_leroy committed
290 291

    # Register the function called when the mouse is pressed.
sumpfralle's avatar
sumpfralle committed
292
    GLUT.glutMouseFunc(mousePressed)
lode_leroy's avatar
lode_leroy committed
293 294

    # Register the function called when the mouse is pressed.
sumpfralle's avatar
sumpfralle committed
295
    GLUT.glutMotionFunc(mouseMoved)
lode_leroy's avatar
lode_leroy committed
296 297 298 299 300

    # Initialize our window.
    InitGL(640, 480)

    # Start Event Processing Engine
sumpfralle's avatar
sumpfralle committed
301
    GLUT.glutMainLoop()
lode_leroy's avatar
lode_leroy committed
302 303 304 305 306 307 308 309 310


test_model = None
test_cutter = None
test_pathlist = None

def DrawTestScene():
    global test_model, test_cutter, test_pathlist
    if test_model:
sumpfralle's avatar
sumpfralle committed
311
        GL.glColor4f(1, 0.5, 0.5, 0.1)
lode_leroy's avatar
lode_leroy committed
312 313
        test_model.to_OpenGL()
    if test_cutter:
sumpfralle's avatar
sumpfralle committed
314
        GL.glColor3f(0.5, 0.5, 0.5)
lode_leroy's avatar
lode_leroy committed
315 316 317
        test_cutter.to_OpenGL()
    if test_pathlist:
        for path in test_pathlist:
sumpfralle's avatar
sumpfralle committed
318 319
            GL.glColor3f(0.5, 0.5, 1)
            GL.glBegin(GL.GL_LINE_STRIP)
lode_leroy's avatar
lode_leroy committed
320
            for point in path.points:
sumpfralle's avatar
sumpfralle committed
321 322 323
                GL.glVertex3f(point.x, point.y, point.z)
#                GL.glVertex3f(point.x, point.y, point.z+1)
            GL.glEnd()
lode_leroy's avatar
lode_leroy committed
324 325 326 327 328 329 330

def ShowTestScene(model=None, cutter=None, pathlist=None):
    global test_model, test_cutter, test_pathlist
    test_model = model
    test_cutter = cutter
    test_pathlist = pathlist
    Visualization("TestScene", DrawTestScene)