Package com.bbn.openmap.proj

Source Code of com.bbn.openmap.proj.Orthographic

// **********************************************************************
//
// <copyright>
//
//  BBN Technologies
//  10 Moulton Street
//  Cambridge, MA 02138
//  (617) 873-8000
//
//  Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/proj/Orthographic.java,v $
// $RCSfile: Orthographic.java,v $
// $Revision: 1.3.2.1 $
// $Date: 2004/10/14 18:27:37 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.proj;

import java.awt.Point;
import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.MoreMath;
import com.bbn.openmap.util.Debug;

/**
* Implements the Orthographic projection.
*/
public class Orthographic extends Azimuth {

    /**
     * The Orthographic name.
     */
    public final static transient String OrthographicName = "Orthographic";

    /**
     * The Orthographic type of projection.
     */
    public final static transient int OrthographicType = 7;

    protected int hy, wx;

    // almost constant projection parameters
    protected float cosCtrLat;
    protected float sinCtrLat;

    public final static transient float epsilon = 0.0001f;
    protected final static transient float NORTH_BOUNDARY = NORTH_POLE
            - epsilon;
    protected final static transient float SOUTH_BOUNDARY = -NORTH_BOUNDARY;

    /**
     * Construct an Orthographic projection.
     *
     * @param center LatLonPoint center of projection
     * @param scale float scale of projection
     * @param width width of screen
     * @param height height of screen
     */
    public Orthographic(LatLonPoint center, float scale, int width, int height) {
        super(center, scale, width, height, OrthographicType);
        setMinScale(1000.0f);
    }

    /**
     * Construct an Orthographic projection.
     *
     * @param center LatLonPoint center of projection
     * @param scale float scale of projection
     * @param width width of screen
     * @param height height of screen
     * @param type subclass's type
     */
    public Orthographic(LatLonPoint center, float scale, int width, int height,
            int type) {
        super(center, scale, width, height, type);
        setMinScale(1000.0f);
    }

    //    protected void finalize() {
    //      Debug.message("proj", "Orthographic finalized");
    //    }

    /**
     * Return stringified description of this projection.
     *
     * @return String
     * @see Projection#getProjectionID
     */
    public String toString() {
        return "Orthographic[" + super.toString();
    }

    /**
     * Called when some fundamental parameters change.
     * <p>
     * Each projection will decide how to respond to this change. For
     * instance, they may need to recalculate "constant" paramters
     * used in the forward() and inverse() calls.
     * <p>
     */
    protected void computeParameters() {
        Debug.message("proj", "Orthographic.computeParameters()");
        super.computeParameters();

        // do some precomputation of stuff
        cosCtrLat = (float) Math.cos(ctrLat);
        sinCtrLat = (float) Math.sin(ctrLat);

        // compute the offsets
        hy = height / 2;
        wx = width / 2;
    }

    /**
     * Sets radian latitude to something sane. This is an abstract
     * function since some projections don't deal well with extreme
     * latitudes.
     * <p>
     *
     * @param lat float latitude in radians
     * @return float latitude (-PI/2 &lt;= y &lt;= PI/2)
     * @see com.bbn.openmap.LatLonPoint#normalize_latitude(float)
     * 
     */
    public float normalize_latitude(float lat) {
        if (lat > NORTH_BOUNDARY) {
            return NORTH_BOUNDARY;
        } else if (lat < SOUTH_BOUNDARY) {
            return SOUTH_BOUNDARY;
        }
        return lat;
    }

    /**
     * Check if a given lat/lon is within the visible hemisphere.
     *
     * @param phi1 latitude
     * @param lambda0 longitude
     * @param phi latitude
     * @param lambda longitude
     * @return boolean true if within the visible hemisphere, false if
     *         not
     */
    final public static boolean hemisphere_clip(float phi1, float lambda0,
                                                float phi, float lambda) {
        return (GreatCircle.spherical_distance(phi1, lambda0, phi, lambda)/*-epsilon*/<= MoreMath.HALF_PI);
    }

    /**
     * Calculate point along edge of hemisphere (using center point
     * and current azimuth).
     * <p>
     * This is invoked for points that aren't visible in the current
     * hemisphere.
     *
     * @param p Point
     * @return Point p
     */
    private Point edge_point(Point p, float current_azimuth) {
        LatLonPoint tmpll = GreatCircle.spherical_between(ctrLat,
                ctrLon,
                MoreMath.HALF_PI/*-epsilon*/,
                current_azimuth);

        float phi = tmpll.radlat_;
        float lambda = tmpll.radlon_;
        float cosPhi = (float) Math.cos(phi);
        float lambdaMinusCtrLon = (float) (lambda - ctrLon);

        p.x = (int) (scaled_radius * cosPhi * (float) Math.sin(lambdaMinusCtrLon))
                + wx;
        p.y = hy
                - (int) (scaled_radius * (cosCtrLat * (float) Math.sin(phi) - sinCtrLat
                        * cosPhi * (float) Math.cos(lambdaMinusCtrLon)));
        return p;
    }

    /**
     * Checks if a LatLonPoint is plot-able.
     * <p>
     * A point is plot-able if it is within the visible hemisphere.
     *
     * @param lat float latitude in decimal degrees
     * @param lon float longitude in decimal degrees
     * @return boolean
     */
    public boolean isPlotable(float lat, float lon) {
        lat = normalize_latitude(ProjMath.degToRad(lat));
        lon = wrap_longitude(ProjMath.degToRad(lon));
        return hemisphere_clip(ctrLat, ctrLon, lat, lon);
    }

    /**
     * Forward project a point. If the point is not within the
     * viewable hemisphere, return flags in AzimuthVar variable if
     * specified.
     *
     * @param phi float latitude in radians
     * @param lambda float longitude in radians
     * @param p Point
     * @param azVar AzimuthVar or null
     * @return Point pt
     */
    protected Point _forward(float phi, float lambda, Point p, AzimuthVar azVar) {
        float cosPhi = (float) Math.cos(phi);
        float lambdaMinusCtrLon = (float) (lambda - ctrLon);

        // normalize invalid point to the edge of the sphere
        if (!hemisphere_clip(ctrLat, ctrLon, phi, lambda)) {
            float az = GreatCircle.spherical_azimuth(ctrLat,
                    ctrLon,
                    phi,
                    lambda);
            if (azVar != null) {
                azVar.invalid_forward = true; // set the invalid flag
                azVar.current_azimuth = az; // record azimuth of this
                                            // point
            }
            return edge_point(p, az);
        }

        p.x = (int) (scaled_radius * cosPhi * (float) Math.sin(lambdaMinusCtrLon))
                + wx;
        p.y = hy
                - (int) (scaled_radius * (cosCtrLat * (float) Math.sin(phi) - sinCtrLat
                        * cosPhi * (float) Math.cos(lambdaMinusCtrLon)));
        return p;
    }

    /**
     * Inverse project x,y coordinates into a LatLonPoint.
     *
     * @param x integer x coordinate
     * @param y integer y coordinate
     * @param llp LatLonPoint
     * @return LatLonPoint llp
     * @see Proj#inverse(Point)
     */
    public LatLonPoint inverse(int x, int y, LatLonPoint llp) {
        // convert from screen to world coordinates
        x = x - wx;
        y = hy - y;

        //      Debug.output("Orthographic.inverse: x,y=" + x + "," + y);

        // sqrt(pt . pt)
        float rho = (float) Math.sqrt(x * x + y * y);
        if (rho == 0f) {
            Debug.message("proj", "Orthographic.inverse: center!");
            llp.setLatLon(ProjMath.radToDeg(ctrLat), ProjMath.radToDeg(ctrLon));
            return llp;
        }

        //float c = (float)Math.asin(rho/scaled_radius);
        //float cosC = (float)Math.cos(c);
        //float sinC = (float)Math.sin(c);
        float sinC = rho / scaled_radius;
        float cosC = (float) Math.sqrt(1 - sinC * sinC);

        // calculate latitude
        float lat = (float) Math.asin(cosC * sinCtrLat
                + (y * sinC * (cosCtrLat / rho)));

        // calculate longitude
        float lon;
        if (ctrLat == NORTH_POLE) {
            lon = ctrLon + (float) Math.atan2(x, -y);
        } else if (ctrLat == SOUTH_POLE) {
            lon = ctrLon + (float) Math.atan2(x, y);
        } else {
            lon = ctrLon
                    + (float) Math.atan2((x * sinC),
                            (rho * cosCtrLat * cosC - y * sinCtrLat * sinC));
        }
        //      Debug.output("Orthographic.inverse: lat,lon=" +
        //                         ProjMath.radToDeg(lat) + "," +
        //                         ProjMath.radToDeg(lon));

        // check if point in outer space
        //      if (MoreMath.approximately_equal(lat, ctrLat) &&
        //             MoreMath.approximately_equal(lon, ctrLon) &&
        //             (Math.abs(x-(width/2))<2) &&
        //             (Math.abs(y-(height/2))<2))
        if (Float.isNaN(lat) || Float.isNaN(lon)) {
            //          Debug.message("proj", "Orthographic.inverse(): outer
            // space!");
            lat = ctrLat;
            lon = ctrLon;
        }
        llp.setLatLon(ProjMath.radToDeg(lat), ProjMath.radToDeg(lon));
        return llp;
    }

    /**
     * Inverse project a Point.
     *
     * @param pt x,y Point
     * @param llp resulting LatLonPoint
     * @return LatLonPoint llp
     */
    public LatLonPoint inverse(Point pt, LatLonPoint llp) {
        return inverse(pt.x, pt.y, llp);
    }

    /**
     * Get the upper left (northernmost and westernmost) point of the
     * projection.
     * <p>
     * Returns the upper left point (or closest equivalent) of the
     * projection based on the center point and height and width of
     * screen.
     *
     * @return LatLonPoint
     */
    public LatLonPoint getUpperLeft() {
        LatLonPoint tmp = new LatLonPoint();
        float lat, lon;

        // over north pole
        if (overNorthPole()) {
            lat = NORTH_POLE;
            lon = -DATELINE;
        }

        // over south pole
        else if (overSouthPole()) {
            lon = -DATELINE;

            // get the left top corner
            tmp = inverse(0, 0, tmp);

            // check for invalid
            if (MoreMath.approximately_equal(tmp.radlon_, ctrLon, 0.0001f)) {
                lat = ctrLat + MoreMath.HALF_PI;
            } else {
                // northernmost coord is left top
                lat = tmp.radlat_;
            }
        }

        // view in northern hemisphere
        else if (ctrLat >= 0f) {
            // get the left top corner
            tmp = inverse(0, 0, tmp);

            // check for invalid
            if (MoreMath.approximately_equal(tmp.radlon_, ctrLon, 0.0001f)) {
                lat = inverse(width / 2, 0, tmp).radlat_;
                lon = -DATELINE;
            } else {
                // westernmost coord is left top
                lon = tmp.radlon_;
                // northernmost coord is center top
                lat = inverse(width / 2, 0, tmp).radlat_;
            }
        }

        // view in southern hemisphere
        else {
            // get the left top corner
            tmp = inverse(0, 0, tmp);

            // check for invalid
            if (MoreMath.approximately_equal(tmp.radlon_, ctrLon, 0.0001f)) {
                lat = ctrLat + MoreMath.HALF_PI;
                lon = -DATELINE;
            } else {
                // northernmost coord is left top
                lat = tmp.radlat_;
                // westernmost coord is left bottom
                lon = inverse(0, height - 1, tmp).radlon_;
            }
        }
        tmp.setLatLon(lat, lon, true);
        //      Debug.output("ul="+tmp);
        return tmp;
    }

    /**
     * Get the lower right (southeast) point of the projection.
     * <p>
     * Returns the lower right point (or closest equivalent) of the
     * projection based on the center point and height and width of
     * screen.
     * <p>
     * This is trivial for most cylindrical projections, but much more
     * complicated for azimuthal projections.
     *
     * @return LatLonPoint
     */
    public LatLonPoint getLowerRight() {
        LatLonPoint tmp = new LatLonPoint();
        float lat, lon;

        // over north pole
        if (overNorthPole()) {
            lon = DATELINE;

            // get the right bottom corner
            tmp = inverse(width - 1, height - 1, tmp);

            // check for invalid
            if (MoreMath.approximately_equal(tmp.radlon_, ctrLon, 0.0001f)) {
                lat = ctrLat - MoreMath.HALF_PI;
            } else {
                // southernmost coord is right bottom
                lat = tmp.radlat_;
            }
        }

        // over south pole
        else if (overSouthPole()) {
            lat = SOUTH_POLE;
            lon = DATELINE;
        }

        // view in northern hemisphere
        else if (ctrLat >= 0f) {
            // get the right bottom corner
            tmp = inverse(width - 1, height - 1, tmp);

            // check for invalid
            if (MoreMath.approximately_equal(tmp.radlon_, ctrLon, 0.0001f)) {
                lat = ctrLat - MoreMath.HALF_PI;
                lon = DATELINE;
            } else {
                // southernmost coord is right bottom
                lat = tmp.radlat_;
                // easternmost coord is right top
                lon = inverse(width - 1, 0, tmp).radlon_;
            }
        }

        // view in southern hemisphere
        else {
            // get the right bottom corner
            tmp = inverse(width - 1, height - 1, tmp);

            // check for invalid
            if (MoreMath.approximately_equal(tmp.radlon_, ctrLon, 0.0001f)) {
                lat = inverse(width / 2, height - 1, tmp).radlat_;
                lon = DATELINE;
            } else {
                // easternmost coord is right bottom
                lon = tmp.radlon_;
                // southernmost coord is center bottom
                lat = inverse(width / 2, height - 1, tmp).radlat_;
            }
        }
        tmp.setLatLon(lat, lon, true);
        //      Debug.output("lr="+tmp);
        return tmp;
    }

    /**
     * Get the name string of the projection.
     */
    public String getName() {
        return OrthographicName;
    }

    /*
     * public void testPoint(float lat, float lon) { float x, y; lon =
     * wrap_longitude(ProjMath.degToRad(lon)); lat =
     * normalize_latitude(ProjMath.degToRad(lat)); x = forward_x(lat,
     * lon); y = forward_y(lat, lon);
     *
     * Debug.output("(lon="+ProjMath.radToDeg(lon)+",lat="+
     * ProjMath.radToDeg(lat)+ ") = (x="+x+",y="+y+")"); lat =
     * inverse_lat(x, y); lon = wrap_longitude(inverse_lon(x, y));
     * Debug.output("(x="+x+",y="+y+") = (lon="+
     * ProjMath.radToDeg(lon)+",lat="+ ProjMath.radToDeg(lat)+")"); }
     *
     * public static void main (String argv[]) { Orthographic
     * proj=null; proj = new Orthographic(new LatLonPoint(40.0f,
     * 0.0f), 1.0f, 620, 480);
     *
     * Debug.output("testing"); proj.setEarthRadius(1.0f);
     * Debug.output("setEarthRadius("+proj.getEarthRadius()+")");
     * proj.setPPM(1); Debug.output("setPPM("+proj.getPPM()+")");
     * proj.setMinScale(1.0f);
     * Debug.output("setMinScale("+proj.getMinScale()+")"); try {
     * proj.setScale(1.0f); } catch (java.beans.PropertyVetoException
     * e) { } Debug.output("setScale("+proj.getScale()+")");
     * Debug.output(proj); Debug.output();
     *
     * Debug.output("---testing latitude"); proj.testPoint(0.0f,
     * 0.0f); proj.testPoint(10.0f, 0.0f); proj.testPoint(40.0f,
     * 0.0f); proj.testPoint(-80.0f, 0.0f); proj.testPoint(-90.0f,
     * 0.0f); proj.testPoint(100.0f, 0.0f); proj.testPoint(-3272.0f,
     * 0.0f); Debug.output("---testing longitude");
     * proj.testPoint(0.0f, 10.0f); proj.testPoint(0.0f, -10.0f);
     * proj.testPoint(0.0f, 90.0f); proj.testPoint(0.0f, -90.0f);
     * proj.testPoint(0.0f, 170.0f); proj.testPoint(0.0f, -170.0f);
     * proj.testPoint(0.0f, 180.0f); proj.testPoint(0.0f, -180.0f);
     * proj.testPoint(0.0f, 190.0f); proj.testPoint(0.0f, -190.0f);
     * Debug.output("---testing lat&lon"); proj.testPoint(100.0f,
     * 370.0f); proj.testPoint(-30.0f, -370.0f);
     * proj.testPoint(-80.0f, 550.0f); proj.testPoint(0.0f, -550.0f); }
     */
}
TOP

Related Classes of com.bbn.openmap.proj.Orthographic

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.