/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * This library 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; * version 2.1 of the License. * * This library 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. */ package org.geotoolkit.display3d.scene.camera; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; import org.apache.sis.geometry.GeneralDirectPosition; import javax.vecmath.Vector3f; import javax.vecmath.Vector3d; import java.nio.FloatBuffer; import java.util.logging.Level; import org.geotoolkit.math.XMath; import org.geotoolkit.display3d.Map3D; import org.geotoolkit.display3d.scene.ContextContainer3D; import org.geotoolkit.display3d.scene.Terrain; /** * @author Thomas Rouby (Geomatys) */ public class TrackBallCamera extends Camera { private final Vector3d scale3d; private float rotateX = 0.0f; private float rotateY = 0.0f; private float rotateZ = 0.0f; public TrackBallCamera(Map3D map){ this(map,new Vector3f(0.0f,0.0f,0.0f),new Vector3f(1.0f,0.0f,0.0f),new Vector3f(0.0f,0.0f,1.0f)); } public TrackBallCamera(Map3D map, Vector3f eye, Vector3f center, Vector3f up){ super(map, eye, center, up); scale3d = new Vector3d(1.0, 1.0, 1.0); } public TrackBallCamera(TrackBallCamera orig) { super(orig); this.rotateX = orig.rotateX; this.rotateY = orig.rotateY; this.rotateZ = orig.rotateZ; this.scale3d = new Vector3d(orig.scale3d); } public TrackBallCamera(Map3D map, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ){ this(map, new Vector3f(eyeX, eyeY, eyeZ), new Vector3f(centerX, centerY, centerZ), new Vector3f(upX, upY, upZ)); } /** Global scene scale */ public Vector3d getScale3d() { return scale3d; } public double getProjectionLength(double length){ final double fov = getFovy()*getAspect(); final double angle = Math.toRadians(fov)/2.0; return (((Math.sin(angle)*length)/Math.cos(angle)) * 2.0) / (this.scale3d.x/100.0); } public double getViewScale(double length){ final double distX = this.getProjectionLength(length); return distX/getWidth(); } public void updateCameraElevation() { final Terrain terrain = ((ContextContainer3D)getMap().getContainer()).getTerrain(); if(terrain==null) return; GeneralDirectPosition pos = new GeneralDirectPosition(terrain.getEnvelope().getCoordinateReferenceSystem()); pos.setOrdinate(0, center.x); pos.setOrdinate(1, center.y); try { final double alti = terrain.getAltitudeSmoothOf(pos, terrain.getMaxScale()); setCenter(center.x, center.y, (float)alti); } catch (Exception ex) { getLogger().log(Level.WARNING, "", ex); } } public void translate(float x, float y, float z){ this.translate(new Vector3f(x, y, z)); } public void translate(Vector3f translate){ if (Float.isNaN(translate.x) || Float.isNaN(translate.y) || Float.isNaN(translate.z)){ return; } this.center.add(translate); fireConfigChanged(PROP_CENTER); } public Vector3f getDirection(){ final float radAngle = (float)Math.toRadians(this.rotateZ); Vector3f direction = new Vector3f(0.0f,1.0f,0.0f); direction = new Vector3f( direction.x*(float)Math.cos(-radAngle) + direction.y*-(float)Math.sin(-radAngle), direction.x*(float)Math.sin(-radAngle) + direction.y*(float)Math.cos(-radAngle), 0.0f); direction.normalize(); return direction; } public Vector3f getLeft(){ Vector3f direction = this.getDirection(); return new Vector3f(-direction.y, direction.x, 0.0f); } @Override public float getLength() { return this.getEye().length(); } @Override public void moveFront(final float move){ Vector3f viewDir = this.getDirection(); viewDir.normalize(); viewDir.scale(move); this.translate(viewDir); } @Override public void moveBack(final float move){ this.moveFront(-move); } @Override public void moveLeft(final float move) { Vector3f viewLeft = this.getLeft(); viewLeft.normalize(); viewLeft.scale(move); this.translate(viewLeft); } @Override public void moveRight(final float move) { this.moveLeft(-move); } @Override public void moveUp(final float move) { this.rotateUp(move); } @Override public void moveDown(final float move) { this.rotateDown(move); } @Override public void rotateLeft(final float move) { this.rotateZ = (float)((this.rotateZ+move)%360.0); fireConfigChanged(PROP_CONFIG); } @Override public void rotateRight(final float move) { this.rotateLeft(-move); } @Override public void rotateUp(final float move) { this.rotateX = XMath.clamp(this.rotateX + move, -90.0f, 0.0f); fireConfigChanged(PROP_CONFIG); } @Override public void rotateDown(final float move) { this.rotateUp(-move); } @Override public void zoomMore(final float move){ final Vector3f tmpEye = new Vector3f(this.eye); final float distance = tmpEye.length(); if (distance - move <= 0.0f){ return; } tmpEye.normalize(); float length = distance-move; if (this.minLength >= 0.0f){ length = Math.max(this.minLength, distance-move); } if (this.maxLength >= 0.0f){ length = Math.min(this.maxLength, distance-move); } tmpEye.scale(length); this.setEye(tmpEye); } @Override public void zoomLess(final float move){ this.zoomMore(-move); } @Override public void zoomTo(float distance) { if (this.minLength >= 0.0f){ distance = Math.max(this.minLength, distance); } if (this.maxLength >= 0.0f){ distance = Math.min(this.maxLength, distance); } final Vector3f tmpEye = new Vector3f(this.eye); tmpEye.normalize(); tmpEye.scale(distance); this.setEye(tmpEye); } @Override public FloatBuffer generatePMvMatrix(){ this.pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); this.pmvMatrix.glLoadIdentity(); this.pmvMatrix.gluPerspective(this.getFovy(), this.getAspect(), this.getNear(), this.getFar()); this.pmvMatrix.gluLookAt(this.getEye().x, this.getEye().y, this.getEye().z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); this.pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); this.pmvMatrix.glLoadIdentity(); this.pmvMatrix.update(); return pmvMatrix.glGetPMvMatrixf(); } public float getRotateX() { return rotateX; } public float getRotateY() { return rotateY; } public float getRotateZ() { return rotateZ; } public void setRotateX(float rotateX) { if(this.rotateX == rotateX) return; this.rotateX = rotateX; fireConfigChanged(PROP_CONFIG); } public void setRotateY(float rotateY) { if(this.rotateY == rotateY) return; this.rotateY = rotateY; fireConfigChanged(PROP_CONFIG); } public void setRotateZ(float rotateZ) { if(this.rotateZ == rotateZ) return; this.rotateZ = rotateZ; fireConfigChanged(PROP_CONFIG); } }