// ********************************************************************** // // <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/OMEllipse.java,v $ // $RCSfile: OMEllipse.java,v $ // $Revision: 1.7 $ // $Date: 2009/02/25 22:34:03 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.omGraphics; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.util.ArrayList; import com.bbn.openmap.proj.GeoProj; import com.bbn.openmap.proj.Length; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; import com.bbn.openmap.util.Debug; /** * The OMEllipse is a lat/lon ellipse, made up of a center lat/lon point, and * some length described for the x and y axis. If you want to create ellipses in * X/Y space, use OMCircle. Ellipse arcs are not available yet, and this class * doesn't really work with the EditableOMCircle. You can use EditableOMCircles * to move and delete OMEllipses, but you can't change the axis dimensions. */ public class OMEllipse extends OMCircle { protected double majorAxisSpan; protected double minorAxisSpan; protected transient double[] rawllpts; /** * Create a OMEllipse, positioned with a lat-lon center and a lat-lon axis. * Rendertype is RENDERTYPE_LATLON. * * @param centerPoint latitude/longitude of center point, decimal degrees * @param majorAxisSpan horizontal diameter of circle/ellipse, pixels * @param minorAxisSpan vertical diameter of circle/ellipse, in given units * @param units com.bbn.openmap.proj.Length object. * @param rotateAngle angle of rotation in Radians */ public OMEllipse(LatLonPoint centerPoint, double majorAxisSpan, double minorAxisSpan, Length units, double rotateAngle) { setRenderType(RENDERTYPE_LATLON); setLineType(LINETYPE_GREATCIRCLE); setCenter(centerPoint); setAxis(majorAxisSpan, minorAxisSpan, units); setRotationAngle(rotateAngle); } /** * Create a OMEllipse, positioned with a x-y center with x-y axis. * Rendertype is RENDERTYPE_XY. * * @param x1 window position of center point from left of window, in pixels * @param y1 window position of center point from top of window, in pixels * @param majorAxisSpan horizontal diameter of circle/ellipse, pixels * @param minorAxisSpan vertical diameter of circle/ellipse, pixels * @param rotateAngle angle of rotation in Radians */ public OMEllipse(int x1, int y1, int majorAxisSpan, int minorAxisSpan, double rotateAngle) { super(x1, y1, majorAxisSpan, minorAxisSpan); setRotationAngle(rotateAngle); } /** * Create a OMEllipse, positioned with a lat-lon center and x-y axis. * Rendertype is RENDERTYPE_OFFSET. * * @param centerPoint latitude/longitude of center point, decimal degrees * @param w horizontal diameter of circle/ellipse, pixels * @param h vertical diameter of circle/ellipse, pixels * @param rotateAngle angle of rotation in Radians */ public OMEllipse(LatLonPoint centerPoint, int w, int h, double rotateAngle) { // Use circle constructor super(centerPoint.getY(), centerPoint.getX(), 0, 0, w, h); setRotationAngle(rotateAngle); } /** * Create a OMEllipse, positioned at a Lat-lon location, x-y offset, x-y * axis. Rendertype is RENDERTYPE_OFFSET. * * @param centerPoint latitude/longitude of center point, decimal degrees * @param offset_x1 # pixels to the right the center will be moved from * lonPoint. * @param offset_y1 # pixels down that the center will be moved from * latPoint. * @param w horizontal diameter of circle/ellipse, pixels. * @param h vertical diameter of circle/ellipse, pixels. */ public OMEllipse(LatLonPoint centerPoint, int offset_x1, int offset_y1, int w, int h, double rotateAngle) { super(centerPoint.getY(), centerPoint.getX(), offset_x1, offset_y1, w, h); setRotationAngle(rotateAngle); } /** * Set the axis lengths of the ellipse. * * @param majorAxis x direction of ellipse. * @param minorAxis y direction of ellipse. * @param units com.bbn.openmap.proj.Length object describing units of axis * values. */ public void setAxis(double majorAxis, double minorAxis, Length units) { if (units == null) { units = Length.RADIAN; } this.majorAxisSpan = units.toRadians(majorAxis); this.minorAxisSpan = units.toRadians(minorAxis); rawllpts = null; setNeedToRegenerate(true); } public void setCenter(LatLonPoint llp) { super.setCenter(llp); rawllpts = null; } /** * Get the x axis value. */ public double getMajorAxis() { return majorAxisSpan; } /** * Get the y axis value. */ public double getMinorAxis() { return minorAxisSpan; } /** * Get the float[] of points that make up the ellipse. In radians, lat, lon, * lat, lon, etc. May be null if generate hasn't been called. */ public double[] getLatLonPoints() { return rawllpts; } /** * Given that the center point and the axis are set, calculate the new * lat/lon points all around the ellipse from the center. */ public double[] createLatLonPoints() { // First, need to calculate the lat/lon points for the // ellipse. int i; int nMax = 72; double angle = -Math.PI; double angleInc = 2.0 * Math.PI / nMax; double[] distance = new double[nMax + 1]; double x; double y; double a; double b; double[] azimuth = new double[nMax + 1]; double[] llPoints = new double[2 * (nMax + 1)]; a = majorAxisSpan / 2.0; b = minorAxisSpan / 2.0; for (i = 0; i < nMax; i++) { x = Math.sqrt((a * a * b * b) / ((b * b) + ((a * a) * Math.pow(Math.tan(angle), 2)))); double yt = (x * x) / (a * a); if (yt > 1.0) { yt = 1.0; } y = Math.sqrt((1.0 - yt) * (b * b)); distance[i] = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); azimuth[i] = angle + com.bbn.openmap.MoreMath.HALF_PI + getRotationAngle(); if (Debug.debugging("ellipse")) { Debug.output(" " + i + " " + Math.toDegrees(azimuth[i]) + " ( " + distance[i] + " ) " + (Debug.debugging("ellipsedetail") ? ("[from x:" + x + ", y:" + y + ", a:" + a + ", b:" + b + "]") : "")); } angle += angleInc; } distance[nMax] = distance[0]; azimuth[nMax] = azimuth[0]; int nCounter = 0; for (i = 0; i < nMax + 1; i++) { LatLonPoint llPt = LatLonPoint.getDouble(center).getPoint((float) distance[i], azimuth[i]); llPoints[nCounter++] = llPt.getRadLat(); llPoints[nCounter++] = llPt.getRadLon(); } return llPoints; } public boolean generate(Projection proj) { if (renderType == RENDERTYPE_XY || renderType == RENDERTYPE_OFFSET) { return super.generate(proj); // generate using circle's generate } setNeedToRegenerate(true); if (proj == null) { Debug.message("omgraphic", "OMEllipse: null projection in generate!"); return false; } if (rawllpts == null) { rawllpts = createLatLonPoints(); } ArrayList<float[]> vector = null; // polygon/polyline project the polygon/polyline. // Vertices should already be in radians.ArrayList vector; if (proj instanceof GeoProj) { vector = ((GeoProj) proj).forwardPoly(rawllpts, getLineType(), -1, true); int size = vector.size(); GeneralPath projectedShape = null; // We could call create shape, but this is more efficient. for (int i = 0; i < size; i += 2) { GeneralPath gp = createShape(vector.get(i), vector.get(i + 1), true); projectedShape = appendShapeEdge(projectedShape, gp, false); } setShape(projectedShape); } else { // Create an ellipse in projected space using java2d Ellipse2D ellipse = new Ellipse2D.Float((float) center.getX(), (float) center.getY(), (float) majorAxisSpan, (float) minorAxisSpan); setShape(new GeneralPath(proj.forwardShape(ellipse))); } setLabelLocation(getShape(), proj); setNeedToRegenerate(false); return true; } public void restore(OMGeometry source) { super.restore(source); if (source instanceof OMEllipse) { OMEllipse ellipse = (OMEllipse) source; this.majorAxisSpan = ellipse.majorAxisSpan; this.minorAxisSpan = ellipse.minorAxisSpan; } } }