Attached below are a utility class and a test program which show how to 
transform between local coordinates for a Node and window coordinates for a 
window associated with a Canvas3D.  Use it like this:

    // after the canvas and node are created
    LocalToWindow locToWindow = LocalToWindow(node, canvas);
    ...
    // when you need to transform (canvas location and node transforms may have
    // changed)
    locToWindow.update(); // make sure transforms are up to date
    Point3d[] localPts = <some local coords to transform >
    Point[] windowPts = <the area to put the tranformed pts >
    for (int i = 0; i < localPts.length; i++) {
       locToWindow.transformPt(localPts[i], windowPts[i]);
    }

Hope this helps,

Doug Gehringer
Sun Microsystems
/**
 * Utility class for doing local->window transformations for case where 
 * Canvas3D is a simple display such as a monitor. This won't work for the 
 * more complex cases (i.e. a multiple canvases, head tracking, etc).
 * 
 * Usage:
 *    // after the canvas and node are created
 *    LocalToWindow locToWindow = LocalToWindow(node, canvas);
 *    ...
 *    // when we need to transform (canvas location and node transforms may have
 *    // changed)
 *    locToWindow.update(); // make sure transforms are up to date
 *
 *    Point3d[] localPts = <some local coords to transform >
 *    Point[] windowPts = <the area to put the tranformed pts >
 *    for (int i = 0; i < localPts.length; i++) {
 *       locToWindow.transformPt(localPts[i], windowPts[i]);
 *    }
 */

// standard j3d packages
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.Point;
import java.awt.Dimension;

public class LocalToWindow {

    Canvas3D    canvas = null;
    Node        node = null;

    // inquired/derived data
    Transform3D localToVworld = new Transform3D();
    Transform3D vworldToImagePlate  = new Transform3D();
    Transform3D localToImagePlate = new Transform3D();
    Point3d     eyePos = new Point3d();
    int         projType;
    Point       canvasScr;
    Dimension   screenSize;
    double      metersPerPixelX;
    double      metersPerPixelY;

    // Temporaries
    Point3d     imagePlatePt = new Point3d();
    Vector3d    projVec = new Vector3d();
    Point2d     screenPt = new Point2d();

    /** 
     * Called with the Node which specifies the local coordinates for the
     * points to be transformed and the Canvas3D where the points are
     * displayed
     */
    public LocalToWindow(Node node, Canvas3D canvas) {
        this.canvas = canvas;
        this.node = node;
        update();
    }

    /**
     * Either create LocalToWindow() just before transforming points or call
     * this method to ensure that the transforms are up to date.  Note: if 
     * you are transforming several points, you only need to call this method 
     * once.  
     */
    public void update() {
        node.getLocalToVworld(localToVworld);
        canvas.getVworldToImagePlate(vworldToImagePlate);

        // Make a composite transform:
        // vWorldPt = LocalToVworld * localPt;
        // imagePlatePt = VworldToImagePlate * vWorldPt;
        // imagePlatePt = VworldToImagePlate * LocalToVworld * localPt;
        localToImagePlate.mul(vworldToImagePlate, localToVworld);

        // we need these to project the point from Image Plate coords to 
        // the actual image plate (i.e. perpsective)
        canvas.getCenterEyeInImagePlate(eyePos);
        //System.out.println("eyePos = " + eyePos);
        projType = canvas.getView().getProjectionPolicy();

        // this stuff is to go from image plate coords to window coords
        canvasScr = canvas.getLocationOnScreen();
        //System.out.println("canvasScr = " + canvasScr);
        screenSize = canvas.getScreen3D().getSize();
        double physicalScreenWidth =
            canvas.getScreen3D().getPhysicalScreenWidth();
        double physicalScreenHeight =
            canvas.getScreen3D().getPhysicalScreenHeight();
        metersPerPixelX = physicalScreenWidth / (double) screenSize.width;
        metersPerPixelY = physicalScreenHeight / (double) screenSize.height;

    }

    /** 
     * Transform the point from local coords to window coords
     */
    public void transformPt(Point3d localPt, Point windowPt) { 

        // System.out.println("vWorld Pt = " + local);

        localToImagePlate.transform(localPt, imagePlatePt);
        //System.out.println("imagePlatePt = " + imagePlatePt);

        double zScale = 1.0; // default, used for PARALELL_PROJECTION
        if (projType == View.PERSPECTIVE_PROJECTION) {
            // get the vector from eyePos to imagePlatePt
            projVec.sub(imagePlatePt, eyePos);

            // Scale this vector to make it end at the projection plane.
            // Scale is ratio : 
            //     eye->imagePlate Plane dist  / eye->imagePlatePt dist
            // eye dist to plane is eyePos.z (eye is in +z space)
            // image->eye dist is -projVec.z (image->eye is in -z dir)
            //System.out.println("eye dist = " + (eyePos.z));
            //System.out.println("image dist = " + (-projVec.z));
            zScale = eyePos.z / (-projVec.z);

            screenPt.x = eyePos.x + projVec.x * zScale;
            screenPt.y = eyePos.y + projVec.y * zScale;
        } 
        //System.out.println("screenPt = " + screenPt);
        // Note: screenPt is in image plate coords, at z=0

        // Transform from image plate coords to screen coords
        windowPt.x = (int)Math.round(screenPt.x / metersPerPixelX) - 
                canvasScr.x;
        windowPt.y = screenSize.height - 1 -
            (int)Math.round(screenPt.y / metersPerPixelY) - canvasScr.y;
        //System.out.println("windowPt = " + windowPt);

    }
}
/*
 * Testing LocalToWindow utility.  Rotate using left (or main) button, 
 * select line points using right (or meta + main) button.  Compare coords
 * of selected point with mouse coords.
 */

// standard j3d packages
import javax.media.j3d.*;
import javax.vecmath.*;

// sun utility classes
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.applet.MainFrame;

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.Enumeration;

public class LocalToWindowTest extends Applet {

    Canvas3D    canvas;
    Shape3D     shape;
    Point3d[]   coords;

    public BranchGroup createSceneGraph() {

        // create root of the branch graph
        BranchGroup objRoot = new BranchGroup();

        // create the TransformGroup
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRoot.addChild(objTrans);

        // create box so that we can compare it's reported window coords
        // with what we can "measure" by picking the corners
        coords = new Point3d[5];

        coords[0] = new Point3d( 0.0, 0.0, 0.0);
        coords[1] = new Point3d( 0.5,-0.5, 0.0);
        coords[2] = new Point3d( 0.5, 0.5, 0.0);
        coords[3] = new Point3d(-0.5, 0.5, 0.0);
        coords[4] = new Point3d(-0.5,-0.5, 0.0);

        int [] lineLength = new int[1];
        lineLength[0] = 5;
        LineStripArray lineArray = new LineStripArray(5, LineArray.COORDINATES,
                lineLength);
        lineArray.setCoordinates(0, coords);

        Appearance a = new Appearance();
        a.setColoringAttributes(new ColoringAttributes());
        shape = new Shape3D(lineArray, a);

        shape.setCapability(Shape3D.ALLOW_LOCAL_TO_VWORLD_READ);

        objTrans.addChild(shape);

        objRoot.addChild(new Callback());
        MouseRotate mr = new MouseRotate();
        mr.setTransformGroup(objTrans);
        mr.setSchedulingBounds(new BoundingSphere(new Point3d(),1000));
        objRoot.addChild(mr);

        return objRoot;
    }

    public LocalToWindowTest(){

        setLayout(new BorderLayout());
        canvas = new Canvas3D(null);
        add("Center", canvas);

        // create a simple scene and attach it to virtual universe
        Transform3D t = new Transform3D();
        canvas.getImagePlateToVworld(t);
        //System.out.println("imagePlateToVworld = ");
        //System.out.println(t);

        BranchGroup scene = createSceneGraph();
        SimpleUniverse u = new SimpleUniverse(canvas);

        // This will move the ViewPlatform back a bit so the
        // objects in the scene can be viewed.
        u.getViewingPlatform().setNominalViewingTransform();

        u.addBranchGraph(scene);

        //canvas.getView().setProjectionPolicy(View.PARALLEL_PROJECTION);

    }

    void printXformedCoords() {
        LocalToWindow locToWindow = new LocalToWindow(shape, canvas);
        Point windowPt = new Point(); 
        for (int i = 0; i < coords.length; i++) {
            locToWindow.transformPt(coords[i], windowPt);
            System.out.println("windowPt[" + i + "] = (" + windowPt.x + ", " +
                windowPt.y + ")");
        }
    }

    // allows this to be run as application as well as applet
    public static void main(String[] argv){
        new MainFrame(new LocalToWindowTest(),256,256);
    }

    public class Callback extends Behavior {

        public void initialize(){
            setSchedulingBounds(new BoundingSphere(new Point3d(),1000));
            wakeupOn(new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED));
        }

        public void processStimulus(Enumeration criteria){


            WakeupOnAWTEvent awt=(WakeupOnAWTEvent) criteria.nextElement();
            MouseEvent e=(MouseEvent) awt.getAWTEvent()[0];
            if (e.isMetaDown()) {


                int x=e.getX();
                int y=e.getY();
                System.out.println("mouse ev=("+x+","+y+")");

                printXformedCoords();

            }

            wakeupOn(new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED));
        }
    }
}

Reply via email to