Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / core / GeometryUtilities.java @ 31988

History | View | Annotate | Download (12.1 KB)

1
package com.iver.cit.gvsig.fmap.core;
2

    
3
/* gvSIG. Geographic Information System of the Valencian Government
4
 *
5
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
6
 * of the Valencian Government (CIT)
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
 * MA  02110-1301, USA.
22
 *
23
 */
24

    
25
import java.awt.geom.PathIterator;
26
import java.awt.geom.Point2D;
27
import java.util.ArrayList;
28

    
29
import org.cresques.cts.IProjection;
30

    
31
import com.iver.cit.gvsig.fmap.MapContext;
32
import com.iver.cit.gvsig.fmap.ViewPort;
33
import com.iver.cit.gvsig.fmap.core.FPoint2D;
34
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
35
import com.iver.cit.gvsig.fmap.core.IGeometry;
36
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
37
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
38
import com.iver.cit.gvsig.fmap.layers.FLayer;
39
import com.iver.cit.gvsig.fmap.tools.geo.Geo;
40
import com.vividsolutions.jts.algorithm.CGAlgorithms;
41
import com.vividsolutions.jts.geom.Coordinate;
42
import com.vividsolutions.jts.geom.CoordinateList;
43

    
44
/**
45
 * Misc utilities for calculations with geometries (area, length, close line,
46
 * get multipolygon or multiline parts, etc).
47
 *
48
 * @author Vicente Caballero Navarro (vicente.caballero@iver.es)
49
 * @author Jaume Dom?nguez Faus (jaume.dominguez@iver.es)
50
 * @author C?sar Mart?nez Izquierdo (cesar.martinez@iver.es)
51
 * @author Pablo Piqueras Bartolom? (pablo.piqueras@iver.es)
52
 */
53
public class GeometryUtilities {
54
        /**
55
         * Calculates the area of a polygon.
56
         */
57
        public static double getArea(FLayer layer, IGeometry geom) {
58
                ArrayList parts=getParts(geom);
59
                double area=0;
60
                for (int i=0;i<parts.size();i++){
61
                        Double[][] xsys=(Double[][])parts.get(i);//getXY(geom);
62
                        Double[] xs=xsys[0];
63
                        Double[] ys=xsys[1];
64
                        IProjection proj=layer.getMapContext().getProjection();
65
                        if (isCCW(xs, ys)){
66
                                if (proj.isProjected()) {
67
                                        ViewPort vp =layer.getMapContext().getViewPort();
68
                                        area-= getCoordsArea(vp, xs,ys,new Point2D.Double(xs[xs.length-1].doubleValue(),ys[ys.length-1].doubleValue()));
69
                                }else{
70
                                        area-= getGeoCArea(xs,ys);
71
                                }
72
                        }else{
73
                                if (proj.isProjected()) {
74
                                        ViewPort vp =layer.getMapContext().getViewPort();
75
                                        area+= getCoordsArea(vp, xs,ys,new Point2D.Double(xs[xs.length-1].doubleValue(),ys[ys.length-1].doubleValue()));
76
                                }else{
77
                                        area+= getGeoCArea(xs,ys);
78
                                }
79
                        }
80
                }
81
                return area;
82
        }
83

    
84
    /**
85
     * Calculates the length of a polygon (perimeter) or a line.
86
     *
87
     * @param vp
88
     * @param geom
89
     * @return
90
     */
91
    public static double getLength(ViewPort vp, IGeometry geom){
92
            ArrayList parts=getParts(geom);
93
            double perimeter=0;
94
            for (int j=0;j<parts.size();j++){
95
                    Double[][] xsys=(Double[][])parts.get(j);
96
                    double dist = 0;
97
                    double distAll = 0;
98

    
99
                    for (int i = 0; i < (xsys[0].length - 1); i++) {
100
                            dist = 0;
101

    
102
                            Point2D p = new Point2D.Double(xsys[0][i].doubleValue(), xsys[1][i].doubleValue());
103
                            Point2D p2 = new Point2D.Double(xsys[0][i + 1].doubleValue(), xsys[1][i + 1].doubleValue());
104
                            dist = vp.distanceWorld(p,p2);
105
                            distAll += dist;
106
                    }
107
                    int distanceUnits=vp.getDistanceUnits();
108
                    perimeter+= distAll/MapContext.getDistanceTrans2Meter()[distanceUnits];
109
            }
110
            return perimeter;
111

    
112
    }
113

    
114
        /**
115
         * <p>Returns an array list containing the parts that compose a
116
         * multipolygon or multilyne. Each element of the array list is an array
117
         * (Double[][]) containing the X and Y coordinates for each polygon
118
         * part.</p>
119
         *
120
         * <p>I think it wll be clearer with an example:
121
         *
122
         * <pre>ArrayList parts = GeometryUtilities.getParts(geom);
123
         * // xs will contain all the X coordinates from the first polygon part
124
         * Double[] xs = parts.get(0)[0];
125
         * // ys will contain all the Y coordinates from the first polygon part
126
         * Double[] ys = parts.get(0)[1];
127
         *
128
         * ... do something with 'xs' and 'ys' ...
129
         *
130
         * // xs will now contain all the X coordinates from the second polygon part
131
         * xs = parts.get(1)[0];
132
         * // ys will now contain all the Y coordinates from the second polygon part
133
         * ys = parts.get(1)[1];
134
         *
135
         * ... we will continue with the rest of the parts: parts.get(2),
136
         * parts.get(3), etc... of course, we should check how many parts the polygon
137
         * really has.
138
         * </pre>
139
         *
140
         *
141
         * @param geometry
142
         * @return
143
         */
144
        public static ArrayList getParts(IGeometry geometry) {
145
        ArrayList xs = new ArrayList();
146
        ArrayList ys = new ArrayList();
147
        ArrayList parts=new ArrayList();
148
        double[] theData = new double[6];
149

    
150
        //double[] aux = new double[6];
151
        PathIterator theIterator;
152
        int theType;
153
        int numParts = 0;
154
        theIterator = geometry.getPathIterator(null, FConverter.FLATNESS); //, flatness);
155
        boolean isClosed = false;
156
        double firstX=0;
157
        double firstY=0;
158
        while (!theIterator.isDone()) {
159
            theType = theIterator.currentSegment(theData);
160

    
161
            switch (theType) {
162
            case PathIterator.SEG_MOVETO:
163
                            if (numParts==0){
164
                                    firstX=theData[0];
165
                                    firstY=theData[1];
166
                                    xs.add(new Double(theData[0]));
167
                                    ys.add(new Double(theData[1]));
168
                            }else{
169
                                    if (!isClosed){
170
                                            Double[] x = (Double[]) xs.toArray(new Double[0]);
171
                                            Double[] y = (Double[]) ys.toArray(new Double[0]);
172
                                            parts.add(new Double[][] { x, y });
173
                                            xs.clear();
174
                                            ys.clear();
175
                                    }
176
                                    firstX=theData[0];
177
                                    firstY=theData[1];
178
                                    xs.add(new Double(theData[0]));
179
                                    ys.add(new Double(theData[1]));
180
                            }
181
                numParts++;
182
                isClosed = false;
183
                break;
184
            case PathIterator.SEG_LINETO:
185
                    isClosed=false;
186
                xs.add(new Double(theData[0]));
187
                ys.add(new Double(theData[1]));
188
                break;
189
            case PathIterator.SEG_CLOSE:
190
                    isClosed=true;
191
                xs.add(new Double(theData[0]));
192
                ys.add(new Double(theData[1]));
193
                xs.add(new Double(firstX));
194
                ys.add(new Double(firstY));
195
                Double[] x = (Double[]) xs.toArray(new Double[0]);
196
                Double[] y = (Double[]) ys.toArray(new Double[0]);
197
                parts.add(new Double[][] { x, y });
198
                xs.clear();
199
                ys.clear();
200
                break;
201
            } //end switch
202

    
203
            theIterator.next();
204
        } //end while loop
205

    
206
        if (!isClosed){
207
                isClosed=true;
208
                xs.add(new Double(theData[0]));
209
            ys.add(new Double(theData[1]));
210
            Double[] x = (Double[]) xs.toArray(new Double[0]);
211
            Double[] y = (Double[]) ys.toArray(new Double[0]);
212
            parts.add(new Double[][] { x, y });
213
            xs.clear();
214
            ys.clear();
215
        }
216
        return parts;
217

    
218
    }
219

    
220
        public static boolean isCCW(Double[] xs, Double[] ys){
221
                CoordinateList coordList = new CoordinateList();
222
                for (int i = 0; i < ys.length; i++) {
223
               Coordinate coord=new Coordinate(xs[i].doubleValue(),ys[i].doubleValue());
224
               coordList.add(coord);
225
                }
226
                if (coordList.isEmpty())
227
                        return true;
228
                return CGAlgorithms.isCCW(coordList.toCoordinateArray());
229
        }
230

    
231
        /**
232
         * Returns the area of a polygon, whose coordinates are defined
233
         * in a geographic (latitude/longitude) CRS.
234
         *
235
         * @param xs
236
         * @param ys
237
         * @return
238
         */
239
        private static double getGeoCArea(Double[] xs,Double[] ys) {
240
                double[] lat=new double[xs.length];
241
                double[] lon=new double[xs.length];
242
                for (int K= 0; K < xs.length; K++){
243
                        lon[K]= xs[K].doubleValue()/Geo.Degree;
244
                        lat[K]= ys[K].doubleValue()/Geo.Degree;
245
                }
246
                return (Geo.sphericalPolyArea(lat,lon,xs.length-1)*Geo.SqM);
247
        }
248
        /**
249
         * Calculates the area for a polygon whose coordinates are defined
250
         * in a projected CRS.
251
         *
252
         * @param aux ?ltimo punto.
253
         *
254
         * @return ?rea.
255
         */
256
        private static double getCoordsArea(ViewPort vp, Double[] xs,Double[] ys, Point2D point) {
257
                Point2D aux=point;
258
                double elArea = 0.0;
259
                Point2D pPixel;
260
                Point2D p = new Point2D.Double();
261
                Point2D.Double pAnt = new Point2D.Double();
262

    
263
                for (int pos = 0; pos < xs.length-1; pos++) {
264
                        pPixel = new Point2D.Double(xs[pos].doubleValue(),
265
                                        ys[pos].doubleValue());
266
                        p = pPixel;
267
                        if (pos == 0) {
268
                                pAnt.x = aux.getX();
269
                                pAnt.y = aux.getY();
270
                        }
271
                        elArea = elArea + ((pAnt.x - p.getX()) * (pAnt.y + p.getY()));
272
                        pAnt.setLocation(p);
273
                }
274

    
275
                elArea = elArea + ((pAnt.x - aux.getX()) * (pAnt.y + aux.getY()));
276
                elArea = Math.abs(elArea / 2.0);
277
                return (elArea/(Math.pow(MapContext.getAreaTrans2Meter()[vp.getDistanceArea()],2)));
278
        }
279

    
280

    
281
        /**
282
         * Creates a closed polygon from an open polyline.
283
         */
284
    public static IGeometry closeLine(IGeometry line) {
285
            PathIterator it = line.getPathIterator(null);
286
            double[] newCoords = new double[6]; // Can receive as much 6 coordinates (3 points)
287
            Point2D firstPoint = new Point2D.Double(), point = new Point2D.Double();
288
                GeneralPathX gP = new GeneralPathX();
289
            int currentType;
290
            boolean closed = false;
291
            long numPoints = 0;
292

    
293
                while (! it.isDone()) {
294
                        currentType = it.currentSegment(newCoords);
295

    
296
                        switch (currentType) {
297
                                case PathIterator.SEG_MOVETO:
298
                                        // SEG_MOVETO -> New polygon
299
                                        firstPoint.setLocation(newCoords[0], newCoords[1]);
300
                                //        firstPoint = vP.toMapPoint(firstPoint);
301
                                        gP.moveTo(firstPoint.getX(), firstPoint.getY());
302
                                        numPoints ++;
303
                                        break;
304
                case PathIterator.SEG_LINETO:
305
                                        point.setLocation(newCoords[0], newCoords[1]);
306
                                        //point = vP.toMapPoint(point);
307
                                        gP.lineTo(point.getX(), point.getY());
308
                                        numPoints ++;
309
                        break;
310
                case PathIterator.SEG_QUADTO:
311
                        // Don't used
312
                    break;
313
                case PathIterator.SEG_CUBICTO:
314
                        // Don't used
315
                    break;
316
                case PathIterator.SEG_CLOSE:
317
                        // Closes the line with the first point
318
                                        //gP.lineTo(firstPoint.getX(), firstPoint.getY());
319
                        numPoints ++;
320
                                        gP.closePath();
321
                                        closed = true;
322
                    break;
323
            }
324

    
325
                        it.next();
326
                }
327

    
328
                // Only can close (convert to polygons) the lines which are composed by more than 2 points
329
                if (numPoints < 3)
330
                        return null;
331

    
332
                // Forces to close the multi-line
333
                if ((! closed) && (firstPoint != null)) {
334
                        //gP.lineTo(firstPoint.getX(), firstPoint.getY());
335
                        numPoints ++;
336
                        gP.closePath();
337
                }
338

    
339
                return ShapeFactory.createPolygon2D(gP);
340
    }
341

    
342
    /**
343
     * Creates a polyline 2D from an array of points
344
     *
345
     * @param points
346
     * @return
347
     */
348
    public static IGeometry getPolyLine2D(FPoint2D[] points) {
349
            if (points.length < 2)
350
                    return null;
351

    
352
            // Creates the general path of the new polyline
353
            GeneralPathX gPath = new GeneralPathX();
354

    
355
            gPath.moveTo(points[0].getX(), points[0].getY());
356

    
357
            for (int i = 1; i < points.length; i++) {
358
                    gPath.lineTo(points[i].getX(), points[i].getY());
359
                }
360

    
361
            return ShapeFactory.createPolyline2D(gPath);
362
    }
363

    
364
    /**
365
     * Creates a polygon 2D from an array of points.
366
     *
367
     * @param points
368
     * @return
369
     */
370
    public static IGeometry getPolygon2D(FPoint2D[] points) {
371
            if (points.length < 3)
372
                    return null;
373

    
374
            // Creates the general path of the new polygon
375
            GeneralPathX gPath = new GeneralPathX();
376

    
377
            gPath.moveTo(points[0].getX(), points[0].getY());
378

    
379
            for (int i = 1; i < points.length; i++) {
380
                    gPath.lineTo(points[i].getX(), points[i].getY());
381
                }
382

    
383
            // Forces to close the polygon
384
            gPath.closePath();
385

    
386
            return ShapeFactory.createPolygon2D(gPath);
387
    }
388

    
389
}