342 lines
12 KiB
Python
342 lines
12 KiB
Python
# no more nasty rounding with integer divisions
|
|
from __future__ import division
|
|
#import Numeric
|
|
import numpy as Numeric
|
|
from includes import *
|
|
from geosolver.matfunc import Vec
|
|
from quaternion import *
|
|
from prototypeObjects import *
|
|
|
|
try:
|
|
from OpenGL.GL import *
|
|
from OpenGL.GLU import *
|
|
except ImportError:
|
|
app = QtGui.QApplication(sys.argv)
|
|
QtGui.QMessageBox.critical(None, "OpenGL grabber","PyOpenGL must be installed to run this example.",
|
|
QtGui.QMessageBox.Ok | QtGui.QMessageBox.Default, QtGui.QMessageBox.NoButton)
|
|
sys.exit(1)
|
|
|
|
class CameraType:
|
|
PERSPECTIVE, ORTHOGRAPHIC, OVERLAY = range(3)
|
|
|
|
class Camera:
|
|
def __init__(self, glViewport, camType):
|
|
self.cameraType = camType
|
|
self.setScreenWidthAndHeight(800,600)
|
|
self.farPlane = 2000.0
|
|
self.nearPlane = 0.01
|
|
self.zFarCoef = math.sqrt(3.0)
|
|
self.zNearCoef = 0.005
|
|
self.position = Vec([0.0, 0.0, 0.0])
|
|
self.orientation = Quaternion()
|
|
self.sceneCenter = Vec([0.0, 0.0, 0.0])
|
|
self.target = self.sceneCenter
|
|
self.upVec = Vec([0.0, 1.0, 0.0])
|
|
self.sceneRadius = 1.0
|
|
|
|
self.aspectRatio = 0.0
|
|
self.cameraIsEdited = False
|
|
self.fieldOfView = 45.0
|
|
self.orthoCoef = math.tan(self.fieldOfView/2.0)
|
|
self.sceneRadius = 300.0
|
|
self.revolveAroundPoint = Vec([0.0, 0.0, 0.0])
|
|
self.glViewport = glViewport
|
|
self.modelViewMatrix = Numeric.identity(4)
|
|
|
|
"""Slots"""
|
|
def cameraIsEdited(self):
|
|
self.cameraIsEdited = True
|
|
|
|
"""Gets"""
|
|
def getWindowWidth(self):
|
|
return self.screenWidth
|
|
|
|
def getWindowHeight(self):
|
|
return self.screenHeight
|
|
|
|
def getFarPlane(self):
|
|
zFar = self.getDistanceToSceneCenter() + self.getZClippingCoefficient()*self.getSceneRadius()
|
|
return zFar
|
|
|
|
def getNearPlane(self):
|
|
z = self.getDistanceToSceneCenter() - self.getZClippingCoefficient() * self.getSceneRadius()
|
|
zMin = self.getZNearCoefficient() * self.getZClippingCoefficient() * self.getSceneRadius()
|
|
|
|
if z < zMin:
|
|
if self.cameraType == CameraType.PERSPECTIVE:
|
|
z = zMin
|
|
elif self.cameraType == CameraType.ORTHOGRAPHIC:
|
|
z = 0.0
|
|
return z
|
|
|
|
def getPosition(self):
|
|
return self.position
|
|
|
|
def getCameraType(self):
|
|
return self.cameraType
|
|
|
|
def getScreenWidth(self):
|
|
return self.screenWidth
|
|
|
|
def getScreenHeight(self):
|
|
return self.screenHeight
|
|
|
|
def getAspectRatio(self):
|
|
return self.screenWidth/self.screenHeight
|
|
|
|
def getFieldOfView(self):
|
|
return self.fieldOfView
|
|
|
|
def getHorizontalFov(self):
|
|
return 2.0 * math.atan(math.tan(self.getFieldOfView()/2.0) * self.getAspectRatio())
|
|
|
|
def getOrthoWidth(self):
|
|
revolvePoint = self.coordinatesOf(self.getRevolveAroundPoint())
|
|
dist = self.orthoCoef * math.fabs(revolvePoint[2])
|
|
if self.getAspectRatio() < 1.0:
|
|
return dist
|
|
else:
|
|
return dist * self.getAspectRatio()
|
|
|
|
def getOrthoHeight(self):
|
|
revolvePoint = self.coordinatesOf(self.getRevolveAroundPoint())
|
|
dist = self.orthoCoef * math.fabs(revolvePoint[2])
|
|
if self.getAspectRatio() < 1.0:
|
|
return dist * 1.0/self.getAspectRatio()
|
|
else:
|
|
return dist
|
|
|
|
def getSceneCenter(self):
|
|
return self.sceneCenter
|
|
|
|
def getCameraType(self):
|
|
return self.cameraType
|
|
|
|
def getOrientation(self):
|
|
return self.orientation
|
|
|
|
def getSceneRadius(self):
|
|
return self.sceneRadius
|
|
|
|
def getRevolveAroundPoint(self):
|
|
return self.revolveAroundPoint
|
|
|
|
def getDistanceToSceneCenter(self):
|
|
sceneCenter = self.coordinatesOf(self.getSceneCenter())
|
|
return math.fabs(sceneCenter[2])
|
|
|
|
def getZClippingCoefficient(self):
|
|
return self.zFarCoef
|
|
|
|
def getZNearCoefficient(self):
|
|
return self.zNearCoef
|
|
|
|
def getSceneRadius(self):
|
|
return self.sceneRadius
|
|
|
|
def getViewport(self):
|
|
viewport = Numeric.array([0, self.getScreenHeight(), self.getScreenWidth(), -self.getScreenHeight()])
|
|
return viewport
|
|
|
|
def getViewDirection(self):
|
|
return Vec([0.0, 0.0, -1.0])
|
|
|
|
"""Sets"""
|
|
def setScreenWidthAndHeight(self, width, height):
|
|
self.screenWidth = width
|
|
self.screenHeight = height
|
|
self.setAspectRatio(width, height)
|
|
|
|
def setAspectRatio(self, width, height):
|
|
if height == 0:
|
|
height = 1
|
|
if self.screenWidth >= self.screenHeight:
|
|
self.aspectRatio = width/height
|
|
else:
|
|
self.aspectRatio = height/width
|
|
|
|
def setFieldOfView(self, fov):
|
|
self.fieldOfView = fov
|
|
|
|
def setPosition(self, position):
|
|
self.position = Vec(position)
|
|
|
|
def setUpVec(self, upVec):
|
|
self.upVec = upVec
|
|
|
|
def setSceneCenter(self, sceneCenter):
|
|
self.sceneCenter = sceneCenter
|
|
|
|
def setOrientation(self, qOrientation):
|
|
self.orientation = qOrientation
|
|
|
|
def setAltOrientation(self, qOrientation):
|
|
#print "setAltOrientation",qOrientation
|
|
deltaQ = self.orientation.inverse() * qOrientation
|
|
deltaQ.normalize()
|
|
self.setOrientation(self.orientation*deltaQ)
|
|
self.orientation.normalize()
|
|
|
|
""" Projection / Modelview """
|
|
def computeModelView(self):
|
|
self.orientation.getRotationMatrix(self.modelViewMatrix)
|
|
#print self.orientation.quaternion
|
|
v = Vec([0.0, 0.0, 0.0])
|
|
v = self.orientation.inverseRotate(self.position)
|
|
|
|
self.modelViewMatrix[3][0] = -v[0]
|
|
self.modelViewMatrix[3][1] = -v[1]
|
|
self.modelViewMatrix[3][2] = -v[2]
|
|
self.modelViewMatrix[3][3] = 1.0
|
|
|
|
def loadProjection(self, reset=True):
|
|
glMatrixMode(GL_PROJECTION)
|
|
if reset == True:
|
|
glLoadIdentity()
|
|
|
|
if self.getCameraType() == CameraType.PERSPECTIVE:
|
|
gluPerspective(180.0*self.getFieldOfView()/math.pi, self.getAspectRatio(), self.getNearPlane(), self.getFarPlane())
|
|
elif self.getCameraType() == CameraType.ORTHOGRAPHIC:
|
|
if self.getOrthoWidth() >= self.getOrthoHeight():
|
|
glOrtho(-self.getOrthoWidth(), self.getOrthoWidth(),
|
|
-self.getOrthoHeight(), self.getOrthoHeight(), self.getNearPlane(), self.getFarPlane())
|
|
elif self.getOrthoWidth() < self.getOrthoHeight():
|
|
glOrtho(-self.getOrthoWidth(), self.getOrthoWidth(), -self.getOrthoHeight(),
|
|
self.getOrthoHeight(), self.getNearPlane(), self.getFarPlane())
|
|
#elif self.getCameraType() == CameraType.OVERLAY:
|
|
# glOrtho(0, self.getScreenWidth(), 0, self.getScreenHeight(), -0.1, 100.0)
|
|
|
|
def loadModelView(self):
|
|
glMatrixMode(GL_MODELVIEW)
|
|
self.computeModelView()
|
|
glLoadMatrixd(self.modelViewMatrix)
|
|
#glLoadIdentity()
|
|
#print "position[x,y,z]: ", self.position[0], self.position[1], self.position[2], " target: ", self.target[0], self.target[1], self.target[2], " upvector: ", self.upVec[0], self.upVec[1], self.upVec[2]
|
|
#if not self.getCameraType() == CameraType.OVERLAY:
|
|
# gluLookAt(self.position[0], self.position[1], self.position[2],
|
|
# self.target[0], self.target[1], self.target[2],
|
|
# self.upVec[0], self.upVec[1], self.upVec[2])
|
|
|
|
def lookAt(self, target):
|
|
self.target = target
|
|
# print target, self.getPosition()
|
|
self.setViewDirection(target - self.getPosition())
|
|
|
|
def setViewDirection(self, direction):
|
|
if direction.normSquared() < 1E-10:
|
|
return
|
|
|
|
xAxis = Vec(direction.cross(self.upVec))
|
|
if xAxis.normSquared() < 1E-10:
|
|
xAxis = Vec([1.0, 0.0, 0.0])
|
|
#piet = xAxis.cross(direction)
|
|
#print "xAxis: ", xAxis, " direction: ", direction, " cross: " , piet
|
|
q = Quaternion()
|
|
q.setFromRotatedBasis(xAxis, xAxis.cross(direction), -direction)
|
|
self.setAltOrientation(q)
|
|
|
|
def printPosition(self):
|
|
print "Camera Position(x, y, z): ", self.position[0], self.position[1], self.position[2]
|
|
|
|
def coordinatesOf(self, src):
|
|
tempCoOf = Vec([0.0,0.0,0.0])
|
|
tempCoOf[0] = src[0] - self.position[0]
|
|
tempCoOf[1] = src[1] - self.position[1]
|
|
tempCoOf[2] = src[2] - self.position[2]
|
|
return self.getOrientation().inverseRotate(tempCoOf)
|
|
|
|
def projectedCoordinatesOf(self, src):
|
|
# Rick 20090311 - gives "Projection failed" error using pyopengl 3.0.2
|
|
# projCoord = gluProject(src[0],src[1],src[2],self.modelViewMatrix, None, None)
|
|
# and this doesn't give the correct result (y coords flipped)
|
|
# projCoord = gluProject(src[0],src[1],src[2], None, None, None)
|
|
model = glGetDoublev(GL_MODELVIEW_MATRIX)
|
|
proj = glGetDoublev(GL_PROJECTION_MATRIX)
|
|
# Rick 20090519 - okay this is weird, on my work system I need to use GL_VIEWPORT
|
|
# but on my home system I need to use getViewPort (different viewport coordinates!)
|
|
view = glGetIntegerv(GL_VIEWPORT)
|
|
#view = self.getViewport()
|
|
#print "before gluProject"
|
|
#print "model=",model
|
|
#print "proj=",proj
|
|
#print "view=",view
|
|
projCoord = gluProject(src[0],src[1],src[2], model, proj, view)
|
|
return projCoord;
|
|
|
|
def unprojectedCoordinatesOf(self, src):
|
|
# Rick 20090311 - gives "Projection failed" error using pyopengl 3.0.2
|
|
# unProjCoord = gluUnProject(src[0],src[1],src[2],self.modelViewMatrix, None, self.getViewport())
|
|
# and this doesn't give the correct result (y coords flipped)
|
|
# UnProjCoord = gluProject(src[0],src[1],src[2], None,None,None)
|
|
model = glGetDoublev(GL_MODELVIEW_MATRIX)
|
|
proj = glGetDoublev(GL_PROJECTION_MATRIX)
|
|
# Rick 20090519 - okay this is weird, on my work system I need to use GL_VIEWPORT
|
|
# but on my home system I need to use getViewPort (different viewport coordinates!)
|
|
view = glGetIntegerv(GL_VIEWPORT)
|
|
#view = self.getViewport()
|
|
#print "before gluUnProject"
|
|
#print "src = ",src
|
|
#print "model=",model
|
|
#print "proj=",proj
|
|
#print "view=",view
|
|
unProjCoord = gluUnProject(float(src[0]),float(src[1]),float(src[2]), model, proj, view)
|
|
#print "unProjCoord = ",unProjCoord
|
|
return unProjCoord
|
|
|
|
def getPositionOnXPlane(self, pointPosition):
|
|
positionOnPlane = Vec([0.0, 0.0, 0.0])
|
|
if self.position[0] == pointPosition[0]:
|
|
t = -pointPosition[0]
|
|
else:
|
|
t = -pointPosition[0] / (self.position[0] - pointPosition[0])
|
|
positionOnPlane[1] = self.position[1]*t + (1-t)*pointPosition[1]
|
|
positionOnPlane[2] = self.position[2]*t + (1-t)*pointPosition[2]
|
|
|
|
return positionOnPlane
|
|
|
|
def getPositionOnYPlane(self, pointPosition):
|
|
positionOnPlane = Vec([0.0, 0.0, 0.0])
|
|
#print " camera position: ", self.position[0], self.position[1], self.position[2]
|
|
if self.position[1] == pointPosition[1]:
|
|
t = -pointPosition[1]
|
|
else:
|
|
t = -pointPosition[1] / (self.position[1] - pointPosition[1])
|
|
positionOnPlane[0] = self.position[0]*t + (1-t)*pointPosition[0]
|
|
positionOnPlane[2] = self.position[2]*t + (1-t)*pointPosition[2]
|
|
|
|
return positionOnPlane
|
|
|
|
def getPositionOnZPlane(self, pointPosition):
|
|
positionOnPlane = Vec([0.0, 0.0, 0.0])
|
|
if self.position[2] == pointPosition[2]:
|
|
t = -pointPosition[2]
|
|
else:
|
|
t = -pointPosition[2] / (self.position[2] - pointPosition[2])
|
|
positionOnPlane[0] = self.position[0]*t + (1-t)*pointPosition[0]
|
|
positionOnPlane[1] = self.position[1]*t + (1-t)*pointPosition[1]
|
|
|
|
return positionOnPlane
|
|
|
|
def setSceneRadius(self, radius):
|
|
self.setFocusDistance(self.sceneRadius / math.tan(self.fieldOfView/2.0))
|
|
self.sceneRadius = radius
|
|
|
|
def setFocusDistance(self, distance):
|
|
self.focusDistance = distance
|
|
|
|
def setSceneCenter(self, center):
|
|
self.sceneCenter = center
|
|
self.setRevolveAroundPoint(self.sceneCenter)
|
|
|
|
def setRevolveAroundPoint(self, point):
|
|
prevDist = math.fabs(self.coordinatesOf(self.revolveAroundPoint[2]))
|
|
self.revolveAroundPoint = point
|
|
newDist = math.fabs(self.coordinatesOf(self.revolveAroundPoint[2]))
|
|
|
|
if (prevDist > 1E-9) and (newDist > 1E-9):
|
|
self.orthoCoef *= prevDist / newDist
|
|
|
|
|
|
|
|
|