package org.mitre.jdp.coex.mapbuilder.openmap; import com.bbn.openmap.LatLonPoint; import com.bbn.openmap.Layer; import com.bbn.openmap.layer.OMGraphicHandlerLayer; import com.bbn.openmap.layer.location.Location; import com.bbn.openmap.layer.location.LocationLayer; import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.omGraphics.OMPoint; import com.bbn.openmap.proj.Proj; import com.bbn.openmap.proj.ProjMath; import java.util.*; /** * Utility code for use of OpenMap. * * @author David Smiley (dsmiley@mitre.org) */ public class OpenMapUtils { private OpenMapUtils() { } /** * TODO: when autoCenter=false and autoScale=true, scaling isn't right. */ public static void autoAdjustProjection(Proj proj, Collection omGraphics, boolean autoCenter, boolean autoScale, int pixelPadding) { //#get list of LatLonPoint objects from omGraphics list List latlons = new ArrayList(); GetLatLonPointsFromOMGVisitor visitor = new GetLatLonPointsFromOMGVisitor(); visitor.latlons = latlons; visitOMGraphics(omGraphics, visitor); //#short circuit logic if (latlons.isEmpty()) return;//done! //#put latitude and longitude into their own arrays; sorted float[] latDegrees = new float[latlons.size()]; float[] lonDegrees = new float[latlons.size()]; for (int i = 0; i < latlons.size(); i++) { LatLonPoint latLonPoint = (LatLonPoint) latlons.get(i); latDegrees[i] = latLonPoint.getLatitude(); lonDegrees[i] = latLonPoint.getLongitude(); } Arrays.sort(latDegrees); Arrays.sort(lonDegrees); //#find bounding latlons int gdli = greatestDistanceLoopIndex(lonDegrees, -LatLonPoint.DATELINE, LatLonPoint.DATELINE); LatLonPoint upperLeft = new LatLonPoint( latDegrees[latDegrees.length - 1], lonDegrees[(gdli + 1) % (lonDegrees.length)]); LatLonPoint lowerRight = new LatLonPoint( latDegrees[0], lonDegrees[gdli]); //#set center if (autoCenter) { LatLonPoint centerLL = new LatLonPoint( upperLeft.getLatitude() - (upperLeft.getLatitude() - lowerRight.getLatitude()) / 2, lowerRight.getLongitude() - (lowerRight.getLongitude() - upperLeft.getLongitude()) / 2); proj.setCenter(centerLL); } //#set auto-scale if (autoScale && latlons.size() > 1) { proj.setScale(ProjMath.getScale(upperLeft, lowerRight, proj)); //#inset if (pixelPadding > 0) { java.awt.Point upperLeftP = proj.forward(proj.getUpperLeft()); java.awt.Point lowerRightP = proj.forward(proj.getLowerRight()); upperLeftP.setLocation(upperLeftP.getX() - pixelPadding, upperLeftP.getY() - pixelPadding); lowerRightP.setLocation(lowerRightP.getX() + pixelPadding, lowerRightP.getY() + pixelPadding); upperLeft = proj.inverse(upperLeftP); lowerRight = proj.inverse(lowerRightP); proj.setScale(proj.getScale(upperLeft, lowerRight, upperLeftP, lowerRightP)); } } } /** * Given degrees, a series of sorted numbers in the range (startDegree,endDegree) that wrap around * as if looped (ie: the first and last items are adjacent), return index to the number that is * furthest from the one after it. */ private static int greatestDistanceLoopIndex(float[] degrees, float startDegree, float endDegree) { if (degrees.length == 0) return -1; if (degrees.length == 1) return 0; int result = -1; float gd = 0;//greatest distance for (int i = 0; i < degrees.length; i++) { float dd; if (i == degrees.length - 1) { //handle final wrap-around case dd = (endDegree - degrees[i]) + (degrees[0] - startDegree); } else { dd = degrees[i + 1] - degrees[i]; } if (dd >= gd) { result = i; gd = dd; } } return result; } public static class GetLatLonPointsFromOMGVisitor implements OMGraphicVisitor { public Collection latlons;//remember to initialize public void visit(OMGraphic omg) { if (omg.getRenderType() != OMGraphic.RENDERTYPE_LATLON && omg.getRenderType() != OMGraphic.RENDERTYPE_OFFSET) return; if (omg instanceof Location) { Location o = (Location) omg; latlons.add(new LatLonPoint(o.lat, o.lon)); return; } if (omg instanceof OMPoint) { OMPoint o = (OMPoint) omg; latlons.add(new LatLonPoint(o.getLat(), o.getLon())); return; } //TODO support more } } /** * For recursive handling of OMGraphics (since {@link OMGraphicList} might be present). * This would be a useful addition to OMGraphic, and/or OMraphic returning an iterator. * Visitor design pattern. */ public static void visitOMGraphics(OMGraphic omg, OMGraphicVisitor visitor) { if (omg instanceof OMGraphicList) { OMGraphicList omglist = (OMGraphicList) omg; List graphics = omglist.getTargets(); if (graphics != null) for (Iterator iter = graphics.iterator(); iter.hasNext();) visitOMGraphics((OMGraphic) iter.next(), visitor); } else visitor.visit(omg); } public static void visitOMGraphics(Collection graphics, OMGraphicVisitor visitor) { for (Iterator iter = graphics.iterator(); iter.hasNext();) visitOMGraphics((OMGraphic) iter.next(), visitor); } public interface OMGraphicVisitor { public void visit(OMGraphic omg); } /** * The OMGraphic objects added might be OMGraphicLists. * Note: Doesn't work for all layers yet. */ public static void addOMGraphicsFromLayers(Layer[] layers, Collection c) { for (int i = 0; i < layers.length; i++) { Layer layer = layers[i]; if (layer instanceof OMGraphicHandlerLayer) { OMGraphicHandlerLayer l = (OMGraphicHandlerLayer) layer; OMGraphicList omgl = l.getList(); if (omgl != null) { List graphics = omgl.getTargets(); if (graphics != null) c.addAll(graphics); } return; } if (layer instanceof LocationLayer) { LocationLayer o = (LocationLayer) layer; Vector graphics = o.getGraphicList(); if (graphics != null) c.addAll(graphics); return; } //TODO support more } } /** * Debug an openmap operation by enabling OpenMap's debugall if commons-logging * permits it for the operation. Unfortunately, OpenMap isn't using a standard logging * library, so this is a work-around. * @param clazz * @param method optional * @param handler */ /* public static void debug(Class clazz, String method, Runnable handler) { boolean currentLevel = Debug.debugAll; if (currentLevel) {//short-circuit handler.run(); return; } String logName = clazz.getName(); if (method != null) logName += "."+method; Log log = LogFactory.getLog(logName); if (log.isDebugEnabled()) Debug.debugAll = true; try { handler.run(); } finally { Debug.debugAll = false; } }*/ }