package org.osm2world.core.target.common.rendering; import static org.osm2world.core.math.VectorXYZ.Y_UNIT; import org.osm2world.core.math.VectorXYZ; import org.osm2world.core.math.VectorXZ; public class Camera { VectorXYZ up; VectorXYZ pos; VectorXYZ lookAt; /** returns the view direction vector with length 1 */ public VectorXYZ getViewDirection() { //TODO: (performance)? cache viewDirection return lookAt.subtract(pos).normalize(); } /** * returns the vector that is orthogonal to the connection * between pos and lookAt and points to the right of it. * The result has length 1. */ public VectorXYZ getRight() { return getViewDirection().crossNormalized(up); } public VectorXYZ getPos() { return pos; } public VectorXYZ getLookAt() { return lookAt; } public VectorXYZ getUp() { return up; } public void setPos(VectorXYZ pos) { this.pos = pos; } public void setCamera(double posX, double posY, double posZ, double lookAtX, double lookAtY, double lookAtZ) { setPos(posX, posY, posZ); up = Y_UNIT; // some initial setup value setLookAt(lookAtX, lookAtY, lookAtZ); } public void setCamera(double posX, double posY, double posZ, double lookAtX, double lookAtY, double lookAtZ, double upX, double upY, double upZ) { setPos(posX, posY, posZ); up = new VectorXYZ(upX, upY, upZ); setLookAt(lookAtX, lookAtY, lookAtZ); } private void setPos(double x, double y, double z) { this.setPos(new VectorXYZ(x, y, z)); } private void setLookAt(VectorXYZ lookAt) { this.lookAt = lookAt; VectorXYZ right = getRight(); up = right.crossNormalized(getViewDirection()); } private void setLookAt(double x, double y, double z) { this.setLookAt(new VectorXYZ(x, y, z)); } /** * moves pos and lookAt in the view direction * @param step units to move forward */ public void moveForward(double step) { VectorXYZ d = getViewDirection(); move(d.x * step, d.y * step, d.z * step); } /** * moves pos and lookAt forward in the map plane * @param step units to move forward */ public void moveMapForward(double step) { VectorXYZ d = getViewDirection(); VectorXZ md = new VectorXZ(d.x, d.z).normalize(); move(md.x * step, 0, md.z * step); } /** * moves pos and lookAt to the right, orthogonally to the view direction * * @param step units to move right, negative units move to the left */ public void moveRight(double step) { VectorXYZ right = getRight(); move(right.x * step, right.y * step, right.z * step); } /** * moves pos and lookAt to the right in the map plane * * @param step units to move right, negative units move to the left */ public void moveMapRight(double step) { VectorXYZ right = getRight(); VectorXZ md = new VectorXZ(right.x, right.z).normalize(); move(md.x * step, 0, md.z * step); } /** * move pos and lookAt upwards, orthogonally to the view direction * * @param step units to move up, negative units move down */ public void moveUp(double step) { move(up.x * step, up.y * step, up.z * step); } /** * move pos and lookAt upwards in respect to the map plane * * @param step units to move up, negative units move down */ public void moveMapUp(double step) { move(0, step, 0); } /** moves both pos and lookAt by the given vector */ public void move(VectorXYZ move) { pos = pos.add(move); lookAt = lookAt.add(move); } /** moves both pos and lookAt by the given vector */ public void move(double moveX, double moveY, double moveZ) { pos = pos.add(moveX, moveY, moveZ); lookAt = lookAt.add(moveX, moveY, moveZ); } /** * moves lookAt to represent a rotation counterclockwise * around the y axis on pos * * @param d angle in radians */ public void rotateY(double d) { up = up.rotateY(d); VectorXYZ toOldLookAt = lookAt.subtract(pos); VectorXYZ toNewLookAt = toOldLookAt.rotateY(d); lookAt = pos.add(toNewLookAt); } /** * rotates the camera around the yaw axis * * @param d angle in radians */ public void yaw(double d) { VectorXYZ toOldLookAt = lookAt.subtract(pos); VectorXYZ toNewLookAt = toOldLookAt.rotateVec(d, up); lookAt = pos.add(toNewLookAt); } /** * rolls the camera * * @param d angle in radians */ public void roll(double d) { VectorXYZ view = getViewDirection(); up = up.rotateVec(d, view); } /** * rotates the camera around the pitch axis * * @param d angle in radians */ public void pitch(double d) { VectorXYZ right = getRight(); up = up.rotateVec(d, right); VectorXYZ toOldLookAt = lookAt.subtract(pos); VectorXYZ toNewLookAt = toOldLookAt.rotateVec(d, right); lookAt = pos.add(toNewLookAt); } /** * rotates the camera around an axis orthogonal to the y axis * and {@link #getViewDirection()}. * The effect is similar to {@link #pitch(double)}, but independent * from the current roll angle. * * @param d angle in radians */ public void mapPitch(double d) { VectorXYZ right = getViewDirection().crossNormalized(Y_UNIT); up = up.rotateVec(d, right); VectorXYZ toOldLookAt = lookAt.subtract(pos); VectorXYZ toNewLookAt = toOldLookAt.rotateVec(d, right); lookAt = pos.add(toNewLookAt); } @Override public String toString() { return "{pos=" + pos + ", lookAt=" + lookAt + ", up=" + up + "}"; } }