I think I have found a bug in the j3d library, probably in
getPixelLocationInImagePlate.  It appears that converting from pixel
coordinates to image plate coordinates to virtual world coordinates
produces dimensions that are 2x too big.

The code below (two files) illustrates this bug.  Run the program
without arguments:

java BugDemo

When the user clicks on the canvas window, the application reports the
location of the mouse click in pixel, image plate, and virtual world
coordinates.

When zTrans = 1+sqrt(2) (the default), the green rectangle is at z =
-0.5; the red rectangle is at z = 0; the black rectangle is at z =
0.5.  All rectangles are 0.6 m wide, 0.8 m tall.  Clicking on the red
rectangle (at z = 0) should produce "true" dimensions, but it doesn't;
the reported dimensions are twice as big as they should be.  For
example, clicking on the four corners of the red rectangle produces:

(x, y):                     (496, 251)
(x, y) in image plate:      (0.1765, 0.2105, 0.0)
(x, y) in Virtual World:    (0.6000000000000001, 0.7999999999999998, 0.0)

(x, y):                     (124, 251)
(x, y) in image plate:      (0.0835, 0.2105, 0.0)
(x, y) in Virtual World:    (-0.5999999999999999, 0.7999999999999998, 0.0)

(x, y):                     (124, 747)
(x, y) in image plate:      (0.0835, 0.08650000000000001, 0.0)
(x, y) in Virtual World:    (-0.5999999999999999, -0.7999999999999998, 0.0)

(x, y):                     (496, 747)
(x, y) in image plate:      (0.1765, 0.08650000000000001, 0.0)
(x, y) in Virtual World:    (0.6000000000000001, -0.7999999999999998, 0.0)

The VW (x, y) values should be (+/- 0.3, +/- 0.4), not (+/- 0.6, +/- 0.8).

I got the same results when I used Olivier Fillon's
getCanvasPtToVworldPt method:

http://archives.java.sun.com/cgi-bin/wa?A2=ind9910&L=java3d-interest&P=R20329

Am I right?

Thanks!

KJ



::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// File BugDemo.java
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.*;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Text2D;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class BugDemo extends Applet {

    private static final StringBuffer USAGE = new StringBuffer();
    private static final StringBuffer MSG   = new StringBuffer();
    static {
        USAGE.append(
"Usage: java BugDemo\n"                                                     +
"       java BugDemo <zTrans>\n"                                            +
"       java BugDemo <screenWidthMeters> <screenHeightMeters>\n"            +
"       java BugDemo <zTrans> <screenWidthMeters> <screenHeightMeters>\n"   +
"zTrans is the z-displacement of the centerEye; it defaults to 1+sqrt(2)\n" +
"screenWidthMeters and screenHeightMeters are the width and height of\n"    +
"the computer screen, in meters; they default to 0.4 and 0.3, respectively\n");

        MSG.append(
"When zTrans = 1+sqrt(2) (the default), the green rectangle is at z =\n"    +
"-0.5; the red rectangle is at z = 0; the black rectangle is at z = 0.5.\n" +
"All rectangles are 0.6 m wide, 0.8 m tall.  Clicking on the red\n"         +
"rectangle (at z = 0) should produce \"true\" dimensions, but it\n"         +
"doesn't; the reported dimensions are twice as big as they should be.\n");
    }

    private static final Color3f        WHITE     = new Color3f(1f,1f,1f);
    private static final Color3f        BLACK     = new Color3f(0f,0f,0f);
    private static final Color3f        RED       = new Color3f(1f,0f,0f);
    private static final Color3f        GREEN     = new Color3f(0f,1f,0f);
    private static final int            FASTEST   = ColoringAttributes.
                                                    FASTEST;
    private static final BoundingSphere BOUNDS    =
        new BoundingSphere(new Point3d(0f, 0f, 0f), 1000f);

    private static       double         screenX   = 0.4; // meters
    private static       double         screenY   = 0.3; // meters
    private static       boolean        zTransSet = false;
    private static       float          zTrans;
    private static       Canvas3D       canvas3D;

    private TransformGroup makeRectangle(float zval, Color3f color) {

        Appearance app = new Appearance();
        Box rectangle = new Box(0.6f, 0.8f, 0f, app);

        PolygonAttributes pa = new PolygonAttributes();
        pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
        pa.setCullFace   (PolygonAttributes.CULL_NONE);
        app.setPolygonAttributes(pa);

        ColoringAttributes ca = new ColoringAttributes(color, FASTEST);
        app.setColoringAttributes(ca);

        Transform3D  rectTrans = new Transform3D();
        rectTrans.set(new Vector3f(0f, 0f, zval));
        TransformGroup rectTG = new TransformGroup(rectTrans);
        rectTG.addChild(rectangle);

        return rectTG;
    }

    private TransformGroup makeMessage() {
        Transform3D    textLoc = new Transform3D();
        textLoc.set(new Vector3f(-0.3f, 0.3f, 0f));
        TransformGroup textTG  = new TransformGroup(textLoc);
        Text2D         text2D  = new Text2D(MSG.toString(),
                                            BLACK, "Helvetica", 18,
                                            Font.ITALIC);
        textTG.addChild(text2D);
        return textTG;
    }

    public BranchGroup createSceneGraph() {

        // create group nodes
        BranchGroup    rectangleBG  = new BranchGroup();
        TransformGroup handle       = new TransformGroup();
        BranchGroup    objRoot      = new BranchGroup();

        // create leaf nodes
        TransformGroup text         = makeMessage();
        TransformGroup rectangleTG0 = makeRectangle( 0.5f, BLACK);
        TransformGroup rectangleTG1 = makeRectangle( 0.0f, RED);
        TransformGroup rectangleTG2 = makeRectangle(-0.5f, GREEN);
        Background     background   = new Background(WHITE);
        MyMouseClick   myMouseClick = new MyMouseClick(canvas3D);
        MouseZoom      mouseZoom    = new MouseZoom();

        // connect all nodes in scene graph
        rectangleBG.addChild(rectangleTG0);
        rectangleBG.addChild(rectangleTG1);
        rectangleBG.addChild(rectangleTG2);
        handle     .addChild(rectangleBG);
        objRoot    .addChild(handle);
        objRoot    .addChild(background);
        objRoot    .addChild(text); // bug? text doesn't show!?
        objRoot    .addChild(myMouseClick);
        objRoot    .addChild(mouseZoom);

        // set node properties
        handle.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        handle.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

        background.setApplicationBounds(BOUNDS);
        myMouseClick.setTransformGroup(handle);
        myMouseClick.setSchedulingBounds(BOUNDS);
        mouseZoom.setTransformGroup(handle);
        mouseZoom.setSchedulingBounds(BOUNDS);

        objRoot.compile();

        return objRoot;

    } // end of CreateSceneGraph


    public BugDemo() {

        setLayout(new BorderLayout());

        GraphicsConfiguration config =
            SimpleUniverse.getPreferredConfiguration();
        canvas3D = new Canvas3D(config);
        add("Center", canvas3D);

        Screen3D s3d = canvas3D.getScreen3D();
        s3d.setPhysicalScreenWidth (screenX);
        s3d.setPhysicalScreenHeight(screenY);

        SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

        if(zTransSet) {
            TransformGroup vpTrans =
                simpleU.getViewingPlatform().getViewPlatformTransform();
            Transform3D T3D = new Transform3D();
            vpTrans.getTransform(T3D);

            T3D.setTranslation(new Vector3f(0f, 0f, zTrans));
            vpTrans.setTransform(T3D);
        }
        else {
            simpleU.getViewingPlatform().setNominalViewingTransform();
        }

        simpleU.addBranchGraph(createSceneGraph());

    } // end of BugDemo constructor

    public static void main(String[] args) {
        switch(args.length) {
        case 0: break;
        case 1:
            zTransSet = true;
            zTrans = Float.parseFloat(args[0]);
            break;
        case 2:
            screenX = Double.parseDouble(args[0]);
            screenY = Double.parseDouble(args[1]);
            break;
        case 3:
            zTransSet = true;
            zTrans = Float.parseFloat(args[0]);
            screenX = Double.parseDouble(args[1]);
            screenY = Double.parseDouble(args[2]);
            break;
        default:
            System.err.print(USAGE);
            System.exit(1);
            break;
        }

        BugDemo demo = new BugDemo();
        Frame frame = new MainFrame(demo, 620, 1000);

        Screen3D s3d = demo.canvas3D.getScreen3D();

        Point3d centerEye = new Point3d();

        do {
            demo.canvas3D.getCenterEyeInImagePlate(centerEye);
        } while (centerEye.x == 0f);

        System.out.println("centerEye in image plate:   "
                           + centerEye);

        Transform3D i2v = new Transform3D();
        demo.canvas3D.getImagePlateToVworld(i2v);
        System.out.println("IP -> VW transformation:");
        System.out.print(i2v);

        i2v.transform(centerEye);
        System.out.println("centerEye in Virtual World: "
                           + centerEye);
        System.out.println();

        System.out.println(MSG);

    }
} // end of class BugDemo

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// File: MyMouseClick.java
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.*;

public class MyMouseClick extends MouseBehavior {
    private Canvas3D    canvas3D  = null;
    private Point3d     base      = new Point3d();
    private Transform3D i2v       = new Transform3D();

    public MyMouseClick(Canvas3D c3D){
        super(0);
        canvas3D = c3D;
    }

    public void processStimulus (Enumeration criteria) {
        WakeupCriterion wakeup;
        AWTEvent[] events;
        MouseEvent evt;

        while (criteria.hasMoreElements()) {
            wakeup = (WakeupCriterion) criteria.nextElement();
            if (wakeup instanceof WakeupOnAWTEvent) {
                events = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
                if (events.length > 0) {
                    evt = (MouseEvent) events[events.length-1];
                    int id = evt.getID();
                    if(id == MouseEvent.MOUSE_PRESSED &&
                       !evt.isAltDown() && !evt.isMetaDown()) {
                        x = evt.getX();
                        y = evt.getY();
                        report();
                    }
                }
            }
        }
        wakeupOn (mouseCriterion);
    }

    private void report() {
        System.out.println("(x, y):                     " +
                           "(" + x + ", " + y + ")");

        canvas3D.getPixelLocationInImagePlate(x, y, base);
        System.out.println("(x, y) in image plate:      " +
                           base);

        canvas3D.getImagePlateToVworld(i2v);
        i2v.transform(base);
        System.out.println("(x, y) in Virtual World:    " +
                           base);
        System.out.println();
    }
}

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to