geosolver/workbench/camera.py
2017-03-28 19:38:00 +02:00

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