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