Package com.bbn.openmap.proj

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

// **********************************************************************
//
// <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/ProjectionFactory.java,v $
// $RCSfile: ProjectionFactory.java,v $
// $Revision: 1.4.2.9 $
// $Date: 2007/01/25 22:09:20 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.proj;

import com.bbn.openmap.Environment;
import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.MapBean;
import com.bbn.openmap.OMComponent;
import com.bbn.openmap.util.Debug;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

/**
* The ProjectionFactory creates Projections. It used to have
* Projection classes hard-coded into it which were accessable through
* static methods, but this paradigm has been changed slightly so the
* ProjectionFactory is actually a singleton which can be accessed by
* a ProjectionFactory.getInstance() static method. This was done so
* that the singleton, when added to the MapHandler, can look for
* ProjectionLoaders to dynamically add projections to the factory.
* For convenience, there are still some static methods on the
* ProjectionFactory class which use the singleton to create and
* return projection objects. Changes to the available projections can
* be discovered through property changes.
* <P>
*
* The ProjectionFactory singleton instance can be added to the
* MapHandler via the openmap.properties file by adding the
* ProjectionFactoryLoader to the openmap.components property. If you
* are using the openmap.properties file to configure your
* application, you MUST add the ProjectionFactoryLoader, or you won't
* see any projections.
*/
public class ProjectionFactory extends OMComponent {

    /**
     * Center lat/lon property parameter for new projections passed to
     * ProjectionLoader.
     */
    public final static String CENTER = "CENTER";
    /**
     * Scale property parameter for new projections passed to
     * ProjectionLoader.
     */
    public final static String SCALE = "SCALE";
    /**
     * Projeciton height (pixels) property parameter for new
     * projections passed to ProjectionLoader.
     */
    public final static String HEIGHT = "HEIGHT";
    /**
     * Projection width (pixels) property parameter for new
     * projections passed to ProjectionLoader.
     */
    public final static String WIDTH = "WIDTH";
    /**
     * Datum property parameter for new projections passed to
     * ProjectionLoader.
     */
    public final static String DATUM = "DATUM";

    /**
     * The property name that is fired when the list of available
     * projections has changed.
     */
    public final static String AvailableProjectionProperty = "AvailableProjections";

    /**
     * PropertyChangeSupport for letting listeners know about new
     * projections that are available from the factory.
     */
    protected PropertyChangeSupport pcs;

    /**
     * Singleton instance.
     */
    protected static ProjectionFactory instance;

    protected Vector projLoaders = new Vector();

    /**
     * Singleton constructor.
     */
    private ProjectionFactory() {
        pcs = new PropertyChangeSupport(this);
    }

    /**
     * Get the singleton instance of the ProjectionFactory.
     */
    public static ProjectionFactory getInstance() {
        if (instance == null) {
            instance = new ProjectionFactory();
        }

        return instance;
    }

    /**
     * Returns an array of Projection names available from this
     * factory.
     */
    public static String[] getAvailableProjections() {
        ProjectionFactory factory = getInstance();

        // duplicate List to handle multiple simultanous requests
        List projLoaders = new ArrayList(factory.getProjectionLoaders());
        int nProjections = projLoaders.size();
        String projNames[] = new String[nProjections];
        int i = 0;

        for (Iterator it = projLoaders.iterator(); it.hasNext();) {
            projNames[i++] = ((ProjectionLoader) it.next()).getPrettyName();
        }

        return projNames;
    }

    /**
     * Return the Projection Class with the given pretty name.
     *
     * @param name
     *            the name of the projection, set in the pretty name of it's
     *            ProjectionLoader.
     * @return Class of Projection, or null if not found.
     */
    public static Class getProjClassForName(String name) {
        if (name != null) {
            for (Iterator it = getInstance().iterator(); it.hasNext();) {
                ProjectionLoader loader = (ProjectionLoader) it.next();
                if (name.equalsIgnoreCase(loader.getPrettyName())) {
                    return loader.getProjectionClass();
                }
            }

            // If there wasn't a class with the pretty name, check to
            // make sure it wasn't a class name itself. If it fails,
            // return null. We just want to do this in case people
            // start using class names for pretty names.
            try {
                return Class.forName(name);
            } catch (ClassNotFoundException cnfe) {
            }

        }
        return null;
    }

    /**
     * Return an int representing the OpenMap projection, given the
     * name of the projection. Useful for setting a projection based
     * on the name stated in a properties file.
     *
     * @param projName the projection name from the Projection class.
     * @return the projection type number for that name.
     * @deprecated The notion of a projection type number is going
     *             away, use the class of the projection instead.
     */
    public static int getProjType(String projName) {

        int projType = Mercator.MercatorType;

        if (projName == null) {
        } else if (projName.equalsIgnoreCase(Mercator.MercatorName))
            projType = Mercator.MercatorType;
        else if (projName.equalsIgnoreCase(MercatorView.MercatorViewName))
            projType = MercatorView.MercatorViewType;
        else if (projName.equalsIgnoreCase(Orthographic.OrthographicName))
            projType = Orthographic.OrthographicType;
        else if (projName.equalsIgnoreCase(OrthographicView.OrthographicViewName))
            projType = OrthographicView.OrthographicViewType;
        else if (projName.equalsIgnoreCase(LLXY.LLXYName))
            projType = LLXY.LLXYType;
        else if (projName.equalsIgnoreCase(LLXYView.LLXYViewName))
            projType = LLXYView.LLXYViewType;
        else if (projName.equalsIgnoreCase(CADRG.CADRGName))
            projType = CADRG.CADRGType;
        else if (projName.equalsIgnoreCase(Gnomonic.GnomonicName))
            projType = Gnomonic.GnomonicType;

        return projType;
    }

    /**
     * Makes a new projection based on the given projection and given
     * type.
     * <p>
     * The <code>centerLat</code>,<code>centerLon</code>,
     * <code>scale</code>,<code>width</code>, and
     * <code>height</code> parameters are taken from the given
     * projection, and the type is taken from the type argument.
     *
     * @param newProjType the type for the resulting projection
     * @param p the projection from which to copy other parameters
     * @deprecated The notion of a projection type number is going
     *             away, use the class of the projection instead.
     */
    public static Projection makeProjection(int newProjType, Projection p) {
        LatLonPoint ctr = p.getCenter();
        return makeProjection(newProjType,
                ctr.getLatitude(),
                ctr.getLongitude(),
                p.getScale(),
                p.getWidth(),
                p.getHeight());
    }

    /**
     * Create a projection.
     *
     * @param projType projection type
     * @param centerLat center latitude in decimal degrees
     * @param centerLon center latitude in decimal degrees
     * @param scale float scale
     * @param width pixel width of projection
     * @param height pixel height of projection
     * @return Projection
     * @deprecated The notion of a projection type number is going
     *             away, use the class of the projection instead.
     */
    public static Projection makeProjection(int projType, float centerLat,
                                            float centerLon, float scale,
                                            int width, int height) {

        Class projClass = null;
        switch (projType) {
        case CADRG.CADRGType:
            projClass = com.bbn.openmap.proj.CADRG.class;
            break;
        case Mercator.MercatorType:
            projClass = com.bbn.openmap.proj.Mercator.class;
            break;
        case MercatorView.MercatorViewType:
            projClass = com.bbn.openmap.proj.MercatorView.class;
            break;
        case LLXY.LLXYType:
            projClass = com.bbn.openmap.proj.LLXY.class;
            break;
        case LLXYView.LLXYViewType:
            projClass = com.bbn.openmap.proj.LLXYView.class;
            break;
        case Orthographic.OrthographicType:
            projClass = com.bbn.openmap.proj.Orthographic.class;
            break;
        case OrthographicView.OrthographicViewType:
            projClass = com.bbn.openmap.proj.OrthographicView.class;
            break;
        case Gnomonic.GnomonicType:
            projClass = com.bbn.openmap.proj.Gnomonic.class;
            break;
        default:
            System.err.println("Unknown projection type " + projType
                    + " in ProjectionFactory.create()");
        }

        return makeProjection(projClass,
                centerLat,
                centerLon,
                scale,
                width,
                height);
    }

    /**
     * Makes a new projection based on the given projection class name
     * and parameters from the given projection.
     */
    public static Projection makeProjection(String projClassName, Projection p) {

        LatLonPoint ctr = p.getCenter();
        return makeProjection(projClassName,
                ctr.getLatitude(),
                ctr.getLongitude(),
                p.getScale(),
                p.getWidth(),
                p.getHeight());
    }

    /**
     * Create a projection. If the Class for the classname can't be
     * found, a Mercator projection will be returned.
     *
     * @param projClassName the classname of the projection.
     * @param centerLat center latitude in decimal degrees.
     * @param centerLon center latitude in decimal degrees.
     * @param scale float scale.
     * @param width pixel width of projection.
     * @param height pixel height of projection.
     * @return Projection
     */
    public static Projection makeProjection(String projClassName,
                                            float centerLat, float centerLon,
                                            float scale, int width, int height) {

        if (projClassName == null) {
            throw new ProjectionException("No projection class name specified");
        }

        try {
            return makeProjection(Class.forName(projClassName),
                    centerLat,
                    centerLon,
                    scale,
                    width,
                    height);
        } catch (ClassNotFoundException cnfe) {
            throw new ProjectionException("Projection class " + projClassName
                    + " not found");
        }
    }

    /**
     * Create a projection. If the class can't be found, a Mercator
     * projection will be returned.
     *
     * @param projClass the class of the projection.
     * @param centerLat center latitude in decimal degrees.
     * @param centerLon center latitude in decimal degrees.
     * @param scale float scale.
     * @param width pixel width of projection.
     * @param height pixel height of projection.
     * @return Projection
     */
    public static Projection makeProjection(Class projClass, float centerLat,
                                            float centerLon, float scale,
                                            int width, int height) {

        ProjectionFactory factory = getInstance();

        ProjectionLoader loader = MercatorLoader.defaultMercator;

        for (Iterator it = factory.iterator(); it.hasNext();) {
            ProjectionLoader pl = (ProjectionLoader) it.next();
            if (pl.getProjectionClass() == projClass) {
                loader = pl;
            }
        }

        return factory.makeProjection(loader,
                centerLat,
                centerLon,
                scale,
                width,
                height);
    }

    /**
     * Looks at the Environment settings for the default projection
     * and returns a Projection suited for those settings. If there is
     * a problem creating the projection, the default projection of
     * the MapBean will be returned. The ProjectionFactory needs to be
     * loaded with the Projection class described in the properties
     * before this will return an expected projection.
     *
     * @return Projection from Environment settings.
     */
    public static Projection getDefaultProjectionFromEnvironment() {
        return getDefaultProjectionFromEnvironment(0, 0);
    }

    /**
     * Looks at the Environment settings for the default projection
     * and returns a Projection suited for those settings. If there is
     * a problem creating the projection, the default projection of
     * the MapBean will be returned. The ProjectionFactory needs to be
     * loaded with the Projection class described in the properties
     * before this will return an expected projection.
     *
     * @param width pixel height of projection. If 0 or less, the
     *        Environment.Width value will be used.
     * @param height pixel height of projection. If 0 or less, the
     *        Environment.Height value will be used.
     * @return Projection from Environment settings, fit for the pixel
     *         height and width provided.
     */
    public static Projection getDefaultProjectionFromEnvironment(int width,
                                                                 int height) {
        // Initialize the map projection, scale, center
        // with user prefs or defaults
        Projection proj = null;

        int w = (width <= 0) ? Environment.getInteger(Environment.Width,
                MapBean.DEFAULT_WIDTH) : width;
        int h = (height <= 0) ? Environment.getInteger(Environment.Height,
                MapBean.DEFAULT_HEIGHT) : height;

        try {
            proj = ProjectionFactory.makeProjection(Environment.get(Environment.Projection),
                    Environment.getFloat(Environment.Latitude, 0f),
                    Environment.getFloat(Environment.Longitude, 0f),
                    Environment.getFloat(Environment.Scale,
                            Float.POSITIVE_INFINITY),
                    w,
                    h);

        } catch (com.bbn.openmap.proj.ProjectionException pe) {
            if (Debug.debugging("proj")) {
                Debug.output("ProjectionFactory.getDefaultProjectionFromEnvironment(): Can't use ("
                        + Environment.Projection
                        + " = "
                        + Environment.get(Environment.Projection)
                        + ") property as a projection class, need a class name instead.  Using default of com.bbn.openmap.proj.Mercator.");
            }
            proj = ProjectionFactory.makeProjection(Mercator.class,
                    Environment.getFloat(Environment.Latitude, 0f),
                    Environment.getFloat(Environment.Longitude, 0f),
                    Environment.getFloat(Environment.Scale,
                            Float.POSITIVE_INFINITY),
                    w,
                    h);
        }

        return proj;
    }

    /**
     * Call the provided ProjectionLoader to create the projection
     * with the given parameters. The parameters are converted to
     * Properties before being passed to the ProjectionLoader.
     *
     * @param centerLat center latitude in decimal degrees.
     * @param centerLon center latitude in decimal degrees.
     * @param scale float scale.
     * @param width pixel width of projection.
     * @param height pixel height of projection.
     */
    public Projection makeProjection(ProjectionLoader loader, float centerLat,
                                     float centerLon, float scale, int width,
                                     int height) {
        return makeProjection(loader,
                centerLat,
                centerLon,
                scale,
                width,
                height,
                null);
    }

    /**
     * Call the provided ProjectionLoader to create the projection
     * with the given parameters. The parameters are converted to
     * Properties before being passed to the ProjectionLoader. The
     * ProjectionLoader should throw a ProjectionException from here
     * if it has a problem creating the projection with the provided
     * parameters.
     *
     * @param loader projection loader to use.
     * @param centerLat center latitude in decimal degrees.
     * @param centerLon center latitude in decimal degrees.
     * @param scale float scale.
     * @param width pixel width of projection.
     * @param height pixel height of projection.
     * @param projProps a Properties object to add the parameters
     *        to, which can include extra parameters that are needed
     *        by this particular projection loader. If null, a
     *        Properties object will be created.
     * @return projection, or null if the projection can't be created.
     */
    public Projection makeProjection(ProjectionLoader loader, float centerLat,
                                     float centerLon, float scale, int width,
                                     int height, Properties projProps) {

        Projection proj = null;
        if (loader == null) {
            Debug.error("ProjectionFactory.makeProjection() not given a ProjectionLoader to use to create a Projection");
            return proj;
        }

        if (projProps == null) {
            projProps = new Properties();
        }

        projProps.put(CENTER, new LatLonPoint(centerLat, centerLon));
        projProps.put(SCALE, Float.toString(scale));
        projProps.put(WIDTH, Integer.toString(width));
        projProps.put(HEIGHT, Integer.toString(height));

        proj = loader.create(projProps);

        if (proj == null) {
            Debug.error("ProjectionFactory.makeProjection() tried to create a Projection from a "
                    + loader.getPrettyName()
                    + ", "
                    + loader.getProjectionClass().getName() + ", failed.");
        }

        return proj;
    }

    public void addProjectionLoader(ProjectionLoader loader) {
        projLoaders.add(loader);
        fireLoadersChanged();
    }

    public boolean removeProjectionLoader(ProjectionLoader loader) {
        boolean removed = projLoaders.remove(loader);
        if (removed) {
            fireLoadersChanged();
        }
        return removed;
    }

    public void clearProjectionLoaders() {
        if (projLoaders.size() > 0) {
            projLoaders.clear();
            fireLoadersChanged();
        }
    }

    public Iterator iterator() {
        return projLoaders.iterator();
    }

    public int numProjections() {
        return projLoaders.size();
    }

    public Collection getProjectionLoaders() {
        return Collections.unmodifiableCollection(projLoaders);
    }
       
    protected void fireLoadersChanged() {
        pcs.firePropertyChange(AvailableProjectionProperty, null, projLoaders);
    }

    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        if (pcl != null) {
            pcs.addPropertyChangeListener(pcl);
            pcl.propertyChange(new PropertyChangeEvent(this, AvailableProjectionProperty, null, projLoaders));
        }
    }

    public void addPropertyChangeListener(String propertyName,
                                          PropertyChangeListener pcl) {
        if (pcl != null) {
            pcs.addPropertyChangeListener(propertyName, pcl);
            pcl.propertyChange(new PropertyChangeEvent(this, AvailableProjectionProperty, null, projLoaders));
        }
    }

    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        pcs.removePropertyChangeListener(pcl);
    }

    public void removePropertyChangeListener(String propertyName,
                                             PropertyChangeListener pcl) {
        pcs.removePropertyChangeListener(propertyName, pcl);
    }

    /**
     * Using the MapHandler to find ProjectionLoaders being added from
     * the application.
     */
    public void findAndInit(Object obj) {
        if (obj instanceof ProjectionLoader) {
            addProjectionLoader((ProjectionLoader) obj);
        }
    }

    /**
     * Using the MapHandler to find ProjectionLoaders being removed
     * from the application.
     */
    public void findAndUndo(Object obj) {
        if (obj instanceof ProjectionLoader) {
            removeProjectionLoader((ProjectionLoader) obj);
        }
    }

    /**
     * Convenience method to load default projections into the shared
     * instance of the ProjectionFactory.
     *
     * @return ProjectionFactory shared instance.
     */
    public static ProjectionFactory loadDefaultProjections() {
        return loadDefaultProjections(getInstance());
    }

    /**
     * Convenience method to load default projections into a
     * ProjectionFactory.
     *
     * @param pf
     * @return ProjectionFactory
     */
    public static ProjectionFactory loadDefaultProjections(ProjectionFactory pf) {
        if (pf != null && pf.numProjections() == 0) {
            pf.addProjectionLoader(new com.bbn.openmap.proj.MercatorLoader());
            pf.addProjectionLoader(new com.bbn.openmap.proj.OrthographicLoader());
            pf.addProjectionLoader(new com.bbn.openmap.proj.CADRGLoader());
            pf.addProjectionLoader(new com.bbn.openmap.proj.LLXYLoader());
            pf.addProjectionLoader(new com.bbn.openmap.proj.GnomonicLoader());
        }
        return pf;
    }

}
TOP

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

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.