// **********************************************************************
//
// <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.2.2.2 $
// $Date: 2005/01/10 16:59:45 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.omGraphics;
import java.awt.Point;
import java.awt.geom.GeneralPath;
import java.io.Serializable;
import java.util.ArrayList;
import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.proj.Projection;
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="com.bbn.openmap.proj.Projection.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 OMGraphic implements Serializable {
/**
* 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 float lat1 = 0.0f;
/** Longitude of first corner, decimal degrees. */
protected float 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 float lat2 = 0.0f;
/** Longitude of second corner, decimal degrees. */
protected float 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(float lt1, float ln1, float lt2, float 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(float lt1, float ln1, float lt2, float 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(float lt1, float 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(float lt1, float ln1, float lt2, float 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(float lt1, float 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 float 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 float getWestLon() {
return lon1;
}
/**
* Get the latitude of the south edge in a LatLon rectangle.
*
* @return float latitude
*/
public float getSouthLat() {
return lat2;
}
/**
* Get the longitude of the east edge in a LatLon rectangle.
*
* @return float longitude
*/
public float 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) {
setShape(null);
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 = proj.forward(lat1, lon1);
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 rects = proj.forwardRect(new LatLonPoint(lat1, lon1), // NW
new LatLonPoint(lat2, lon2), // SE
lineType, nsegs, !isClear(fillPaint));
int size = rects.size();
for (int i = 0, j = 0; i < size; i += 2, j++) {
GeneralPath gp = createShape((int[]) rects.get(i),
(int[]) rects.get(i + 1),
true);
if (shape == null) {
setShape(gp);
} else {
((GeneralPath) shape).append(gp, false);
}
}
break;
case RENDERTYPE_UNKNOWN:
System.err.println("OMRect.generate(): invalid RenderType");
return false;
}
setNeedToRegenerate(false);
return true;
}
}