fr.def.iss.vd2.lib_v3d.camera.V3DSimple3DCamera.java Source code

Java tutorial

Introduction

Here is the source code for fr.def.iss.vd2.lib_v3d.camera.V3DSimple3DCamera.java

Source

// Copyright 2010 DEF
//
// This file is part of V3dScene.
//
// V3dScene 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 3 of the License, or
// (at your option) any later version.
//
// V3dScene 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 V3dScene.  If not, see <http://www.gnu.org/licenses/>.

package fr.def.iss.vd2.lib_v3d.camera;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;

import com.spaceagencies.i3d.scene.I3dCamera;
import com.spaceagencies.i3d.scene.element.I3dElement;

import fr.def.iss.vd2.lib_v3d.V3DContext;
import fr.def.iss.vd2.lib_v3d.V3DVect3;
import fr.def.iss.vd2.lib_v3d.element.V3DBoundingBox;

/**
 *
 * @author fberto
 */
public class V3DSimple3DCamera extends I3dCamera {

    private V3DVect3 position = new V3DVect3(0, 0, 0);
    private V3DVect3 rotation = new V3DVect3(45, 0, 0);
    private float distance = 10;
    private float perspective = 45;
    private boolean showCenter = false;

    public V3DSimple3DCamera() {
    }

    @Override
    protected void configureView(GLU glu) {

        float cameraX = -distance * (float) Math.cos(Math.toRadians(rotation.x))
                * (float) Math.sin(Math.toRadians(rotation.z)) + position.x;
        float cameraY = -distance * (float) Math.cos(Math.toRadians(rotation.x))
                * (float) Math.cos(Math.toRadians(rotation.z)) + position.y;
        float cameraZ = distance * (float) Math.sin(Math.toRadians(rotation.x)) + position.z;

        float topX = 0;
        float topY = 0;
        float topZ = 1;

        if (rotation.x > 85) {
            topX = (float) Math.sin(Math.toRadians(rotation.z));
            topY = (float) Math.cos(Math.toRadians(rotation.z));
            topZ = 0;
        }

        glu.gluLookAt(cameraX, cameraY, cameraZ, position.x, position.y, position.z, topX, topY, topZ);

        float[] direction = new float[4];
        direction[0] = 1;
        direction[1] = 1;
        direction[2] = 0.4f;
        direction[3] = 0.0f;

    }

    public V3DVect3 getPosition() {
        return position;
    }

    public void setPosition(V3DVect3 position) {
        this.position.copy(position);
        firePositionChanged();
    }

    public V3DVect3 getRotation() {
        return rotation;
    }

    public void setRotation(V3DVect3 rotation) {
        if (!rotation.isSame(this.rotation)) {
            this.rotation.copy(rotation);
            fireRotationChanged();
        }
    }

    public void setPosition(float x, float y, float z) {
        this.position.x = x;
        this.position.y = y;
        this.position.z = z;
        firePositionChanged();
    }

    public void setRotation(float x, float y, float z) {
        this.rotation.x = x;
        this.rotation.y = y;
        this.rotation.z = z;
        fireRotationChanged();
    }

    public float getDistance() {
        return distance;
    }

    public void setDistance(float distance) {
        this.distance = distance;
    }

    private void displayTarget() {

        GL11.glColor4f(1.0f, 0.5f, 0.5f, 0.8f);
        GL11.glLineWidth(1.2f);
        GL11.glBegin(GL11.GL_LINES);
        {

            GL11.glColor4f(1.0f, 0.0f, 0.0f, 0.8f);
            GL11.glVertex3d(-1, 0, 0);
            GL11.glVertex3d(1, 0, 0);

            GL11.glVertex3d(0.9, 0.1, 0);
            GL11.glVertex3d(1, 0, 0);

            GL11.glVertex3d(0.9, -0.1, 0);
            GL11.glVertex3d(1, 0, 0);

            //y
            GL11.glColor4f(0.0f, 1.0f, 0.0f, 0.8f);
            GL11.glVertex3d(0, -1, 0);
            GL11.glVertex3d(0, 1, 0);

            GL11.glVertex3d(0.1, 0.9, 0);
            GL11.glVertex3d(0, 1, 0);

            GL11.glVertex3d(-0.1, 0.9, 0);
            GL11.glVertex3d(0, 1, 0);

            //z
            GL11.glColor4f(0.0f, 0.0f, 1.0f, 0.8f);
            GL11.glVertex3d(0, 0, -1);
            GL11.glVertex3d(0, 0, 1);

            GL11.glVertex3d(0.1, 0, 0.9);
            GL11.glVertex3d(0, 0, 1);

            GL11.glVertex3d(-0.1, 0, 0.9);
            GL11.glVertex3d(0, 0, 1);

        }
        GL11.glEnd();

        GL11.glPointSize(1.2f);
        GL11.glBegin(GL11.GL_POINTS);
        {
            GL11.glVertex3d(position.x, position.y, position.z);

        }
        GL11.glEnd();

    }

    public void setShowCenter(boolean showCenter) {
        this.showCenter = showCenter;
    }

    @Override
    protected void preDisplayScene() {
        if (showCenter) {
            displayTarget();
        }
    }

    @Override
    public void enableRotation() {
        GL11.glPopMatrix();
    }

    @Override
    public void disableRotation() {
        GL11.glPushMatrix();
        GL11.glRotatef(getRotation().z + 90, 0, 0, 1.0f);
        GL11.glRotatef(getRotation().x - 90, -1.0f, 0, 0.0f);

    }

    @Override
    public float getRelativeSize() {
        return (float) (distance * Math.tan(Math.toRadians(perspective / 2f)));
    }

    @Override
    protected void initPerspective() {
        if (currentHeight <= 0) { // avoid a divide by zero error!
            currentHeight = 1;
        }
        final float h = currentWidth / currentHeight;

        GLU.gluPerspective(perspective, h, distance * 0.1f, distance * 100.0f);

    }

    public Point2D.Float pick(int pickX, int pickY, float pickH) {

        final double ratio = currentWidth / currentHeight;

        double y;
        double x;

        //apply rotation

        double pickXT1 = 2 * ((pickX - currentWidth / 2) / currentWidth) * ratio;
        double pickYT1 = 2 * ((pickY - currentHeight / 2) / currentHeight);

        // heigh of the camera
        double a = (distance * Math.sin(Math.toRadians(rotation.x))) - pickH;

        // size of screen at 0
        double N = (distance * Math.tan(Math.toRadians(perspective / 2)));

        // pick distance to center
        double n = pickYT1 * N;

        // angle enter camera center and y ray
        double beta = -Math.atan(n / distance);

        //distance between bottom projection to pick projection
        double y1 = (a * Math.tan(Math.toRadians(90 - rotation.x) + beta));

        //distance between bottom projection to center projection
        double y2 = (a * Math.tan(Math.toRadians(90 - rotation.x)));

        double y0 = y1 - y2;

        //x compute

        double h1 = (a / Math.cos(Math.toRadians(90 - rotation.x) + beta));

        double h2 = h1 * Math.cos(beta);

        // size of screen at 0
        double M = (h2 * Math.tan(Math.toRadians(perspective / 2)));

        // pick distance to center
        double x0 = pickXT1 * M;

        double xRot = x0 * Math.cos(Math.toRadians(rotation.z)) + y0 * Math.sin(Math.toRadians(rotation.z));
        double yRot = y0 * Math.cos(Math.toRadians(rotation.z)) - x0 * Math.sin(Math.toRadians(rotation.z));

        y = yRot + position.y;
        x = xRot + position.x;

        return new Point2D.Float((float) x, (float) y);

    }

    public float getfitDistance(V3DVect3 size) {
        float sizeX = (float) Math.abs(size.x * Math.sin(Math.toRadians(rotation.z)))
                + (float) Math.abs(size.y * Math.cos(Math.toRadians(rotation.z)));
        float sizeY = (float) Math.abs(size.z * Math.cos(Math.toRadians(rotation.x))
                + Math.sin(Math.toRadians(rotation.x)) * (Math.abs(size.y * Math.sin(Math.toRadians(rotation.z)))
                        + Math.abs(size.x * Math.cos(Math.toRadians(rotation.z)))));

        if (currentHeight <= 0) { // avoid a divide by zero error!
            currentHeight = 1;
        }
        final float h = currentWidth / currentHeight;

        if (sizeY <= 0) { // avoid a divide by zero error!
            sizeY = 1;
        }

        float targetH = sizeX / sizeY;
        float l = 0;

        if (targetH < h) {
            l = 1.1f * Math.abs(sizeY) / 2;
        } else {
            l = 1.1f * Math.abs(sizeX) / (2 * h);
        }

        if (Float.isInfinite(l)) {
            l = 0;
        }

        return (l / (float) Math.tan(Math.toRadians(perspective / 2f)));

    }

    public void fit(final V3DVect3 center, final V3DVect3 size) {
        Runnable fitAction = new Runnable() {

            @Override
            public void run() {
                setPosition(center);
                setDistance(getfitDistance(size));
            }
        };

        if (isConfigured()) {
            fitAction.run();
        } else {
            setCameraInitialisation(fitAction);
        }

    }

    public void fit(V3DBoundingBox boundingBox) {
        V3DVect3 scenePosition = boundingBox.getPosition();
        V3DVect3 sceneSize = boundingBox.getSize();
        V3DVect3 center = new V3DVect3(scenePosition.x, scenePosition.y, scenePosition.z);
        fit(center, sceneSize.multiply(1.2f));
    }

    @Override
    public void fitAll() {
        V3DBoundingBox bbox = currentScene.getRootElement().getBoundingBox();
        fit(bbox);
    }

    public boolean containsAll() {
        I3dElement rootElt = null;
        if (currentScene != null) {
            rootElt = currentScene.getRootElement();
        }
        if (rootElt == null) {
            return true;
        } else {
            V3DVect3 sceneSize = rootElt.getBoundingBox().getSize();
            return (getfitDistance(sceneSize) < distance);
        }
    }

    @Override
    public void fitAllIfInvalid() {
        if (distance == 0) {
            fitAll();
        }
    }

    //Position and Rotation controller

    List<Camera3DChangeListener> camera3DChangeListeners = new ArrayList<Camera3DChangeListener>();

    public void addCameraChangeListener(Camera3DChangeListener listener) {
        camera3DChangeListeners.add(listener);
    }

    public void removeCameraChangeListener(Camera3DChangeListener listener) {
        camera3DChangeListeners.remove(listener);
    }

    public void firePositionChanged() {
        for (Camera3DChangeListener listener : camera3DChangeListeners) {
            listener.positionChanged();
        }
    }

    public void fireRotationChanged() {
        for (Camera3DChangeListener listener : camera3DChangeListeners) {
            listener.rotationChanged();
        }
    }

    @Override
    public void center(V3DVect3 position) {
        setPosition(position);
    }

    public interface Camera3DChangeListener {
        public void positionChanged();

        public void rotationChanged();
    }

}