Package jsynoptic.plugins.java3d

Source Code of jsynoptic.plugins.java3d.ViewTransform

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2007, by :
*     Corporate:
*         EADS Astrium
*     Individual:
*         Claude Cazenave
*
* $Id: ViewTransform.java,v 1.3 2008/02/11 14:09:28 cazenave Exp $
*
* Changes
* -------
* 4 janv. 08  : Initial public release
*
*/
package jsynoptic.plugins.java3d;

import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Timer;
import java.util.TimerTask;

import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.View;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.universe.ViewingPlatform;

public class ViewTransform implements Serializable, Cloneable {
    static final long serialVersionUID = 723655790680357786L;
   
    /**
     * In rotation mode, the user rotates the whole scene and can zoom in or
     * out. Rotation mode is adapted to study one object. This is the default
     */
    public static final int ROTATION_MODE = 0;

    /**
     * In fly-by mode, the user can freely move in the scene. This is more
     * adapted for scenes with multiple objects or for objects with a complex
     * internal geometry to study.
     */
    public static final int FLY_BY_MODE = 1;

    /**
     * The current viewing mode FLY BY or ROTATION
     */
    private int _viewingMode;

    private Matrix4f _zoom;

    private Matrix4f _rot;

    private Matrix4f _drotX;

    private Matrix4f _drotY;

    private Matrix4f _trans;

    private Vector3f _vtrans;

    private int _pos2DX, _pos2DY;

    private boolean _perspective;

    private float _wsize;

    private float _zoomFactor;

    private float _scaleFactor;

    private float _eyeDistance;

    private float _transFactorX;

    private float _transFactorY;

    private int _accumulator;

    private transient Timer _zoomAccumulator;

    private transient Transform3D _transform;

    private transient Transform3D _tempTransform;

    private transient ViewingPlatform _viewingPlatform;

    // TODO get platform and view according to persitent info and plugin support
    public ViewTransform(ViewingPlatform viewingPlatform) {
        _viewingMode = ROTATION_MODE;
        _viewingPlatform = viewingPlatform;
        _transform = new Transform3D();
        // avoids cumulative rounding errors
        // This should avoid "non-congruent transform above view transform"
        // exception
        _transform.setAutoNormalize(true);
        _tempTransform = new Transform3D();
        _zoom = new Matrix4f();
        _zoom.setIdentity();
        _rot = new Matrix4f();
        _rot.setIdentity();
        _trans = new Matrix4f();
        _trans.setIdentity();
        _drotX = new Matrix4f();
        _drotY = new Matrix4f();
        _vtrans = new Vector3f();
        _zoomFactor = 0.f;
        _scaleFactor = 1.f;
        _eyeDistance = 2.f;
        _transFactorX = 0.f;
        _transFactorY = 0.f;
        _perspective = true;
        _wsize = 100;
        _accumulator = 0;
        updateZoomMatrix();
        updateTranslateMatrix();
        // Use J3D recommendation to set this between 100 and 1000
        // default is a factor of 100 (front=0.1, back=10)
        // Make this 1000 to have more space
        getView().setBackClipDistance(getView().getFrontClipDistance() * 1000);
    }

    private View getView() {
        return _viewingPlatform.getViewers()[0].getView();
    }

    public float getEyeDistance() {
        return _eyeDistance;
    }

    public void setEyeDistance(float eyeDistance) {
        this._eyeDistance = eyeDistance;
    }

    public float getScaleFactor() {
        return _scaleFactor;
    }

    public void setScaleFactor(float scaleFactor) {
        this._scaleFactor = scaleFactor;
    }

    public float getTransFactorX() {
        return _transFactorX;
    }

    public void setTransFactorX(float transFactorX) {
        this._transFactorX = transFactorX;
    }

    public float getTranslationFactorY() {
        return _transFactorY;
    }

    public void setTranslationFactorY(float transFactorY) {
        this._transFactorY = transFactorY;
    }

    public float getWSize() {
        return _wsize;
    }

    public void setWSize(float wsize) {
        this._wsize = wsize;
    }

    public float getZoomFactor() {
        return _zoomFactor;
    }

    public void setZoomFactor(float zoomFactor) {
        this._zoomFactor = zoomFactor;
    }

    public void setPerspective(boolean p) {
        _perspective = p;
    }

    public boolean isPerspective() {
        return _perspective;
    }

    /**
     * Updates the translation matrix with the translation factors previously
     * specified This is intentionally a separate function, so that it is
     * possible to do multiple factor modifications, in both directions, then
     * finally update the matrix at the end.
     */
    public void updateTranslateMatrix() {
        if (_perspective) {
            _vtrans.x = 2.f * _transFactorX * _scaleFactor;
            _vtrans.y = 2.f * _transFactorY * _scaleFactor;
        } else {
            _vtrans.x = 2.f * _transFactorX * _scaleFactor;
            _vtrans.y = 2.f * _transFactorY * _scaleFactor;
        }
        _vtrans.z = _eyeDistance;
        _trans.set(_vtrans);
    }

    /**
     * Updates the zoom matrix with the translation factors previously specified
     * This is intentionally a separate function, so that it is possible to do
     * multiple factor modifications, then finally update the matrix at the end.
     */
    public void updateZoomMatrix() {
        if (_perspective) {
            _vtrans.x = 0.f;
            _vtrans.y = 0.f;
            _vtrans.z = _zoomFactor / _wsize * 10.f; // TODO scale
            _scaleFactor = _eyeDistance / (_eyeDistance - _vtrans.z);
            _zoom.set(_vtrans);
        } else {
            _scaleFactor = (float) Math.pow(1.01, _zoomFactor);
            _zoom.setScale(_scaleFactor);
        }
    }

    /**
     * Initialize 2D rotation algorithm with the current position as origin.
     * Typically, this is related to mouse positions in X and Y. Note that WSize
     * should be set to the same value referential as the positions. This is
     * typically a window dimension.
     */
    public void init2DPosition(int posX, int posY) {
        _pos2DX = posX;
        _pos2DY = posY;
    }

    /**
     * Does a rotation of the scene according to moves in a 2D coordinate
     * system. Use init2DPosition to position an origin, then do as many
     * rotate2D as required. Note that WSize should be set to the same value
     * referential as the positions. This is typically a window dimension.
     *
     * @param newX
     *            The new X position in 2D, typically a mouse position
     * @param newY
     *            The new Y position in 2D, typically a mouse position
     */
    public void rotate2D(int newX, int newY) {
        rotate2D(newX, newY, true);
    }

    /**
     * Does a rotation of the scene according to moves in a 2D coordinate
     * system. Use init2DPosition to position an origin, then do as many
     * rotate2D as required. Note that WSize should be set to the same value
     * referential as the positions. This is typically a window dimension.
     *
     * @param newX
     *            The new X position in 2D, typically a mouse position
     * @param newY
     *            The new Y position in 2D, typically a mouse position
     * @param inverse
     *            Inverse the direction of the rotation if true. This is used
     *            ROTATION_MODE viewing mode for the scene, in which case the
     *            scene rotates according to the mouse => in fact, the camera
     *            rotates in the opposite direction. => default is true
     */
    public void rotate2D(int newX, int newY, boolean inverse) {
        float dx = (float) (newX - _pos2DX) / _wsize;
        float dy = (float) (newY - _pos2DY) / _wsize;
        _pos2DX = newX;
        _pos2DY = newY;
        // Default is ROTATION_MODE => rotate the object according to the mouse
        // => default is to move the camera in inverse direction as the mouse
        if (inverse) {
            dx = -dx;
            dy = -dy;
        }
        _drotX.rotX(dy * 2 * (float) Math.PI);
        _drotY.rotY(dx * 2 * (float) Math.PI);
        _rot.mul(_drotX);
        _rot.mul(_drotY);
        applyTransform();
    }

    /**
     * Turns perspective on an off
     */
    public void changeProjection() {
        setPerspective(!_perspective);
        updateZoomMatrix();
        updateTranslateMatrix();
        applyTransform();
    }

    /** Reset all values to default */
    public void reset() {
        _rot.setIdentity();
        _zoomFactor = 0.f;
        updateZoomMatrix();
        _transFactorX = 0.f;
        _transFactorY = 0.f;
        updateTranslateMatrix();
        applyTransform();
    }

    /**
     * @return Returns the pos2DX.
     */
    public int getPos2DX() {
        return _pos2DX;
    }

    /**
     * @param pos2DX
     *            The pos2DX to set.
     */
    public void setPos2DX(int pos2DX) {
        this._pos2DX = pos2DX;
    }

    /**
     * @return Returns the pos2DY.
     */
    public int getPos2DY() {
        return _pos2DY;
    }

    /**
     * @param pos2DY
     *            The pos2DY to set.
     */
    public void setPos2DY(int pos2DY) {
        this._pos2DY = pos2DY;
    }

    /**
     * @return Returns the viewingMode.
     */
    public int getViewingMode() {
        return _viewingMode;
    }

    /**
     * @param viewingMode
     *            The viewingMode to set.
     */
    public void setViewingMode(int viewingMode) {
        _viewingMode = viewingMode;
    }

    /** Auto zooms the scene out of all objects */
    public void autoZoom() {
        float size = getSceneSize();
        if (size <= 0)
            return;
        _eyeDistance = size * 2f;
        _zoomFactor = 0.f;
        updateZoomMatrix();
        updateTranslateMatrix();
        applyTransform();
    }

    /**
     * Used for auto-zooming to englobe the scene
     *
     * @return &lt;=0 if not supported, or the max distance from the origin for
     *         any point in the scene otherwise
     */
    protected float getSceneSize() {
        Bounds res=null;
        Enumeration<?> e=_viewingPlatform.getLocale().getAllBranchGraphs();
        while(e.hasMoreElements()){
            BranchGroup bg=(BranchGroup)e.nextElement();
            Bounds b=bg.getBounds();
            if(res==null){
                res=b;
            }
            else{
                res.combine(b);
            }
        }
        if (res instanceof BoundingSphere) {
            return (float)((BoundingSphere)res).getRadius();
        }
        // else, include this bounds object in a bounding sphere and get radius
        BoundingSphere bs=new BoundingSphere(res);
        return (float)bs.getRadius();
    }

    /**
     * Zooms in or out of the scene according to the increment. This is an
     * arbitrary algorithm to help create correct zoom factors. You could use
     * setZoomFactor and then update the zoom matrix directly, with the same
     * effect.<br>
     * The added value of this function is to provide a relative and easy to
     * manipulate way to zoom in or out, with increments like +1 or -1 for small
     * zooms, and +10 and -10 for greater zooms, etc...<br>
     * Note that WSize should be set correctly.
     *
     * @param zoomIncrement
     *            A value typically 1 or -1, but which can be greater for fast
     *            zooms. Positive values zoom in, negative values zoom out.
     */
    public void zoom(int zoomIncrement) {
        if (getViewingMode() == ROTATION_MODE) {
            // If user does a real fast wheel rotation, then do exponentially
            // fast zoom
            _zoomFactor += Math.pow(2.0, Math.abs(zoomIncrement))
                    * (zoomIncrement < 0 ? -1 : 1);
            updateZoomMatrix();
            updateTranslateMatrix();
            applyTransform();
            return;
        }
        synchronized (this) {
            _accumulator += zoomIncrement;
            if (_zoomAccumulator != null)
                return;
            _zoomAccumulator = new Timer();
            _zoomAccumulator.schedule(new TimerTask() {
                public void run() {
                    int accuCopy;
                    synchronized (ViewTransform.this) {
                        accuCopy = _accumulator;
                        _accumulator = 0;
                        _zoomAccumulator = null;
                    }
                    Vector3f view = new Vector3f(0, 0, -1);
                    _rot.transform(view);
                    float scale = (float) Math.pow(2.0, Math.abs(accuCopy))
                            * getSceneSize() / 200.0f;
                    if (accuCopy < 0)
                        scale = -scale;
                    view.scale(scale);
                    _trans.m03 += view.x;
                    _trans.m13 += view.y;
                    _trans.m23 += view.z;
                    applyTransform();
                }
            }, 200);
        }
    }

    /**
     * Uses the 2D increments in position to compute a zoom factor, then zooms
     * the scene accordingly.
     *
     * @param newX
     *            The new X position in 2D, typically a mouse position
     * @param newY
     *            The new Y position in 2D, typically a mouse position
     */
    public void zoom2D(int newX, int newY) {
        if (getViewingMode() == ROTATION_MODE) {
            float dx = (float) (newX - _pos2DX) / _wsize;
            float dy = (float) (newY - _pos2DY) / _wsize;
            _pos2DX = newX;
            _pos2DY = newY;
            double arbitraryDelta = (dx + dy) * 10.0;
            _zoomFactor += Math.pow(2.0, Math.abs(arbitraryDelta))
                    * (arbitraryDelta < 0 ? -1 : 1);
            updateZoomMatrix();
            updateTranslateMatrix();
            applyTransform();
            return;
        }
        float dx = (float) (newX - _pos2DX) / _wsize;
        float dy = -(float) (newY - _pos2DY) / _wsize;
        _pos2DX = newX;
        _pos2DY = newY;
        Vector3f viewX = new Vector3f(1, 0, 0);
        _rot.transform(viewX);
        viewX.scale(dx / 5.0f);
        Vector3f viewY = new Vector3f(0, 1, 0);
        _rot.transform(viewY);
        viewY.scale(dy / 5.0f);
        _trans.m03 += viewX.x + viewY.x;
        _trans.m13 += viewX.y + viewY.y;
        _trans.m23 += viewX.z + viewY.z;
        applyTransform();
    }

    /**
     * Does a translation of the scene according to moves in a 2D coordinate
     * system. Use init2DPosition to position an origin, then do as many
     * translate2D as required. Note that WSize should be set to the same value
     * referential as the positions. This is typically a window dimension.
     *
     * @param newX
     *            The new X position in 2D, typically a mouse position
     * @param newY
     *            The new Y position in 2D, typically a mouse position
     */
    public void translate2D(int newX, int newY) {
        if (getViewingMode() == ROTATION_MODE) {
            float dx = (float) (newX - _pos2DX) / _wsize;
            float dy = (float) (newY - _pos2DY) / _wsize;
            _pos2DX = newX;
            _pos2DY = newY;
            _transFactorX -= dx;
            _transFactorY += dy;
            updateTranslateMatrix();
            applyTransform();
            return;
        }
        // rotation around view vector
        Vector3f view = new Vector3f(0, 0, -1);
        _rot.transform(view);
        float dx = (float) (newX - _pos2DX) / _wsize;
        float dy = (float) (newY - _pos2DY) / _wsize;
        _pos2DX = newX;
        _pos2DY = newY;
        AxisAngle4f aa = new AxisAngle4f(view, (dx - dy) * (float) Math.PI);
        Matrix4f mat = new Matrix4f();
        mat.setIdentity();
        mat.setRotation(aa);
        mat.mul(_rot);
        _rot = mat;
        applyTransform();
    }

    public void applyTransform() {
        if (getViewingMode() == ROTATION_MODE) {
            _transform.set(_rot);
            _tempTransform.set(_trans);
        } else {
            _transform.set(_trans);
            _tempTransform.set(_rot);
        }
        _transform.mul(_tempTransform);
        _tempTransform.set(_zoom);
        _transform.mul(_tempTransform);
        _viewingPlatform.getViewPlatformTransform().setTransform(_transform);
    }
   
    public Object clone() throws CloneNotSupportedException{
        ViewTransform res=(ViewTransform)super.clone();
        res._zoom=new Matrix4f(_zoom);
        res._rot=new Matrix4f(_rot);
        res._drotX=new Matrix4f(_drotX);
        res._drotY=new Matrix4f(_drotY);
        res._trans=new Matrix4f(_trans);
        res._vtrans=new Vector3f(_vtrans);

        res._transform = new Transform3D();
        res._transform.setAutoNormalize(true);
        res._tempTransform = new Transform3D();
       
        res._viewingPlatform=null;

        res._zoomAccumulator=null;
       
        return res;
    }

    void setViewingPlatform(ViewingPlatform viewingPlatform) {
        _viewingPlatform=viewingPlatform;
       
    }
   
    private void writeObject(java.io.ObjectOutputStream out)
                 throws IOException{
        out.defaultWriteObject();
    }
   
    private void readObject(java.io.ObjectInputStream in)
                 throws IOException, ClassNotFoundException{
        in.defaultReadObject();
        _transform = new Transform3D();
        _transform.setAutoNormalize(true);
        _tempTransform = new Transform3D();
       
        _viewingPlatform=null;

        _zoomAccumulator=null;
    }
}
TOP

Related Classes of jsynoptic.plugins.java3d.ViewTransform

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.