/** * @file View.java * @see Draw3d.java *
* Encapsulates all information necessary for mapping objects * in the 3d world coordinates system based on the current view to * positions on the canvas. * * We assume a fixed view point at (1/2, 1/2, 1), the view plane at * z=0 and the window going from (0,0) to (1,1). * * To simplify the projection, we'll transform this view to one with * the viewpoint at the origin and the projection plane at z=-1 and * the window going from (-0.5, -0.5, -1) to (0.5, 0.5, -1). * This is done by a simple translation of (-0.5, -0.5, -1) that is * is applied after the scene transformation. * * modified: Robert S. Laramee * date: Tuesday, 10 November 1998 * The inverse() method was modified to return the latest inverse * composite matrix. */ import java.awt.*; import java.math.*; //import matrix.*; // the cs770 matrix package class View { private static int _canvasHeight = 100; // height of canvas private static int _canvasWidth = 100; // width of canvas private static double _winScale = 100; // scale for window private static Matrix4 _sceneXform; // scene transformation private static Matrix4 _sceneInverse; // scene transformation private static Matrix4 _tempXform; // scene transformation private static Matrix4 _tempInverse; // scene transformation private static Matrix4 _toStdView; // wc to std view private static String _lastRotateAxis = new String("x"); //-------------- View( ) ------------------------------ public View( ) { _sceneXform = new Matrix4(); _sceneInverse = new Matrix4(); updateComposite(); } //-------------- View( Dimension canvasSize ) ------------- public View( Dimension canvasSize ) { this(); reSize( canvasSize ); } //-------------- reSize ( Dimension canvasSize ) ------------- public void reSize( Dimension canvasSize ) { _canvasHeight = canvasSize.height; _canvasWidth = canvasSize.width; _winScale = (double) Math.min( _canvasHeight, _canvasWidth ); } //-------------- toCanvas -------------------------------- public static Point toCanvas( NDCpoint ndc ) { return toCanvas( new Point4( ndc.x, ndc.y, 0 ) ); } //-------------- toCanvas -------------------------------- public static Point toCanvas( Point4 wc ) { Point4 temp = _toStdView.timesPoint( wc ); double ndcx, ndcy; ndcx = -temp.x / temp.z + 0.5; ndcy = -temp.y / temp.z + 0.5; return( new Point((int)(ndcx * _winScale ), (int)(_winScale - ndcy * _winScale ))); } //-------------- toCanvas -------------------------------- public static void toCanvas( Point4 pts[], int x[], int y[] ) { Point temp; for (int i = 0; i < pts.length; i++ ) { temp = toCanvas( pts[i] ); x[i] = temp.x; y[i] = temp.y; } } /** * toVC * Given a canvas point in x,y and a viewing coord z-value find the back * projection of the canvas point into the viewing coord system at that z. * This method gets called every time a shape is added to the canvas. */ public static Point4 toVC( Point p, double z ) { Point4 vcpos = new Point4(); // position in Viewing coordinates // first get the canvas point as a vc position vcpos.x = p.x / _winScale; vcpos.y = 1.0 - (double) p.y / _winScale; // now do the back projection // This assumes the viewing position as described above vcpos.x = (vcpos.x - 0.5) * (1-z) + 0.5; vcpos.y = (vcpos.y - 0.5) * (1-z) + 0.5; vcpos.z = z; return vcpos; } /** * inverse() * This was modified so it returns the *latest* update of the Inverse * composite matrix - tempInverse. But tempInverse is null at the start. */ public static final Matrix4 inverse( ) { if (_tempInverse != null) { return _tempInverse; } else { return _sceneInverse; } } //-------------- toVC -------------------------------- public static void toVC( Point p, double z, Point4 vcpos ) { vcpos = toVC( p, z); } //-------------- toWC -------------------------------- // map from VC coords to World Coords public static Point4[] toWc( Point4 vcpts[] ) { Point4 temp[] = new Point4[ vcpts.length ]; for (int i=0; i < vcpts.length; i++ ) temp[i] = _sceneInverse.timesPoint( vcpts[i] ); return temp; } //-------------- toNDC -------------------------------- public static void toNDC( Point p, NDCpoint ndc ) { ndc.x = p.x / _winScale; ndc.y = 1.0 - (double) p.y / _winScale; } //-------------- toNDC -------------------------------- public static NDCpoint toNDC( Point p ) { return ( new NDCpoint ( p.x / _winScale, 1.0 - (double) p.y / _winScale )); } //-------------- toRadians ( theta ) ------------- public static final double toRadians( float theta ) { return theta*0.0174533; // theta*2*pi/360; } /** * rotate (axis, theta ) * This is what gets called when the rotate scroll bars are adjusted */ public static void rotate( String axis, float theta ) { updateComposite( Matrix4.rotation( axis, toRadians(theta) )); } //-------------- updateComposite -------------------------------- private static void updateComposite ( ) { _toStdView = Matrix4.translation( -0.5, -0.5, -1).times( _sceneXform); } //-------------- reset -------------------------------- public static void reset ( ) { _sceneXform = new Matrix4(); _sceneInverse = new Matrix4(); updateComposite(); } //-------------- updateComposite -------------------------------- private static void updateComposite ( Matrix4 rotate ) { Matrix4 t1 = Matrix4.translation( -0.5, -0.5, 0.5 ); Matrix4 t2 = Matrix4.translation( 0.5, 0.5, -0.5 ); _tempXform = t2.times( rotate ).times( t1 ).times( _sceneXform ); _tempInverse = _sceneInverse.times( t2).times( rotate.transpose() ).times( t1 ); _toStdView = Matrix4.translation( -0.5, -0.5, -1).times( _tempXform ); } //-------------- updateScene -------------------------------- // "Freezes" previous rotations into Scene xform. public static void updateScene ( ) { _sceneXform = _tempXform; _sceneInverse = _tempInverse; } }