(The bulk of the file is mostly due to documentation, which I'm keeping intact in case it's useful.)
Code:
"""
This module provides functions and classes related to the utilization of
virtual reality hardware with Vizard in the lab of _______ at SUNY Optometry.
Variables: None.
Functions: getValue, loadCave, linkView,
isHiBallAvailable, getTracker, getAllSensors.
Classes: Keyboard, HiBall.
For additional information about a particular function or class, please see
the documentation string for that attribute.
Usage examples:
>>> (headTrkr, stylusTrkr, stylusBtn) = sunyhardware.getAllSensors()
>>> tracker = HiBall()
>>> screenWidth = getValue('screenWidth')
>>> print loadCave.__doc__
<removed>
August 4, 2008
edited by:
<removed>
July 29, 2011
"""
from __future__ import division #implements "/" as division without truncation regardless of its operands
import viz #standard Vizard module
import vizcave #Vizard virtual reality cave module
#private variables (measurements taken by hand [AEY 8/11/2011] in meters)
#1024x768, projector settings: 'size' = 1.060, 'vertical stretch' = 1.000
#most are a rough average of two measurements
_screenHeight = 1.779
_screenWidth = 2.396
_screenHeightOffset = (
0.448 #floor-to-frame
+ 0.034 #plus frame width
+ 0.030 #plus frame-to-image
)
_screenWidthOffset = (
-0.060 #origin-to-right-wall
+ 0.270 #plus wall-to-big-frame
+ 0.034 #plus frame width
+ 0.030 #plus frame-to-image
)
_screenDepthOffset = (
0.573 #origin-to-wall
+ 0.083 #plus wall-to-frame
+ 0.023 #plus frame width
+ 0.008 #plus glass-to-image (glass thickness)
)
_eyesHeightOffset = 0.140 #approx dist of eyes below HiBall (MAR+SJH 1/23/2009, RBM subject)
_eyesDepthOffset = 0.110 #approx dist of eyes in front of HiBall (MAR+SJH 1/23/2009, RBM subject)
_stylusOffset = [-0.00175, -0.1050, -0.1693] #TODO from HiBall stylus calibration procedure, currently 2003 numbers
# intended for link.preTrans(); see Help (Reference > Linking > Operators on Links)
def getValue(parameter):
"""
Returns the read-only value of the named private attribute.
Currently accepted parameter names include: 'screenHeight', 'screenWidth',
'screenHeightOffset', 'screenWidthOffset', 'screenDepthOffset',
'eyesHeightOffset', 'eyesDepthOffset'.
Definition:
getValue(parameter)
Usage:
>>> screenWidth = getValue('screenWidth')
"""
if parameter=='screenWidth':
return _screenWidth
elif parameter=='screenHeight':
return _screenHeight
elif parameter=='screenHeightOffset':
return _screenHeightOffset
elif parameter=='screenWidthOffset':
return _screenWidthOffset
elif parameter=='screenDepthOffset':
return _screenDepthOffset
elif parameter=='eyesHeightOffset':
return _eyesHeightOffset
elif parameter=='eyesDepthOffset':
return _eyesDepthOffset
elif parameter=='xZero':
return -_screenWidthOffset - _screenWidth/2
elif parameter=='yZero':
return _screenHeightOffset + _screenHeight/2
elif parameter=='zZero':
return _screenDepthOffset
elif parameter=='stylusOffset':
return _stylusOffset
elif isinstance(parameter,tuple): # must use tuples since strings are lists
return [getValue(x) for x in parameter]
def getVisualBounds(origin):
# Given HiBall coordinates of a viewpoint, return elevations and azimuths of each edge of screen (l,r,t,b)
from math import atan2, degrees
(x0, y0, z0) = getValue(('xZero', 'yZero', 'zZero'))
(w, h) = getValue(('screenWidth', 'screenHeight'))
[x,y,z] = origin
lrtb = (x0-w/2-x, x0+w/2-x, y0+h/2-y, y0-h/2-y)
angles = map(lambda opposite: atan2(opposite,z), lrtb)
print "bounds at", origin
print "... are", map(degrees, angles)
return angles
def loadCave(tracker=None,orthographic=False):
"""
Returns a Vizard cave optionally driven by tracker coordinates.
Creates a vizcave wall based on coordinates for the Christie Mirage S+4K
projection screen. Creates a stereo vizcave cave to which the wall and
optionally provided tracker are added. The cave can optionally be placed
in orthographic projection (defaults to perspective). The tracker, if
provided, sends position and orientation information to the cave, which
is used in the calculation of the viewing frustum. Note that the active
viewport is not updated with the tracking position; please use linkView
to do so.
Definition:
loadCave(tracker=None,orthographic=False)
Usage:
>>> cave = loadCave(tracker)
"""
#save default inter-pupilary distance (IPD)
ipd = viz.MainWindow.getIPD()
if not isinstance(tracker,viz.VizView):
ipd = -ipd #KLUDGE - this solves eye-swap problem, but still not sure where this problem comes from
def makeOrthographic():
# TODO Doesn't change IPD based on orientation of eyes with head
# Requires the wall to be in the X-Y plane
# to set up tracker so that stereo IPD will be correct?
# NOTE this is the "intended" way of doing this, but has drawbacks
viz.MainView.eyeheight(0)
viz.MainView.reset(viz.RESET_POS)
viz.MainWindow.ortho(
-_screenWidthOffset - _screenWidth,
-_screenWidthOffset,
_screenHeightOffset,
_screenHeightOffset + _screenHeight,
-1, -1, # automatic near and far clip
eye = viz.BOTH_EYE)
viz.MainWindow.screenDistance(_screenDepthOffset)
return None
cave = vizcave.Cave()
def makePerspective():
#setup wall using world coordinates
upperLeft = [-_screenWidthOffset-_screenWidth, _screenHeightOffset+_screenHeight, _screenDepthOffset]
upperRight = [-_screenWidthOffset, _screenHeightOffset+_screenHeight, _screenDepthOffset]
lowerLeft = [-_screenWidthOffset-_screenWidth, _screenHeightOffset, _screenDepthOffset]
lowerRight = [-_screenWidthOffset, _screenHeightOffset, _screenDepthOffset]
wall = vizcave.Wall('wall',upperLeft,upperRight,lowerLeft,lowerRight)
#setup cave with wall and tracker (optional)
cave.setIPD(ipd)
cave.addWall(wall)
if tracker:
cave.setTracker(pos=tracker, ori=tracker)
tracker.makeOrthographic = makeOrthographic
tracker.makePerspective = makePerspective
if orthographic:
tracker.makeOrthographic()
else:
tracker.makePerspective()
return cave
# FAILED METHOD
# Below code **messes up stereo** when giving orthographic-like projection
"""
#setup wall using world coordinates
upperLeft = [-_screenWidthOffset-_screenWidth, _screenHeightOffset+_screenHeight, _screenDepthOffset]
upperRight = [-_screenWidthOffset, _screenHeightOffset+_screenHeight, _screenDepthOffset]
lowerLeft = [-_screenWidthOffset-_screenWidth, _screenHeightOffset, _screenDepthOffset]
lowerRight = [-_screenWidthOffset, _screenHeightOffset, _screenDepthOffset]
wall = vizcave.Wall('wall',upperLeft,upperRight,lowerLeft,lowerRight)
#setup cave with wall and tracker (optional)
cave = vizcave.Cave()
cave.setIPD(ipd)
cave.addWall(wall)
if tracker:
# HACK if orthographic, shift viewpoint as if view is from far away (image as through a telescope)
cave.orthoTracker = viz.link(tracker, viz.NullLinkable)
cave.orthoTracker.postTrans([0,0,-100])
def makeOrthographic():
cave.setTracker(pos=cave.orthoTracker, ori=tracker)
def makePerspective():
cave.setTracker(pos=tracker, ori=tracker) #named arguments used for clarity (ori required for stereo)
cave.makeOrthographic = makeOrthographic
cave.makePerspective = makePerspective
if orthographic:
cave.makeOrthographic()
else:
cave.makePerspective()
return cave
"""
def linkView(tracker,withCave=False):
"""
Returns a view based on tracker coordinates.
Links the provided tracker to the Vizard main viewpoint. If
withCave=True, links the tracker to main view through the cave
view, otherwise links directly to the main view (default).
Definition:
linkView(tracker,withCave=False)
Usage:
>>> view = linkView(tracker,True)
"""
# HACK CaveView doesn't require a cave...at the moment
return vizcave.CaveView(tracker)
"""
if withCave:
#link tracker to CaveView
view = vizcave.CaveView(tracker) #added flexibility to change viewpoint manually
else:
#link tracker directly to viz.MainView
view = viz.link(tracker,viz.MainView)
view.setDstFlag(viz.LINK_POS_RAW) #use the raw tracker position coordinates
return view
"""
def orthoUpdateCaveAndView(tracker, cave, view, ortho):
if ortho:
tracker.makeOrthographic()
cave.setTracker(pos=None, ori=None)
view.setView(viz.NullLinkable) # disassociate CaveView and tracker
viz.cam.reset()
else:
tracker.makePerspective()
cave.setTracker(pos=tracker,ori=tracker)
view.setView(viz.MainView)