// ********************************************************************** // // <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/omGraphics/OMRect.java,v $ // $RCSfile: OMRect.java,v $ // $Revision: 1.7 $ // $Date: 2009/01/21 01:24:41 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.omGraphics; import java.awt.Point; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.util.ArrayList; import com.bbn.openmap.proj.GeoProj; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; import com.bbn.openmap.util.Debug; /** * Graphic type that lets you draw four-sided polygons that have corners that * share coordinates or window points. * <p> * <h3>NOTE:</h3> * See the <a href="../proj/GeoProj.html#poly_restrictions"> * RESTRICTIONS </a> on Lat/Lon polygons/polylines which apply to rectangles as * well. Not following the guidelines listed may result in ambiguous/undefined * shapes! Similar assumptions apply to the other vector graphics that we * define: circles, ellipses, polys, lines. * <p> * These assumptions are virtually the same as those on the more generic OMPoly * graphic type. * <p> * * @see OMPoly * */ public class OMRect extends OMGraphicAdapter implements OMGraphic { /** * Horizontal window position of first corner, in pixels from left side of * window. */ protected int x1 = 0; /** * Vertical window position of first corner, in pixels from the top of the * window. */ protected int y1 = 0; /** Latitude of first corner, decimal degrees. */ protected double lat1 = 0.0f; /** Longitude of first corner, decimal degrees. */ protected double lon1 = 0.0f; /** * Horizontal window position of second corner, in pixels from left side of * window. */ protected int x2 = 0; /** * Vertical window position of second corner, in pixels from the top of the * window. */ protected int y2 = 0; /** Latitude of second corner, decimal degrees. */ protected double lat2 = 0.0f; /** Longitude of second corner, decimal degrees. */ protected double lon2 = 0.0f; /** * Number of segments to draw (used only for LINETYPE_GREATCIRCLE or * LINETYPE_RHUMB lines). */ protected int nsegs = -1; /** Default constructor, waiting to be filled. */ public OMRect() { super(RENDERTYPE_UNKNOWN, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE); } /** * Create a lat/lon rectangle. * * @param lt1 latitude of north edge, decimal degrees. * @param ln1 longitude of west edge, decimal degrees. * @param lt2 latitude of south edge, decimal degrees. * @param ln2 longitude of east edge, decimal degrees. * @param lType line type - see OMGraphic.lineType. */ public OMRect(double lt1, double ln1, double lt2, double ln2, int lType) { this(lt1, ln1, lt2, ln2, lType, -1); } /** * Create a lat/lon rectangle. * * @param lt1 latitude of north edge, decimal degrees. * @param ln1 longitude of west edge, decimal degrees. * @param lt2 latitude of south edge, decimal degrees. * @param ln2 longitude of east edge, decimal degrees. * @param lType line type - see OMGraphic.lineType. * @param nsegs number of segment points (only for LINETYPE_GREATCIRCLE or * LINETYPE_RHUMB line types, and if < 1, this value is generated * internally) */ public OMRect(double lt1, double ln1, double lt2, double ln2, int lType, int nsegs) { super(RENDERTYPE_LATLON, lType, DECLUTTERTYPE_NONE); lat1 = lt1; lon1 = ln1; lat2 = lt2; lon2 = ln2; this.nsegs = nsegs; } /** * Construct an XY rectangle. It doesn't matter which corners of the * rectangle are used, as long as they are opposite from each other. * * @param px1 x pixel position of the first corner relative to the window * origin * @param py1 y pixel position of the first corner relative to the window * origin * @param px2 x pixel position of the second corner relative to the window * origin * @param py2 y pixel position of the second corner relative to the window * origin */ public OMRect(int px1, int py1, int px2, int py2) { super(RENDERTYPE_XY, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE); x1 = px1; y1 = py1; x2 = px2; y2 = py2; } /** * Construct an XY rectangle relative to a lat/lon point * (RENDERTYPE_OFFSET). It doesn't matter which corners of the rectangle are * used, as long as they are opposite from each other. * * @param lt1 latitude of the reference point, decimal degrees. * @param ln1 longitude of the reference point, decimal degrees. * @param px1 x pixel position of the first corner relative to the reference * point * @param py1 y pixel position of the first corner relative to the reference * point * @param px2 x pixel position of the second corner relative to the * reference point * @param py2 y pixel position of the second corner relative to the * reference point */ public OMRect(double lt1, double ln1, int px1, int py1, int px2, int py2) { super(RENDERTYPE_OFFSET, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE); lat1 = lt1; lon1 = ln1; x1 = px1; y1 = py1; x2 = px2; y2 = py2; } /** * Set a lat/lon rectangle. * * @param lt1 latitude of north edge, decimal degrees. * @param ln1 longitude of west edge, decimal degrees. * @param lt2 latitude of south edge, decimal degrees. * @param ln2 longitude of east edge, decimal degrees. * @param lType line type - see OMGraphic.lineType. */ public void setLocation(double lt1, double ln1, double lt2, double ln2, int lType) { setRenderType(RENDERTYPE_LATLON); setLineType(lType); lat1 = lt1; lon1 = ln1; lat2 = lt2; lon2 = ln2; setNeedToRegenerate(true); } /** * Set an XY rectangle. It doesn't matter which corners of the rectangle are * used, as long as they are opposite from each other. * * @param px1 x pixel position of the first corner relative to the window * origin * @param py1 y pixel position of the first corner relative to the window * origin * @param px2 x pixel position of the second corner relative to the window * origin * @param py2 y pixel position of the second corner relative to the window * origin */ public void setLocation(int px1, int py1, int px2, int py2) { setRenderType(RENDERTYPE_XY); setLineType(LINETYPE_UNKNOWN); x1 = Math.min(px1, px2); y1 = Math.min(py1, py2); x2 = Math.max(px1, px2); y2 = Math.max(py1, py2); setNeedToRegenerate(true); } /** * Set an XY rectangle relative to a lat/lon point (RENDERTYPE_OFFSET). It * doesn't matter which corners of the rectangle are used, as long as they * are opposite from each other. * * @param lt1 latitude of the reference point, decimal degrees. * @param ln1 longitude of the reference point, decimal degrees. * @param px1 x pixel position of the first corner relative to the reference * point * @param py1 y pixel position of the first corner relative to the reference * point * @param px2 x pixel position of the second corner relative to the * reference point * @param py2 y pixel position of the second corner relative to the * reference point */ public void setLocation(double lt1, double ln1, int px1, int py1, int px2, int py2) { setRenderType(RENDERTYPE_OFFSET); setLineType(LINETYPE_UNKNOWN); lat1 = lt1; lon1 = ln1; x1 = px1; y1 = py1; x2 = px2; y2 = py2; setNeedToRegenerate(true); } /** * Get the latitude of the north edge in a LatLon rectangle. It also happens * to be the latitude of the offset point. * * @return float latitude */ public double getNorthLat() { return lat1; } /** * Get the longitude of the west edge in a LatLon rectangle. It also happens * to be the longitude of the offset point. * * @return float longitude */ public double getWestLon() { return lon1; } /** * Get the latitude of the south edge in a LatLon rectangle. * * @return float latitude */ public double getSouthLat() { return lat2; } /** * Get the longitude of the east edge in a LatLon rectangle. * * @return float longitude */ public double getEastLon() { return lon2; } /** * Get the top of XY rectangle. * * @return int */ public int getTop() { return y1; } /** * Get the left of XY rectangle. * * @return int */ public int getLeft() { return x1; } /** * Get the bottom of XY rectangle. * * @return int */ public int getBottom() { return y2; } /** * Get the right of XY rectangle. * * @return int */ public int getRight() { return x2; } /** * Set the number of segments of the lat/lon lines. (This is only for * LINETYPE_GREATCIRCLE or LINETYPE_RHUMB line types, and if < 1, this * value is generated internally). * * @param nsegs number of segment points */ public void setNumSegs(int nsegs) { this.nsegs = nsegs; } /** * Get the number of segments of the lat/lon lines. (This is only for * LINETYPE_GREATCIRCLE or LINETYPE_RHUMB line types). * * @return int number of segment points */ public int getNumSegs() { return nsegs; } /** * Prepare the rectangle for rendering. * * @param proj Projection * @return true if generate was successful */ public boolean generate(Projection proj) { setNeedToRegenerate(true); if (proj == null) { Debug.message("omgraphic", "OMRect: null projection in generate!"); return false; } // reset the internals switch (renderType) { case RENDERTYPE_XY: setShape(createBoxShape((int) Math.min(x2, x1), (int) Math.min(y2, y1), (int) Math.abs(x2 - x1), (int) Math.abs(y2 - y1))); break; case RENDERTYPE_OFFSET: if (!proj.isPlotable(lat1, lon1)) { setNeedToRegenerate(true);// HMMM not the best flag return false; } Point p1 = (Point) proj.forward(lat1, lon1, new Point()); setShape(createBoxShape((int) Math.min(p1.x + x1, p1.x + x2), (int) Math.min(p1.y + y1, p1.y + y2), (int) Math.abs(x2 - x1), (int) Math.abs(y2 - y1))); break; case RENDERTYPE_LATLON: ArrayList<float[]> rects; if (proj instanceof GeoProj) { rects = ((GeoProj) proj).forwardRect(new LatLonPoint.Double(lat1, lon1), // NW new LatLonPoint.Double(lat2, lon2), // SE lineType, nsegs, !isClear(fillPaint)); } else { rects = proj.forwardRect(new Point2D.Double(lon1, lat1), new Point2D.Double(lon2, lat2)); } int size = rects.size(); GeneralPath projectedShape = null; for (int i = 0; i < size; i += 2) { GeneralPath gp = createShape(rects.get(i), rects.get(i + 1), true); projectedShape = appendShapeEdge(projectedShape, gp, false); } setShape(projectedShape); break; case RENDERTYPE_UNKNOWN: System.err.println("OMRect.generate(): invalid RenderType"); return false; } setLabelLocation(getShape(), proj); setNeedToRegenerate(false); return true; } public void restore(OMGeometry source) { super.restore(source); if (source instanceof OMRect) { OMRect rect = (OMRect) source; this.x1 = rect.x1; this.y1 = rect.y1; this.lat1 = rect.lat1; this.lon1 = rect.lon1; this.x2 = rect.x2; this.y2 = rect.y2; this.lat2 = rect.lat2; this.lon2 = rect.lon2; this.nsegs = rect.nsegs; } } }