/* Copyright (C) 2001, 2006 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. */ package gov.nasa.worldwind.view; import gov.nasa.worldwind.geom.Angle; import gov.nasa.worldwind.geom.Matrix; import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.geom.Vec4; import gov.nasa.worldwind.globes.Globe; import gov.nasa.worldwind.util.Logging; /** * @author Patrick Muris from dcollins BasicOrbitViewModel * @version $Id: FlatOrbitViewModel.java 4292 2008-01-29 21:18:10Z dcollins $ */ class FlatOrbitViewModel implements OrbitViewModel { private static class BasicModelCoordinates implements FlatOrbitViewModel.ModelCoordinates { private final Position center; private final Angle heading; private final Angle pitch; private final double zoom; private BasicModelCoordinates(Position center, Angle heading, Angle pitch, double zoom) { if (center == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (heading == null || pitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.center = center; this.heading = heading; this.pitch = pitch; this.zoom = zoom; } public Position getCenterPosition() { return this.center; } public Angle getHeading() { return this.heading; } public Angle getPitch() { return this.pitch; } public double getZoom() { return this.zoom; } } FlatOrbitViewModel() { } public Matrix computeTransformMatrix(Globe globe, Position center, Angle heading, Angle pitch, double zoom) { if (globe == null) { String message = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (center == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (heading == null || pitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // Construct the model-view transform matrix for the specified coordinates. // Because this is a model-view transform, matrices are applied in reverse order. Matrix transform = Matrix.IDENTITY; // Zoom. transform = transform.multiply(Matrix.fromTranslation(0, 0, -zoom)); // Heading and pitch. transform = transform.multiply(Matrix.fromRotationX(pitch.multiply(-1))); transform = transform.multiply(Matrix.fromRotationZ(heading)); // Center position. transform = transform.multiply(computeCenterTransform(globe, center)); return transform; } public ModelCoordinates computeModelCoordinates(Globe globe, Vec4 eyePoint, Vec4 centerPoint, Vec4 up) { if (globe == null) { String message = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (eyePoint == null || centerPoint == null || up == null) { String message = Logging.getMessage("nullValue.Vec4IsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } Matrix modelview = Matrix.fromLookAt(eyePoint, centerPoint, up); return computeModelCoordinates(globe, modelview, centerPoint); } public ModelCoordinates computeModelCoordinates(Globe globe, Matrix modelTransform, Vec4 centerPoint) { if (globe == null) { String message = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (modelTransform == null) { String message = Logging.getMessage("nullValue.MatrixIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (centerPoint == null) { String message = Logging.getMessage("nullValue.Vec4IsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // Compute the center position, and center position transform. Position centerPos = globe.computePositionFromPoint(centerPoint); Matrix centerTransform = computeCenterTransform(globe, centerPos); Matrix centerTransformInv = centerTransform.getInverse(); if (centerTransformInv == null) { String message = Logging.getMessage("generic.NoninvertibleMatrix"); Logging.logger().severe(message); throw new IllegalStateException(message); } // Compute the heading-pitch-zoom transform. Matrix hpzTransform = modelTransform.multiply(centerTransformInv); // Extract the heading, pitch, and zoom values from the transform. Angle heading = hpzTransform.getRotationZ(); Angle pitch = hpzTransform.getRotationX(); Vec4 zoomVec = hpzTransform.getTranslation(); if (heading != null && pitch != null && zoomVec != null) return new BasicModelCoordinates(centerPos, heading, pitch.multiply(-1), zoomVec.getLength3()); else return null; } // TODO: Adapt to flat world (OK) private static Matrix computeCenterTransform(Globe globe, Position center) { Matrix transform = Matrix.IDENTITY; if (globe != null && center != null) { // Flat sea level at zero on z, no need to move from globe center to surface. // No need to compute "spherical coordinates" for center, because Globe is computing the translation. // Center latitude and longitude. Use translation for lat/lon placement. Vec4 centerPoint = globe.computePointFromPosition(center); // Globe center point. Vec4 globeCenter = globe.getCenter(); transform = transform.multiply(Matrix.fromTranslation(-centerPoint.x, -centerPoint.y, -centerPoint.z)); transform = transform.multiply(Matrix.fromTranslation(-globeCenter.x, -globeCenter.y, -globeCenter.z)); } return transform; } }