Package com.bbn.openmap.layer.rpf

Source Code of com.bbn.openmap.layer.rpf.RpfCacheManager$RpfMaps

// **********************************************************************
//
// <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/layer/rpf/RpfCacheManager.java,v $
// $RCSfile: RpfCacheManager.java,v $
// $Revision: 1.3.2.1 $
// $Date: 2004/10/14 18:27:14 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.layer.rpf;

import java.io.Serializable;

import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.omGraphics.*;
import com.bbn.openmap.proj.CADRG;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;

/**
* The RpfCacheManager is the object you need if you want to retrieve
* RPF files. You set it up with a RpfFrameProvider, and it gives that
* provider to the RpfCacheHandler it creates. The RpfCacheManager
* then handles working with the RpfCacheHandlers to get subframes to
* display.
* <P>
*
* RPF data comes with a Table of Contents, which sits at the root of
* the RPF file system structure and contains information about the
* frame files. When the RpfFrameProvider gets created, it creates an
* array of RpfTocHandlers. These Table of Contents readers know how
* to take a geographic area and figure out which frames and subframes
* are needed to put on the screen. An array of RpfTocHandlers are
* needed in case there are many places where there is RPF data.
* <P>
*
* The RpfCacheManager also manages objects called RpfCacheHandlers.
* Cache handlers take the information from a frame provider, and
* create a subframe cache for that zone and map type. The situation
* gets pretty tricky when the screen has the equator and/or the
* dateline on it, and a different cache handler is needed for each
* quadrant of the earth. This situation is relatively rare, though,
* and the RpfCacheManager automatically checks for these situations
* and creates the cache handlers needed.
* <P>
* There are two calls to the Cache that you need to use. The
* constructor sets up the cache with the location of the data. The
* getRectangle() call returns an OMGraphicList of objects to draw,
* that cover the area asked for.
*/
public class RpfCacheManager implements Serializable {

    /**
     * The size of the smaller caches, when more cachehandlers are
     * needed to cover the equator and the dateline. Lowered from 20
     * to try to conserve memory.
     */
    public final static int SMALL_CACHE_SIZE = 10;
    /** A box is a earth quadrant. */
    public final static int MAX_NUM_BOXES = 4;
    /**
     * The cache handlers needed to cover the screen. Need one for
     * each earth quadrant, and for each RPF directory, in case
     * coverage is spread out over different sources.
     */
    protected RpfCacheHandler[] caches = new RpfCacheHandler[MAX_NUM_BOXES];
    /** The place to look for for image data. */
    protected RpfFrameProvider frameProvider;
    /**
     * Contains information about displaying the RPF data. Also passed
     * to the RpfTocHandlers to determine chart selection.
     *
     * @see RpfViewAttributes
     */
    protected RpfViewAttributes viewAttributes;
    /**
     * A specialized OMGraphicList to handle the maps and info, and
     * switching either/or on/off.
     */
    protected RpfMaps graphics;
    /**
     * The size of the aux caches, which are used when the map crosses
     * the equator or dateline.
     */
    protected int auxCacheSize;

    public RpfCacheManager() {}

    /**
     * Constructor that lets you set the RPF frame provider
     *
     * @param fp the object supplying the data.
     */
    public RpfCacheManager(RpfFrameProvider fp) {
        this(fp, new RpfViewAttributes());
    }

    /**
     * Constructor that lets you set the RPF frame provider, the view
     * attributes and the subframe cache size.
     *
     * @param rfp the object supplying the data.
     * @param rva the view attributes for the images.
     */
    public RpfCacheManager(RpfFrameProvider rfp, RpfViewAttributes rva) {
        this(rfp, rva, RpfCacheHandler.SUBFRAME_CACHE_SIZE, SMALL_CACHE_SIZE);
    }

    /**
     * Constructor that lets you set the RPF frame provider, the view
     * attributes and the subframe cache sizes.
     *
     * @param rfp the object supplying the data.
     * @param rva the view attributes for the images.
     * @param mainCacheSize the number of subframes held in the large
     *        main cache.
     * @param auxSubframeCacheSize the number of subframes held in the
     *        aux caches.
     */
    public RpfCacheManager(RpfFrameProvider rfp, RpfViewAttributes rva,
            int mainCacheSize, int auxSubframeCacheSize) {
        frameProvider = rfp;
        viewAttributes = rva;
        caches[0] = new RpfCacheHandler(rfp, rva, mainCacheSize);
        graphics = new RpfMaps(rva);
        auxCacheSize = auxSubframeCacheSize;
    }

    //      public void finalize() {
    //      Debug.message("gc", "RpfCacheManager: getting GC'd");
    //      }

    /**
     * Reset the caches in the RpfCacheHandlers.
     */
    public void clearCaches() {
        for (int i = 0; i < caches.length; i++) {
            if (caches[i] != null) {
                caches[i].clearCache();
            }
        }
    }

    /**
     * Set the view attributes for the layer. The frame provider view
     * attributes are updated, and the cache is cleared.
     *
     * @param rva the RpfViewAttributes used for the layer.
     */
    public void setViewAttributes(RpfViewAttributes rva) {
        viewAttributes = rva;
        for (int i = 0; i < caches.length; i++) {
            if (caches[i] != null) {
                caches[i].setViewAttributes(viewAttributes);
            }
        }
    }

    /**
     * Get the view attributes or the layer.
     *
     * @return RpfViewAttributes.
     */
    public RpfViewAttributes getViewAttributes() {
        return viewAttributes;
    }

    /**
     * Set the RpfFrameProvider for the layer. Clears out the cache,
     * and the frame provider gets the RpfViewAttributes held by the
     * layer.
     *
     * @param fp the frame provider.
     */
    public void setFrameProvider(RpfFrameProvider fp) {
        frameProvider = fp;

        for (int i = 0; i < caches.length; i++) {
            if (caches[i] != null) {
                caches[i].setFrameProvider(fp);
            }
        }
    }

    /**
     * Return RpfFrameProvider used by the layer.
     */
    public RpfFrameProvider getFrameProvider() {
        return frameProvider;
    }

    /**
     * Returns the Vector containing RpfCoverageBoxes from the primary
     * RpfCacheHandler. The Vector is the same that was returned to
     * the cache handler from the RpfFrameProvider as a result of the
     * last setCache call. These provide rudimentary knowledge about
     * what is being displayed.
     *
     * @return Vector of RpfCoverageBoxes.
     */
    public java.util.Vector getCoverageBoxes() {
        return caches[0].getCoverageBoxes();
    }

    /**
     * The call to the cache that lets you choose what kind of
     * information is returned. This function also figures out what
     * part of the earth is covered on the screen, and creates
     * auxillary cache handlers as needed. The CADRG projection held
     * inside the view attributes, used by the RpfTocHandlers, is set
     * here. If the projection passed in is not CADRG, and the caller
     * doesn't care, then a new CADRG projection is created.
     *
     * @param proj the projection of the screen.
     */
    public OMGraphicList getRectangle(Projection proj) {

        float[] lat = new float[3];
        float[] lon = new float[3];

        // This should be checked by the caller.
        if (!(proj instanceof CADRG)) {
            if (viewAttributes.requireProjection) {
                return new OMGraphicList();
            } else {
                viewAttributes.proj = new CADRG(proj.getCenter(), proj.getScale(), proj.getWidth(), proj.getHeight());
            }
        } else {
            viewAttributes.proj = (CADRG) proj;
        }

        // Need to update the view attributes of the frame provider if
        // it is remote.
        if (frameProvider != null && frameProvider.needViewAttributeUpdates()) {
            frameProvider.setViewAttributes(viewAttributes);
        }

        // Hand off coordinates and scale to RpfCacheHandler.
        // Then the RpfCacheHandler will figure out the frames to load
        // and add to the display list.

        // This next bit of mumbo jumbo is to handle the equator and
        // dateline: Worst case, crossing both, treat each area
        // separately, so it is the same as handling four requests for
        // data - above and below the equator, and left and right of
        // the dateline. Normal case, there is only one box. Two
        // boxes if crossing only one of the boundaries.

        int xa = 2;
        int ya = 2;
        int lat_minus = 2;
        int lon_minus = 2;
        // Set up checks for equator and dateline
        LatLonPoint ll1 = proj.getUpperLeft();
        LatLonPoint ll2 = proj.getLowerRight();

        lat[0] = ll1.getLatitude();
        lon[0] = ll1.getLongitude();
        lat[1] = ll2.getLatitude();
        lon[1] = ll2.getLongitude();
        lat[2] = ll2.getLatitude();
        lon[2] = ll2.getLongitude();

        if (lon[0] > 0 && lon[2] < 0) {
            lon[1] = -179.999f; // put a little breather on the
                                // dateline
            lon_minus = 1;
        }
        if (lat[0] > 0 && lat[2] < 0) {
            lat[1] = -0.0001f; // put a little breather on the equator
            lat_minus = 1;
        }

        if (Debug.debugging("rpf")) {
            Debug.output("RpfCacheManager - for:");
            Debug.output("\tlat[0] " + lat[0]);
            Debug.output("\tlon[0] " + lon[0]);
            Debug.output("\tlat[1] " + lat[1]);
            Debug.output("\tlon[1] " + lon[1]);
            Debug.output("\tlat[2] " + lat[2]);
            Debug.output("\tlon[2] " + lon[2]);
            Debug.output("\tlat_minus = " + lat_minus);
            Debug.output("\tlon_minus = " + lon_minus);
        }

        /*
         * Worst case, there are four boxes on the screen. Best case,
         * there is one. The things that create boxes and dictates how
         * large they are are the equator and the dateline. When the
         * screen straddles one or both of these lat/lon lines,
         * lon_minus and lat_minus get adjusted, causing two or four
         * different calls to the tochandler to get the data
         * above/below the equator, and left/right of the dateline.
         * Plus, each path gets checked until the required boxes are
         * filled.
         */

        // Normal (maybe) box[0] gets filled every time - bottom right
        // box.
        caches[0].setCache(lat[ya - lat_minus],
                lon[xa - lon_minus],
                lat[ya],
                lon[xa],
                viewAttributes.proj);

        if (Debug.debugging("rpf"))
            Debug.output("RpfCacheManager: main (1) cache used.");

        // Dateline split
        if (lon_minus == 1) {
            if (caches[1] == null) {
                caches[1] = new RpfCacheHandler(frameProvider, viewAttributes, auxCacheSize);
            }
            caches[1].setCache(lat[ya - lat_minus], lon[0], lat[ya], -1f
                    * lon[1], viewAttributes.proj); // -1 to make it
                                                    // 180

            if (Debug.debugging("rpf"))
                Debug.output("-- second cache used");
        } else {
            caches[1] = null;
        }

        // Equator Split
        if (lat_minus == 1) {
            if (caches[2] == null) {
                caches[2] = new RpfCacheHandler(frameProvider, viewAttributes, auxCacheSize);
            }
            caches[2].setCache(lat[0], lon[xa - lon_minus], -1f * lat[1], // flip
                                                                          // breather
                    lon[xa], viewAttributes.proj);

            if (Debug.debugging("rpf"))
                Debug.output("-- third cache used");
        } else {
            caches[2] = null;
        }

        // Both!!
        if (lon_minus == 1 && lat_minus == 1) {
            if (caches[3] == null) {
                caches[3] = new RpfCacheHandler(frameProvider, viewAttributes, auxCacheSize);
            }
            caches[3].setCache(lat[0], lon[0], -1f * lat[1],//  flip
                                                            // breather
                    -1f * lon[1], viewAttributes.proj);// -1 to make
                                                       // it 180, not
                                                       // -180

            if (Debug.debugging("rpf"))
                Debug.output("-- fourth cache used");
        } else {
            caches[3] = null;
        }

        OMGraphicList gl = new OMGraphicList();
        gl.add(getSubframes());
        return gl;
    }

    /**
     * Creates the OMGraphicList by cycling through the caches,
     * getting the images and attribute infomation.
     */
    protected OMGraphic getSubframes() {

        //      graphics = new RpfMaps(viewAttributes);
        graphics.clear();

        if (Debug.debugging("rpf")) {
            Debug.output("RpfCacheManager: show maps: "
                    + viewAttributes.showMaps + ", showInfo: "
                    + viewAttributes.showInfo);
        }

        if (!(viewAttributes.showMaps || viewAttributes.showInfo)) {
            return graphics;
        }

        for (int nbox = 0; nbox < MAX_NUM_BOXES; nbox++) {
            if (caches[nbox] != null && caches[nbox].getGoodData()) {

                int subframeRunningCount = 0;

                for (int subx = caches[nbox].start.x; subx <= caches[nbox].end.x; subx++) {
                    for (int suby = caches[nbox].start.y; suby <= caches[nbox].end.y; suby++) {

                        ///////
                        RpfSubframe subframe = caches[nbox].getCached(subx,
                                suby,
                                subframeRunningCount);
                        ///////

                        if (subframe == null) {
                            if (Debug.debugging("rpf")) {
                                Debug.output("RpfCacheManager: checking other TOCs for subframe.");
                            }
                            subframe = caches[nbox].getSubframeFromOtherTOC(subx,
                                    suby,
                                    subframeRunningCount);
                        }

                        if (subframe != null) {
                            graphics.addInfo(subframe.information);
                            graphics.addInfo(subframe.rectangle);
                            graphics.addMap(subframe.image);

                            if (Debug.debugging("rpf"))
                                Debug.output("RpfCacheManager: Adding subframe "
                                        + subx + ", " + suby);
                        } else {
                            if (Debug.debugging("rpf"))
                                Debug.output("RpfCacheManager: subframe "
                                        + subx + ", " + suby + " empty");
                        }
                        subframeRunningCount++;
                    }
                }
            }
        }

        if (Debug.debugging("rpf")) {
            Debug.output("RpfCacheManager: done.");
        }

        return graphics;
    }

    public class RpfMaps extends OMGraphic {
        public RpfViewAttributes atts;
        public OMGraphicList maps = new OMGraphicList();
        public OMGraphicList infos = new OMGraphicList();

        public RpfMaps(RpfViewAttributes rva) {
            atts = rva;
        }

        public void clear() {
            maps.clear();
            infos.clear();
        }

        public void addMap(OMGraphic graphic) {
            maps.add(graphic);
        }

        public void addInfo(OMGraphic graphic) {
            infos.add(graphic);
        }

        public boolean generate(Projection proj) {
            maps.generate(proj);
            infos.generate(proj);
            return true;
        }

        public void render(java.awt.Graphics g) {
            if (atts.showMaps) {
                maps.render(g);
            }
            if (atts.showInfo) {
                infos.render(g);
            }
        }

        public float distance(int x, int y) {
            return Float.MAX_VALUE;
        }
    }

}
TOP

Related Classes of com.bbn.openmap.layer.rpf.RpfCacheManager$RpfMaps

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.