Создание 3D-графики с помощью PyOpenGL

Я использую PyOpenGL для генерации трехмерной морской поверхности в соответствии с "2D волновым уравнением". Основная цель - показать динамический график "2D волнового уравнения". Но он постоянно говорит мне об этой ошибке:

E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\mytest>python seawave_2d_opengl.py
Traceback (most recent call last):
  File "E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\lib\site-packages\OpenGL\GLUT\
special.py", line 130, in safeCall
    return function( *args, **named )
  File "seawave_2d_opengl.py", line 106, in Draw
    glVertex3f(x,y,z)
  File "E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\lib\site-packages\OpenGL\p
latform\baseplatform.py", line 402, in __call__
    return self( *args, **named )
ctypes.ArgumentError: argument 3: <class 'TypeError'>: wrong type
GLUT Display callback <function Draw at 0x0000000004086950> with (),{} failed: r
eturning None argument 3: <class 'TypeError'>: wrong type

E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\mytest>

Вот код:

from numpy import linspace,zeros,sin,pi,exp,sqrt
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys

def solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, tstop, user_action=None):
    dx = Lx/float(nx)
    dy = Ly/float(ny)
    x = linspace(0, Lx, nx+1)  #grid points in x dir
    y = linspace(0, Ly, ny+1)  #grid points in y dir
    if dt <= 0:                #max time step?
        dt = (1/float(c))*(1/sqrt(1/dx**2 + 1/dy**2))
    Cx2 = (c*dt/dx)**2
    Cy2 = (c*dt/dy)**2  #help variables
    dt2 = dt**2

    up = zeros((nx+1,ny+1))  #solution array
    u = up.copy()            #solution at t-dt
    um = up.copy()           #solution at t-2*dt

    #set initial condition:
    t =0.0
    for i in range(0,nx):
        for j in range(0,ny):
            u[i,j] = I(x[i], y[j])
    for i in range(1,nx-1):
        for j in range(1,ny-1):
            um[i,j] = u[i,j] + \
                      0.5*Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
                      0.5*Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
                      dt2*f(x[i], y[j], t)
    #boundary values of um (equals t=dt when du/dt=0)
    i = 0
    for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
    j = 0
    for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)
    i = nx
    for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
    j = ny
    for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)

    if user_action is not None:
        user_action(u, x, y, t)   #allow user to plot etc.

    while t <= tstop:
        t_old = t
        t += dt

        #update all inner points:
        for i in range(1,nx-1):
            for j in range(1,ny-1):
                up[i,j] = -um[i,j] + 2*u[i,j] + \
                          Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
                          Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
                          dt2*f(x[i], y[j], t_old)

        #insert boundary conditions:
        i = 0
        for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
        j = 0
        for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)
        i = nx
        for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
        j = ny
        for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)

        if user_action is not None:
            user_action(up, x, y, t)

        um, u, up = u, up, um  #update data structures
    return u  #dt might be computed in this function
#Actually,the book wrote `return dt`,but I changed `dt` to `u`
def I(x, y):
    return exp(-(x-Lx/2.0)**2/2.0 -(y-Ly/2.0)**2/2.0)
def f(x, y, t):
    return sin(2*x*y*pi*t/Lx)  #defined by myself
def bc(x, y, t):
    return 0.0
#These three functions are some basic functions related to the first function "solver0"

Lx = 10
Ly = 10
c = 1.0
dt = 0
nx = 40
ny = 40
tstop = 20

#The following part is to generate 3D graphics,where I must make mistakes:
def init():
    glClearColor(1.0,1.0,1.0,0.0)  

def Draw():
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(0,0,1.0)
    glBegin(GL_LINES)   
    for t in range(0,20,1):
        z = solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, t, user_action=None)
        glVertex3f(x,y,z) 
 #x and y cannot be used here because they are not defined as global variables.
    glEnd()
    glFlush  

def Update():
    global t
    t += 0.1
    glutPostRedisplay() 

def main():    
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
    glutInitWindowSize(800,600)
    glutInitWindowPosition(100,50)
    glutCreateWindow("2D Wave Equations".encode("cp932"))
    init()
    glutDisplayFunc(Draw)
    glutIdleFunc(Update)
    glutMainLoop()   

main()

Какую ошибку я сделал? Может ли кто-нибудь помочь мне в этом?:(

1 ответ

Решение

Как можно догадаться по трассировке стека, один из аргументов (третий?!?) В glVertex3f(x,y,z) имеет неправильный тип. Обсуждение в комментариях прояснило, что z является двухмерным ndarray в то время как glVertex3f() ожидает скаляры. Это выглядит как solver0() вычисляет массив z значения вместо одного z-значения на вызов.

РЕДАКТИРОВАТЬ Я теперь вроде понимаю, что solver0() делает. Функция должна быть задокументирована в книге, в которой она была напечатана. Хотя Stackru не предназначен для интерпретации кода копирования и вставки, я дам небольшой обзор того, что, как мне кажется, делает функция:

  1. Lx и Ly дают диапазон всех х и у
  2. nx и ny дают количество значений x и y между 0 и Lx, Ly, которые используются.
  3. Функция вычисляет массив значений x и y, для которых z-значение (up) вычисляется.
  4. Вычисляет up для нескольких значений времени от 0 до tstop с шириной шага dt,
  5. Если пользовательская функция user_action дано, это называется после up был вычислен. Пользовательская функция вызывается с up, x, y, t в качестве аргументов.

Подводя итог: один вызов solver0 вычисляет все значения x, y и z для заданного диапазона значений x и y и заданного промежутка времени с заданным разрешением.

Другие вопросы по тегам