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 GeoPath /* implements Shape */ {
013        protected static final Ellipsoid REFERENCE_ELLIPSOID = Ellipsoid.WGS84;
014        
015        private GeneralPath path;
016        private ArrayList<GeoPoint> toPoints;
017        private double maxDistanceMeters;
018        private double flatnessDistanceMeters;
019        private int limit;
020        
021        protected final GeodeticCalculator geoCalc;
022        
023        public GeoPath() {
024                this(100000, 1, 4);
025        }
026        
027        public GeoPath(double maxDistanceMeters, double flatnessDistanceMeters, int limit) {
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        
036        public void moveTo(GeoPoint point) {
037                path.moveTo(point.x, point.y);
038                toPoints.add(point);
039        }
040        
041        public void moveToLatLong(double longitudeDegrees, double latitudeDegrees) {
042                moveTo(new GeoPoint(longitudeDegrees, latitudeDegrees));
043        }
044        
045        public void lineTo(GeoPoint point) {
046                GeneralPath newPath = new GeneralPath();
047                
048                // Move to the initial point
049                GeoPoint lastPoint = new GeoPoint();
050                if (toPoints.size() > 0) {
051                        lastPoint = toPoints.get(toPoints.size() - 1);
052                        newPath.moveTo(lastPoint.x, lastPoint.y);
053                }
054                
055                // Calculate the curve to the new point
056                GlobalCoordinates start = toGlobalCoord(lastPoint);
057                GlobalCoordinates end = toGlobalCoord(point);
058                GeodeticCurve curve = geoCalc.calculateGeodeticCurve(REFERENCE_ELLIPSOID, start, end);
059                
060                // Generate points along the curve, adding them to the new path
061                double distance = maxDistanceMeters;
062                while (distance < curve.getEllipsoidalDistance()) {
063                        GlobalCoordinates c = geoCalc.calculateEndingGlobalCoordinates(REFERENCE_ELLIPSOID, start, curve
064                                        .getAzimuth(), distance);
065                        newPath.lineTo(c.getLongitude(), c.getLatitude());
066                        distance += maxDistanceMeters;
067                }
068                newPath.lineTo(point.x, point.y);
069                
070                // Append the new path to the existing path
071                path.append(newPath, true);                
072                toPoints.add(point);
073                
074        }
075        
076        public void lineToLatLong(double longitudeDegrees, double latitudeDegrees) {
077                lineTo(new GeoPoint(longitudeDegrees, latitudeDegrees));
078        }
079        
080        public void arcTo(GeoPoint pivot, double widthMeters, double heightMeters, double leftAzimuthDegrees,
081                        double rightAzimuthDegrees) {
082                GeneralPath newPath = new GeneralPath();
083                Arc2D arc;
084                                                
085                if (leftAzimuthDegrees > rightAzimuthDegrees) {
086                    arc = new Arc2D(-widthMeters / 2, -heightMeters / 2, widthMeters, heightMeters,
087                                leftAzimuthDegrees - 90, Math.abs((360 - leftAzimuthDegrees) + rightAzimuthDegrees), Arc2D.OPEN);
088                } else {
089                    arc = new Arc2D(-widthMeters / 2, -heightMeters / 2, widthMeters, heightMeters,
090                                leftAzimuthDegrees - 90, Math.abs(leftAzimuthDegrees - rightAzimuthDegrees), Arc2D.OPEN);
091                }
092                
093                GeoPoint point = null;
094                if (pivot != null) {
095                        FlatteningPathIterator it = new FlatteningPathIterator(arc.getPathIterator(null), flatnessDistanceMeters, limit);
096                        while (!it.isDone()) {
097                                // Add a point to the list for each segment flattened from the curve
098                                double[] strokePoints = new double[6];
099                                int type = it.currentSegment(strokePoints);
100                                double x = strokePoints[0];
101                                double y = strokePoints[1];
102                                double azimuth = Angle.toDegrees(Math.atan2(x, y));
103                                GlobalCoordinates coord = new GlobalCoordinates(pivot.getLatitude(), pivot.getLongitude());
104                                GlobalCoordinates c = geoCalc.calculateEndingGlobalCoordinates(REFERENCE_ELLIPSOID, coord, azimuth,
105                                                //new Point2D(0,0).distance(x, y));
106                                                Point2D.distance(0, 0, x, y));
107                                switch (type) {
108                                        case PathIterator.SEG_MOVETO:
109                                                newPath.moveTo(c.getLongitude(), c.getLatitude());
110                                                GeoPoint startPoint = new GeoPoint(c.getLongitude(), c.getLatitude());
111                                                if (toPoints.size() > 0 && !startPoint.equals(toPoints.get(toPoints.size() - 1))) {
112                                                        lineTo(startPoint);
113                                                }
114                                                break;
115                                        case PathIterator.SEG_LINETO:
116                                                newPath.lineTo(c.getLongitude(), c.getLatitude());
117                                                point = new GeoPoint(c.getLongitude(), c.getLatitude());
118                                                break;
119                                }
120                                it.next();
121                        }
122                }
123                
124                path.append(newPath, true);
125                toPoints.add(point);
126        }
127        
128        public ArrayList<GeoPoint> getToPoints() {
129                return toPoints;
130        }
131        
132        public void closePath() {
133            
134                
135                if (toPoints.size() > 0 && !toPoints.get(0).equals(toPoints.get(toPoints.size() - 1))) {                        
136                        lineTo(toPoints.get(0));                        
137                }
138        }
139        
140//      @Override
141//      public boolean contains(Point2D p) {
142//              return path.contains(p);
143//      }
144//      
145//      @Override
146//      public boolean contains(Rectangle2D r) {
147//              return path.contains(r);
148//      }
149//      
150//      @Override
151//      public boolean contains(double x, double y) {
152//              return path.contains(x, y);
153//      }
154//      
155//      @Override
156//      public boolean contains(double x, double y, double w, double h) {
157//              return contains(x, y, w, h);
158//      }
159//      
160//      @Override
161//      public Rectangle getBounds() {
162//              return path.getBounds();
163//      }
164//      
165//      @Override
166//      public Rectangle2D getBounds2D() {
167//              return path.getBounds2D();
168//      }
169        
170//      @Override
171        public PathIterator getPathIterator(AffineTransform at) {
172                return path.getPathIterator(at);
173        }
174        
175//      @Override
176//      public PathIterator getPathIterator(AffineTransform at, double flatness) {
177//              return path.getPathIterator(at, flatness);
178//      }
179//      
180//      @Override
181//      public boolean intersects(Rectangle2D r) {
182//              return path.intersects(r);
183//      }
184//      
185//      @Override
186//      public boolean intersects(double x, double y, double w, double h) {
187//              return path.intersects(x, y, w, h);
188//      }
189        
190        @Override
191        public String toString() {
192            return toPoints.toString();
193        }
194        
195        protected GlobalCoordinates toGlobalCoord(GeoPoint point) {
196                return new GlobalCoordinates(point.getLatitude(), point.getLongitude());
197        }
198}