001package sec.geo;
002
003import java.util.ArrayList;
004import armyc2.c2sd.graphics2d.*;
005import org.gavaghan.geodesy.Angle;
006import org.gavaghan.geodesy.Ellipsoid;
007import org.gavaghan.geodesy.GeodeticCalculator;
008import org.gavaghan.geodesy.GeodeticCurve;
009import org.gavaghan.geodesy.GlobalCoordinates;
010
011public class GeoEllipse /* extends GeoPath */ {
012
013    protected static final Ellipsoid REFERENCE_ELLIPSOID = Ellipsoid.WGS84;
014
015    //private final Path2D path;
016    private GeneralPath path;
017    private ArrayList<GeoPoint> toPoints;
018    private double maxDistanceMeters;
019    private double flatnessDistanceMeters;
020    private int limit;
021
022    protected final GeodeticCalculator geoCalc;
023
024    public GeoEllipse(GeoPoint pivot, double widthMeters, double heightMeters, double maxDistanceMeters,
025            double flatnessDistanceMeters, int limit) {
026                //super(maxDistanceMeters, flatnessDistanceMeters, limit);
027        //path = new Path2D.Double();
028        path = new GeneralPath();
029        toPoints = new ArrayList<GeoPoint>();
030        geoCalc = new GeodeticCalculator();
031        this.maxDistanceMeters = maxDistanceMeters;
032        this.flatnessDistanceMeters = flatnessDistanceMeters;
033        this.limit = limit;
034
035        arcTo(pivot, widthMeters, heightMeters, 0, 180);
036        arcTo(pivot, widthMeters, heightMeters, 180, 0);
037    }
038
039    public final void arcTo(GeoPoint pivot, double widthMeters, double heightMeters, double leftAzimuthDegrees,
040            double rightAzimuthDegrees) {
041        //Path2D newPath = new Path2D.Double();
042        GeneralPath newPath = new GeneralPath();
043        Arc2D arc;
044
045        if (leftAzimuthDegrees > rightAzimuthDegrees) {
046            arc = new Arc2D(-widthMeters / 2, -heightMeters / 2, widthMeters, heightMeters,
047                    leftAzimuthDegrees - 90, Math.abs((360 - leftAzimuthDegrees) + rightAzimuthDegrees), Arc2D.OPEN);
048        } else {
049            arc = new Arc2D(-widthMeters / 2, -heightMeters / 2, widthMeters, heightMeters,
050                    leftAzimuthDegrees - 90, Math.abs(leftAzimuthDegrees - rightAzimuthDegrees), Arc2D.OPEN);
051        }
052
053        GeoPoint point = null;
054        if (pivot != null) {
055            FlatteningPathIterator it = new FlatteningPathIterator(arc.getPathIterator(null), flatnessDistanceMeters, limit);
056            while (!it.isDone()) {
057                // Add a point to the list for each segment flattened from the curve
058                double[] strokePoints = new double[6];
059                int type = it.currentSegment(strokePoints);
060                double x = strokePoints[0];
061                double y = strokePoints[1];
062                double azimuth = Angle.toDegrees(Math.atan2(x, y));
063                GlobalCoordinates coord = new GlobalCoordinates(pivot.getLatitude(), pivot.getLongitude());
064                GlobalCoordinates c = geoCalc.calculateEndingGlobalCoordinates(REFERENCE_ELLIPSOID, coord, azimuth,
065                        //new Point2D().distance(x, y));
066                        Point2D.distance(0, 0, x, y));
067                switch (type) {
068                    case PathIterator.SEG_MOVETO:
069                        newPath.moveTo(c.getLongitude(), c.getLatitude());
070                        GeoPoint startPoint = new GeoPoint(c.getLongitude(), c.getLatitude());
071                        if (toPoints.size() > 0 && !startPoint.equals(toPoints.get(toPoints.size() - 1))) {
072                            lineTo(startPoint);
073                        }
074                        break;
075                    case PathIterator.SEG_LINETO:
076                        newPath.lineTo(c.getLongitude(), c.getLatitude());
077                        point = new GeoPoint(c.getLongitude(), c.getLatitude());
078                        break;
079                }
080                it.next();
081            }
082        }
083
084        path.append(newPath, true);
085        toPoints.add(point);
086    }
087
088    public void lineTo(GeoPoint point) {
089        //Path2D newPath = new Path2D.Double();
090        GeneralPath newPath = new GeneralPath();
091
092        // Move to the initial point
093        GeoPoint lastPoint = new GeoPoint();
094        if (toPoints.size() > 0) {
095            lastPoint = toPoints.get(toPoints.size() - 1);
096            newPath.moveTo(lastPoint.x, lastPoint.y);
097        }
098
099        // Calculate the curve to the new point
100        GlobalCoordinates start = toGlobalCoord(lastPoint);
101        GlobalCoordinates end = toGlobalCoord(point);
102        GeodeticCurve curve = geoCalc.calculateGeodeticCurve(REFERENCE_ELLIPSOID, start, end);
103
104        // Generate points along the curve, adding them to the new path
105        double distance = maxDistanceMeters;
106        while (distance < curve.getEllipsoidalDistance()) {
107            GlobalCoordinates c = geoCalc.calculateEndingGlobalCoordinates(REFERENCE_ELLIPSOID, start, curve
108                    .getAzimuth(), distance);
109            newPath.lineTo(c.getLongitude(), c.getLatitude());
110            distance += maxDistanceMeters;
111        }
112        newPath.lineTo(point.x, point.y);
113
114        // Append the new path to the existing path
115        path.append(newPath, true);
116        toPoints.add(point);
117
118    }
119
120    protected GlobalCoordinates toGlobalCoord(GeoPoint point) {
121        return new GlobalCoordinates(point.getLatitude(), point.getLongitude());
122    }
123
124    public PathIterator getPathIterator(AffineTransform at) {
125        return path.getPathIterator(at);
126    }
127    //added path accessor for use by Ellipse only
128    public GeneralPath getPath()
129    {
130        return path;
131    }
132    
133}