Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.geometry / org.gvsig.fmap.geometry.api / src / main / java / org / gvsig / fmap / geom / GeometryUtils.java @ 47364

History | View | Annotate | Download (48.7 KB)

1 43906 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.geom;
25
26 45205 fdiaz
import java.awt.geom.Point2D;
27 47264 jjdelcerro
import java.util.ArrayList;
28
import java.util.Collections;
29 45205 fdiaz
import java.util.List;
30 45732 jjdelcerro
import java.util.Locale;
31 45205 fdiaz
import java.util.Objects;
32 45732 jjdelcerro
import java.util.regex.Matcher;
33
import java.util.regex.Pattern;
34 47264 jjdelcerro
import javax.json.JsonArray;
35
import javax.json.JsonObject;
36
import javax.json.JsonValue;
37 44241 jjdelcerro
import org.apache.commons.lang3.StringUtils;
38 43906 jjdelcerro
import org.cresques.cts.IProjection;
39 45205 fdiaz
import org.gvsig.euclidean.EuclideanLine2D;
40
import org.gvsig.euclidean.EuclideanManager;
41 43906 jjdelcerro
import org.gvsig.fmap.geom.aggregate.MultiLine;
42 45205 fdiaz
import org.gvsig.fmap.geom.aggregate.MultiPoint;
43 43906 jjdelcerro
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
44 47264 jjdelcerro
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
45 43906 jjdelcerro
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
46
import org.gvsig.fmap.geom.exception.CreateGeometryException;
47 45205 fdiaz
import org.gvsig.fmap.geom.operation.GeometryOperationException;
48
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
49
import org.gvsig.fmap.geom.primitive.Arc;
50
import org.gvsig.fmap.geom.primitive.Circle;
51
import org.gvsig.fmap.geom.primitive.Ellipse;
52 43906 jjdelcerro
import org.gvsig.fmap.geom.primitive.Envelope;
53
import org.gvsig.fmap.geom.primitive.Line;
54
import org.gvsig.fmap.geom.primitive.Point;
55
import org.gvsig.fmap.geom.primitive.Polygon;
56 45205 fdiaz
import org.gvsig.fmap.geom.primitive.Spline;
57 44190 jjdelcerro
import org.gvsig.fmap.geom.type.GeometryType;
58 47264 jjdelcerro
import org.gvsig.json.Json;
59 45205 fdiaz
import org.gvsig.tools.exception.BaseException;
60
import org.gvsig.tools.util.ToolsUtilLocator;
61 43906 jjdelcerro
62
/**
63
 *
64
 * @author jjdelcerro
65
 */
66 44190 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
67 43906 jjdelcerro
public class GeometryUtils {
68
69
    private GeometryUtils() {
70
71
    }
72
73 44190 jjdelcerro
    public static GeometryType getGeometryType(int geometryType, int geometrySubType) {
74
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
75
        try {
76
            return geomManager.getGeometryType(geometryType, geometrySubType);
77
        } catch (Exception ex) {
78
            return null;
79
        }
80
    }
81
82 43906 jjdelcerro
    public static boolean isSubtype(int geomTypeParent, int geomTypeChild) {
83
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
84
        return geomManager.isSubtype(geomTypeParent, geomTypeChild);
85
    }
86 45039 fdiaz
87
    public static boolean canAggregate(int geomTypeParent, int geomTypeChild) {
88
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
89
        return geomManager.canAggregate(geomTypeParent, geomTypeChild);
90
    }
91 43906 jjdelcerro
92
    public static Envelope createEnvelope(int subType) {
93
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
94
        try {
95
            return geomManager.createEnvelope(subType);
96
        } catch (CreateEnvelopeException ex) {
97
            return null;
98
        }
99
    }
100
101 45131 fdiaz
    public static Envelope createEnvelope(double minX, double minY, double maxX,
102
        double maxY, int subType) {
103
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
104
        try {
105
            return geomManager.createEnvelope(minX, minY, maxX, maxY, subType);
106
        } catch (CreateEnvelopeException ex) {
107
            return null;
108
        }
109
    }
110
111 43906 jjdelcerro
    public static Line createLine(int subType) {
112
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
113
        try {
114
            return geomManager.createLine(subType);
115
        } catch (CreateGeometryException ex) {
116
            return null;
117
        }
118
    }
119
120
    public static MultiLine createMultiLine(int subType) {
121
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
122
        try {
123
            return geomManager.createMultiLine(subType);
124
        } catch (CreateGeometryException ex) {
125
            return null;
126
        }
127
    }
128
129
    public static Polygon createPolygon(int subType) {
130
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
131
        try {
132
            return geomManager.createPolygon(subType);
133
        } catch (CreateGeometryException ex) {
134
            return null;
135
        }
136
    }
137
138
    public static MultiPolygon createMultiPolygon(int subType) {
139
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
140
        try {
141
            return geomManager.createMultiPolygon(subType);
142
        } catch (CreateGeometryException ex) {
143
            return null;
144
        }
145
    }
146
147
    public static Point createPoint(double x, double y) {
148
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
149
        try {
150
            return geomManager.createPoint(x, y, Geometry.SUBTYPES.GEOM2D);
151
        } catch (CreateGeometryException ex) {
152
            return null;
153
        }
154
    }
155
156
    public static Point createPoint(double x, double y, double z) {
157
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
158
        try {
159
            Point p = geomManager.createPoint(x, y, Geometry.SUBTYPES.GEOM3D);
160
            p.setCoordinateAt(Geometry.DIMENSIONS.Z, z);
161
            return p;
162
        } catch (CreateGeometryException ex) {
163
            return null;
164
        }
165
    }
166
167
    public static Point createPoint(double x, double y, double z, double m) {
168
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
169
        try {
170
            Point p = geomManager.createPoint(x, y, Geometry.SUBTYPES.GEOM3DM);
171
            p.setCoordinateAt(Geometry.DIMENSIONS.Z, z);
172
            p.setCoordinateAt(p.getDimension()-1, m);
173
            return p;
174
        } catch (CreateGeometryException ex) {
175
            return null;
176
        }
177
    }
178 45243 fdiaz
179
    public static Point createPoint(Point center, double radius, double angle) {
180
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
181
        return GeometryUtils.createPoint(
182
                center.getX() + radius * Math.cos(angle),
183
                center.getY() + radius * Math.sin(angle)
184
        );
185
    }
186 43906 jjdelcerro
187 45243 fdiaz
188 43909 jjdelcerro
    public static Geometry createFrom(Object data) {
189
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
190
        try {
191
            return geomManager.createFrom(data);
192
        } catch (GeometryException ex) {
193
            return null;
194
        }
195
    }
196
197 43906 jjdelcerro
    public static Geometry createFrom(String wkt, String srs) {
198
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
199
        try {
200
            return geomManager.createFrom(wkt, srs);
201
        } catch (GeometryException ex) {
202
            return null;
203
        }
204
    }
205
206
    public static Geometry createFrom(String wkt, IProjection srs) {
207
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
208
        try {
209
            return geomManager.createFrom(wkt, srs);
210
        } catch (GeometryException ex) {
211
            return null;
212
        }
213
    }
214
215
    public static Geometry createFrom(String wkt) {
216
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
217
        try {
218
            return geomManager.createFrom(wkt);
219
        } catch (GeometryException ex) {
220
            return null;
221
        }
222
    }
223 43909 jjdelcerro
224
    public static Object convertTo(Geometry geom, String format) {
225
        try {
226
            return geom.convertTo(format);
227
        } catch (Exception ex) {
228
            return null;
229
        }
230
    }
231 43906 jjdelcerro
232
    public static String toWKT(Geometry geom) {
233
        try {
234
            return geom.convertToWKT();
235
        } catch (Exception ex) {
236
            return null;
237
        }
238
    }
239
240
    public static byte[] toWKB(Geometry geom) {
241
        try {
242
            return geom.convertToWKB();
243
        } catch (Exception ex) {
244
            return null;
245
        }
246
    }
247
248 44192 jjdelcerro
    public static byte[] toEWKB(Geometry geom) {
249
        try {
250
            return geom.convertToEWKB();
251
        } catch (Exception ex) {
252
            return null;
253
        }
254
    }
255
256 43906 jjdelcerro
    public static boolean intersects(Geometry geom1, Geometry geom2) {
257
        try {
258
            return geom1.intersects(geom2);
259
        } catch (Exception ex) {
260
            return false;
261
        }
262
    }
263
264 45135 jjdelcerro
    public static String getGeometryTypeName(int type) {
265
        switch (type) {
266
            case Geometry.TYPES.GEOMETRY:
267
                return "Geometry";
268
            case Geometry.TYPES.POINT:
269
                return "Point";
270
            case Geometry.TYPES.CURVE:
271
                return "Curve";
272
            case Geometry.TYPES.SURFACE:
273
                return "Surface";
274
            case Geometry.TYPES.SOLID:
275
                return "Solid";
276
            case Geometry.TYPES.AGGREGATE:
277
                return "Aggregate";
278
            case Geometry.TYPES.MULTIPOINT:
279
                return "Multipoint";
280
            case Geometry.TYPES.MULTICURVE:
281
                return "Multicurve";
282
            case Geometry.TYPES.MULTISURFACE:
283
                return "Multisurface";
284
            case Geometry.TYPES.MULTISOLID:
285
                return "Multisolid";
286
            case Geometry.TYPES.CIRCLE:
287
                return "Circle";
288
            case Geometry.TYPES.ARC:
289
                return "Arc";
290
            case Geometry.TYPES.ELLIPSE:
291
                return "Ellipse";
292
            case Geometry.TYPES.SPLINE:
293
                return "Spline";
294
            case Geometry.TYPES.ELLIPTICARC:
295
                return "Ellipticarc";
296
            case Geometry.TYPES.COMPLEX:
297
                return "Complex";
298
            case Geometry.TYPES.LINE:
299
                return "Line";
300
            case Geometry.TYPES.POLYGON:
301
                return "Polygon";
302
            case Geometry.TYPES.RING:
303
                return "Ring";
304
            case Geometry.TYPES.MULTILINE:
305
                return "Multiline";
306
            case Geometry.TYPES.MULTIPOLYGON:
307
                return "Multipolygon";
308
            case Geometry.TYPES.CIRCUMFERENCE:
309
                return "Circumference";
310
            case Geometry.TYPES.PERIELLIPSE:
311
                return "Periellipse";
312
            case Geometry.TYPES.FILLEDSPLINE:
313
                return "Filledspline";
314
            default:
315
                return "Geometry";
316
        }
317
    }
318
319
    public static String getGeometrySubtypeName(int subtype) {
320
        switch (subtype) {
321
            case Geometry.SUBTYPES.GEOM2D:
322
                return "2D";
323
            case Geometry.SUBTYPES.GEOM3D:
324
                return "3D";
325
            case Geometry.SUBTYPES.GEOM2DM:
326
                return "2DM";
327
            case Geometry.SUBTYPES.GEOM3DM:
328
                return "3DM";
329
            default:
330
                return "Unknown";
331
        }
332
    }
333
334 44241 jjdelcerro
    public static int getGeometryType(String typeName) {
335
        if( StringUtils.isBlank(typeName) ) {
336
            return Geometry.TYPES.UNKNOWN;
337
        }
338
        switch(typeName.toLowerCase()) {
339
            case "geometry":
340
                return Geometry.TYPES.GEOMETRY;
341
            case "point":
342
                    return Geometry.TYPES.POINT;
343
            case "curve":
344
                    return Geometry.TYPES.CURVE;
345
            case "surface":
346
                    return Geometry.TYPES.SURFACE;
347
            case "solid":
348
                    return Geometry.TYPES.SOLID;
349
            case "aggregate":
350
                    return Geometry.TYPES.AGGREGATE;
351
            case "multipoint":
352
                    return Geometry.TYPES.MULTIPOINT;
353
            case "multicurve":
354
                    return Geometry.TYPES.MULTICURVE;
355
            case "multisurface":
356
                    return Geometry.TYPES.MULTISURFACE;
357
            case "multisolid":
358
                    return Geometry.TYPES.MULTISOLID;
359
            case "circle":
360
                    return Geometry.TYPES.CIRCLE;
361
            case "arc":
362
                    return Geometry.TYPES.ARC;
363
            case "ellipse":
364
                    return Geometry.TYPES.ELLIPSE;
365
            case "spline":
366
                    return Geometry.TYPES.SPLINE;
367
            case "ellipticarc":
368
                    return Geometry.TYPES.ELLIPTICARC;
369
            case "complex":
370
                    return Geometry.TYPES.COMPLEX;
371
            case "line":
372
                    return Geometry.TYPES.LINE;
373
            case "polygon":
374
                    return Geometry.TYPES.POLYGON;
375
            case "ring":
376
                    return Geometry.TYPES.RING;
377
            case "multiline":
378
                    return Geometry.TYPES.MULTILINE;
379
            case "multipolygon":
380
                    return Geometry.TYPES.MULTIPOLYGON;
381
            case "circumference":
382
                    return Geometry.TYPES.CIRCUMFERENCE;
383
            case "periellipse":
384
                    return Geometry.TYPES.PERIELLIPSE;
385
            case "filledspline":
386
                    return Geometry.TYPES.FILLEDSPLINE;
387
            default:
388
                return Geometry.TYPES.UNKNOWN;
389
        }
390
    }
391
392
    public static int getGeometrySubtype(String subtype) {
393
        if( StringUtils.isBlank(subtype) ) {
394
            return Geometry.SUBTYPES.UNKNOWN;
395
        }
396
        switch(subtype.toUpperCase()) {
397
            case "GEOM2D":
398
            case "2D":
399
                    return Geometry.SUBTYPES.GEOM2D;
400
            case "GEOM3D":
401
            case "3D":
402
                    return Geometry.SUBTYPES.GEOM3D;
403
            case "GEOM2DM":
404
            case "2DM":
405
                    return Geometry.SUBTYPES.GEOM2DM;
406
            case "GEOM3DM":
407
            case "3DM":
408
                    return Geometry.SUBTYPES.GEOM3DM;
409
            default:
410
                return Geometry.SUBTYPES.UNKNOWN;
411
        }
412
    }
413 45205 fdiaz
414
    /**
415
     * Creates a circle as of center and radius.
416
     *
417
     * @param center
418
     *            of new circle
419
     * @param radius
420
     *            of new circle
421
     * @param subtype
422
     *            subtype of circle. See {@link Geometry.SUBTYPES}
423
     * @return The circle created with center and radius
424
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
425
     */
426
    public static Circle createCircle(Point center, double radius, int subtype)
427
            throws CreateGeometryException {
428
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
429
        Circle circle = (Circle) geomManager.create(Geometry.TYPES.CIRCLE, subtype);
430
        circle.setPoints(center, radius);
431
432
        return circle;
433
    }
434
435
    /**
436
     * Creates a circle from three points.
437
     *
438
     * @param firstPoint
439
     *            of circle
440
     * @param secondPoint
441
     *            of circle
442
     * @param thirdPoint
443
     *            of circle
444
     * @param subtype
445
     *            subtype of circle. See {@link Geometry.SUBTYPES}
446
     * @return The circle created from three points received as parameters.
447
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
448
     */
449
    public static Circle createCircle(Point firstPoint, Point secondPoint,
450
            Point thirdPoint, int subtype) throws CreateGeometryException {
451
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
452
        Circle circle = (Circle) geomManager.create(Geometry.TYPES.CIRCLE, subtype);
453
        circle.setPoints(firstPoint, secondPoint, thirdPoint);
454
455
        return circle;
456
    }
457
458
    /**
459
     * Creates a circle from five points.The first two points are two points on a tangent to the circle.The next two are two points on another tangent to the circle.The last one is a point near the center of the circle.
460
     *
461
     * @param firstPoint
462
     * @param secondPoint
463
     * @param thirdPoint
464
     * @param fourthPoint
465
     * @param fifthPoint
466
     * @param subtype
467
     *            subtype of circle. See {@link Geometry.SUBTYPES}
468
     * @return The circle created from three points received as parameters.
469
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
470
     */
471
    public static Circle createCircle(Point firstPoint, Point secondPoint, Point thirdPoint, Point fourthPoint, Point fifthPoint, int subtype) throws CreateGeometryException {
472
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
473
        EuclideanLine2D line1 = euclideanManager.createLine2D(firstPoint.getX(), firstPoint.getY(), secondPoint.getX(), secondPoint.getY());
474
        EuclideanLine2D line2 = euclideanManager.createLine2D(thirdPoint.getX(), thirdPoint.getY(), fourthPoint.getX(), fourthPoint.getY());
475
        return createCircle(line1, line2, fifthPoint, subtype);
476
    }
477
478
    /**
479
     * Creates a circle from two tangents and one point.
480
     *
481
     * @param line1
482
     *            A tangent line
483
     * @param line2
484
     *            Another tangent line
485
     * @param point
486
     *            A point near the center of the circle.
487
     * @param subtype
488
     *            subtype of circle. See {@link Geometry.SUBTYPES}
489
     * @return The circle created from two tangents and one point received as parameters.
490
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
491
     */
492
    public static Circle createCircle(EuclideanLine2D line1, EuclideanLine2D line2, Point point, int subtype) throws CreateGeometryException {
493
494
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
495
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
496
497
        try {
498
            EuclideanLine2D perpendicular;
499
            EuclideanLine2D bisector;
500
            if (line1.isParallel(line2)) {
501
502
                if (Objects.equals(line1.getYIntercept(), line2.getYIntercept())
503
                        || (Objects.equals(Math.abs(line1.getYIntercept()), 0.0)
504
                        && Objects.equals(Math.abs(line2.getYIntercept()), 0.0))) { //Same lines
505
                    perpendicular = line1.getPerpendicular(point.getX(), point.getY());
506
                    Point2D intersection = line1.getIntersection(perpendicular);
507
                    return createCircle(point, point.distance(geomManager.createPoint(intersection.getX(), intersection.getY(), subtype)), subtype);
508
                } else if (Double.isInfinite(line1.getSlope())) { //Parallel and vertical lines
509
                    Point center = createPoint(-(line2.getC() + line1.getC()) / 2.0, point.getY(), subtype);
510
                    double radius = line1.getDistance(center.getX(), center.getY());
511
                    return createCircle(center, radius, subtype);
512
                } else { //Parallel lines
513
                    bisector = euclideanManager.createLine2D(line1.getA(), line1.getB(), (line2.getC()+line1.getC())/2);
514
                }
515
516
            } else {
517
518
                EuclideanLine2D[] bisectors = line1.getBisectors(line2);
519
520
                double distance1 = bisectors[0].getDistance(point.getX(), point.getY());
521
                double distance2 = bisectors[1].getDistance(point.getX(), point.getY());
522
523
                bisector = bisectors[0];
524
                if (distance1 > distance2) {
525
                    bisector = bisectors[1];
526
                }
527
            }
528
529
            if (Double.isInfinite(bisector.getSlope())) {
530
                Point2D intersection = line1.getIntersection(line2);
531
                Point center = createPoint(intersection.getX(), point.getY(), subtype);
532
                Double radius = line1.getDistance(center.getX(), center.getY());
533
                return createCircle(center, radius, subtype);
534
            } else if (bisector.getSlope() == 0.0) {
535
                if (line1.isParallel(line2)) { //Objects.equals(m0, m1)) { //Same slope
536
                    Point center = createPoint(point.getX(), bisector.getYIntercept(), subtype);
537
                    Double radius = line1.getDistance(center.getX(), center.getY());
538
                    return createCircle(center, radius, subtype);
539
                } else {
540
                    Point2D intersection = line1.getIntersection(line2);
541
                    Point center = createPoint(point.getX(), intersection.getY(), subtype);
542
                    Double radius = line1.getDistance(center.getX(), center.getY());
543
                    return createCircle(center, radius, subtype);
544
                }
545
            }
546
547
            perpendicular = bisector.getPerpendicular(point.getX(), point.getY());
548
            Point2D intersection = bisector.getIntersection(perpendicular);
549
            Double radius = line1.getDistance(intersection.getX(), intersection.getY());
550
            return createCircle(
551
                    geomManager.createPoint(intersection.getX(), intersection.getY(), subtype),
552
                    radius,
553
                    subtype);
554
555
        } catch (GeometryOperationNotSupportedException | GeometryOperationException ex) {
556
            throw new CreateGeometryException(Geometry.TYPES.CIRCLE, subtype, ex);
557
        }
558
    }
559
560
    /**
561
     * Creates a circle from two tangent geometries and the radius.
562
     *
563
     * @param geometry1
564
     *            A tangent geometry
565
     * @param geometry2
566
     *            Another tangent geometry
567
     * @param radius
568
     *            the radius of the cicle.
569
     * @param firstPoint
570
     *            a point near tangent point of geometry1
571
     * @param secondPoint
572
     *            a point near tangent point of geometry2
573
     * @param subtype
574
     *            subtype of circle. See {@link Geometry.SUBTYPES}
575
     * @return The circle created from two tangent geometries and the radius received as parameters.
576
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
577
     */
578
    public static Circle createCircle(Geometry geometry1, Geometry geometry2, double radius, Point firstPoint, Point secondPoint, int subtype) throws CreateGeometryException {
579
580
        try {
581
            Geometry buffer1 = geometry1.buffer(radius);
582
            MultiLine lines1 = buffer1.toLines();
583
584
            Geometry buffer2 = geometry2.buffer(radius);
585
            MultiLine lines2 = buffer2.toLines();
586
587
            Geometry intersection = lines1.intersection(lines2);
588
589
            Point center = null;
590
            if(intersection!=null){
591
                MultiPoint points = intersection.toPoints();
592
593
                double distance = Double.POSITIVE_INFINITY;
594
                for (int i = 0; i < points.getPrimitivesNumber(); i++) {
595
                    Point point = points.getPointAt(i);
596
                    double pointDistance = point.distance(firstPoint)+point.distance(secondPoint);
597
                    if(pointDistance<distance){
598
                        center = point;
599
                        distance = pointDistance;
600
                    }
601
                }
602
            }
603
            if(center == null){
604
                return null;
605
            }
606
            return createCircle(center, radius, subtype);
607
608
        } catch (GeometryOperationNotSupportedException | GeometryOperationException | GeometryException ex) {
609
            throw new CreateGeometryException(Geometry.TYPES.CIRCLE, subtype, ex);
610
        }
611
612
    }
613
614
    /**
615
     * Creates an arc as of center, radius, start angle and extension angle.
616
     *
617
     * @param center
618
     *            center of arc.
619
     * @param radius
620
     *            of arc.
621
     * @param startAngle
622
     *            of arc in radians
623
     * @param angleExt
624
     *            of arc in radians
625
     * @param subtype
626
     *            subtype of arc. See {@link Geometry.SUBTYPES}
627
     * @return The arc created with center, radius, start angle and extension
628
     *         angle.
629
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
630
     */
631
    public static Arc createArc(Point center, double radius, double startAngle,
632
            double angleExt, int subtype) throws CreateGeometryException {
633
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
634
        Arc arc = (Arc) geomManager.create(Geometry.TYPES.ARC, subtype);
635
        arc.setPoints(center, radius, startAngle, angleExt);
636
        return arc;
637
    }
638
639
    /**
640
     * Creates an arc as of three points.
641
     *
642
     * @param start
643
     *            point of arc
644
     * @param middle
645
     *            point of arc. It can be any point of arc.
646
     * @param end
647
     *            point of arc
648
     * @param subtype
649
     *            of arc. See {@link Geometry.SUBTYPES}
650
     * @return The arc created that it start at start point, cross middle
651
     *         point and end at end point.
652
     * @throws org.gvsig.tools.exception.BaseException
653
     */
654
    public static Arc createArc(Point start, Point middle, Point end, int subtype)
655
            throws BaseException {
656
657
        Arc arc = (Arc) GeometryLocator.getGeometryManager().create(Geometry.TYPES.ARC, subtype);
658
        arc.setPoints(start, middle, end);
659
        return arc;
660
661
    }
662
663
    /**
664
     * Creates an ellipse from start and end point of A axis and half length
665
     * of B axis.
666
     *
667
     * @param firstPointAxisA
668
     *            first point of A axis
669
     * @param secondPointAxisA
670
     *            second point of B axis
671
     * @param halfLengthAxisB
672
     *            half length of B axis
673
     * @param subtype
674
     *            of ellipse See {@link Geometry.SUBTYPES}
675
     * @return The ellipse created
676
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
677
     */
678
    public static Arc createEllipse(Point firstPointAxisA, Point secondPointAxisA,
679
            double halfLengthAxisB, int subtype) throws CreateGeometryException {
680
        try {
681
            double lengthAxisA = secondPointAxisA.distance(firstPointAxisA);
682
683
            Point origen = createPoint(0, 0, subtype);
684
            Arc ellipse = createArc(
685
                    origen,
686
                    lengthAxisA / 2,
687
                    0,
688
                    2 * Math.PI,
689
                    subtype);
690
691
            ellipse.scale(origen, 1, halfLengthAxisB * 2 / lengthAxisA);
692
            final EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
693
            EuclideanLine2D axisA = euclideanManager.createLine2D(
694
                    firstPointAxisA.getX(),
695
                    firstPointAxisA.getY(),
696
                    secondPointAxisA.getX(),
697
                    secondPointAxisA.getY());
698
            double angle = axisA.getAngle();
699
            ellipse.rotate(angle, 0, 0);
700
            Point centerOfEllipse = getMidPoint(firstPointAxisA, secondPointAxisA, subtype);
701
            ellipse.move(centerOfEllipse.getX(), centerOfEllipse.getY());
702
            return ellipse;
703
        } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
704
            throw new CreateGeometryException(Geometry.TYPES.ARC, subtype, e);
705
        }
706
    }
707
708
    /**
709
     * Creates a filled ellipse from start and end point of A axis and half length
710
     * of B axis.
711
     *
712
     * @param firstPointAxisA
713
     *            first point of A axis
714
     * @param secondPointAxisA
715
     *            second point of B axis
716
     * @param halfLengthAxisB
717
     *            half length of B axis
718
     * @param subtype
719
     *            of ellipse See {@link Geometry.SUBTYPES}
720
     * @return The ellipse created
721
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
722
     */
723
    public static Ellipse createFilledEllipse(Point firstPointAxisA,
724
            Point secondPointAxisA, double halfLengthAxisB, int subtype)
725
            throws CreateGeometryException {
726
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
727
        Ellipse ellipse = (Ellipse) geomManager.create(Geometry.TYPES.ELLIPSE, subtype);
728
        ellipse.setPoints(firstPointAxisA, secondPointAxisA, halfLengthAxisB);
729
        return ellipse;
730
    }
731
732
    /**
733
     * Gets center point of three points.
734
     *
735
     * @param a
736
     *            Point one
737
     * @param b
738
     *            Point two
739
     * @param c
740
     *            Point three
741
     * @param subtype
742
     *            of point created. See {@link Geometry.SUBTYPES}
743
     * @return Point center.
744
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
745
     */
746
    public static Point getCenter(Point a, Point b, Point c, int subtype)
747
            throws CreateGeometryException {
748
749 45872 jjdelcerro
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
750 45205 fdiaz
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
751 45872 jjdelcerro
752
        Point2D center = euclideanManager.getCenter(
753
                a.getX(), a.getY(),
754
                b.getX(), b.getY(),
755
                c.getX(), c.getY()
756
        );
757
        return geomManager.createPoint(center.getX(), center.getY(), subtype);
758 45205 fdiaz
    }
759
760
    /**
761
     * Gets midpoint of two points
762
     *
763
     * @param a
764
     *            Point one
765
     * @param b
766
     *            Point two
767
     * @param subtype
768
     *            of point created. See {@link Geometry.SUBTYPES}
769
     * @return Mid point of points.
770
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
771
     */
772
    public static Point getMidPoint(Point a, Point b, int subtype)
773
            throws CreateGeometryException {
774 45872 jjdelcerro
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
775
        Point2D p = euclideanManager.getMidPoint(
776
                a.getX(), a.getY(), b.getX(), b.getY()
777
        );
778
        return createPoint(p.getX(), p.getY(), subtype);
779 45205 fdiaz
    }
780
781
    /**
782
     * Creates line as of two point coordinates.
783
     *
784
     * @param x1
785
     *            The X1 coordinate
786
     * @param y1
787
     *            The y1 coordinate
788
     * @param x2
789
     *            The X2 coordinate
790
     * @param y2
791
     *            The y2 coordinate
792
     * @param subtype
793
     *            of line. See {@link Geometry.SUBTYPES}
794
     * @return The Line created.
795
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
796
     */
797
    public static Line createLine(double x1, double y1, double x2, double y2,
798
            int subtype) throws CreateGeometryException {
799
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
800
        Line line = (Line) geomManager.create(Geometry.TYPES.CURVE, subtype);
801
        line.addVertex(x1, y1);
802
        line.addVertex(x2, y2);
803
        return line;
804
    }
805
806
    /**
807
     * Creates line as of two point objects.
808
     *
809
     * @param p1
810
     *            First point
811
     * @param p2
812
     *            Second point
813
     * @param subtype
814
     *            of line. See {@link Geometry.SUBTYPES}
815
     * @return The Line created.
816
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
817
     */
818
    public static Line createLine(Point p1, Point p2, int subtype)
819
            throws CreateGeometryException {
820
        return createLine(p1.getX(), p1.getY(), p2.getX(), p2.getY(),
821
                subtype);
822
    }
823
824
    /**
825
     * Create Spline from point list
826
     *
827
     * @param points
828
     * @param subtype
829
     * @return
830
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
831
     */
832
    public static Spline createSpline(List<Point> points, int subtype)
833
            throws CreateGeometryException {
834
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
835
        Spline spline = (Spline) geomManager.create(Geometry.TYPES.SPLINE, subtype);
836
837
        points.forEach((point) -> {
838
            spline.addVertex(point);
839
        });
840
841
        return spline;
842
    }
843
844
845 45243 fdiaz
    /**
846
     * Calculate the angle between points p1 and p2 with vertex at vertex point
847
     *
848
     * @param vertex
849
     * @param p1
850
     * @param p2
851
     * @return
852
     */
853
    public static double calculateAngle(Point vertex, Point p1, Point p2){
854 45872 jjdelcerro
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
855
        return euclideanManager.calculateAngle(
856
                vertex.getX(), vertex.getY(),
857
                p1.getX(), p1.getY(),
858
                p2.getX(), p2.getY()
859
        );
860 45243 fdiaz
    }
861
862
    /**
863
     * Find the angle in the counterclockwise direction between
864
     * the horizontal line and point p relative to the vertex
865
     *
866
     * @param vertex
867
     * @param p
868
     * @return
869
     */
870
    public static double calculateAngle(Point vertex, Point p){
871 45872 jjdelcerro
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
872
        return euclideanManager.calculateAngle(
873
                vertex.getX(), vertex.getY(),
874
                p.getX(), p.getY()
875
        );
876 45243 fdiaz
    }
877 45268 fdiaz
878
    public static boolean areThreePointsInLine(Point a, Point b, Point c){
879 45872 jjdelcerro
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
880
        return euclideanManager.areThreePointsInLine(
881
                a.getX(), a.getY(),
882
                b.getX(), b.getY(),
883
                c.getX(), c.getY()
884
        );
885 45268 fdiaz
    }
886 45205 fdiaz
887 45732 jjdelcerro
    /**
888
     * Returns a formatted string using the specified format string and coordinate values.Conversion options are:
889
     * <ul>
890
     * <li><code>%[flags][width][.precision]d</code> The result is formatted as a integer number with the degress of the coordinate
891
     * <li><code>%[flags][width][.precision]m</code> The result is formatted as a integer number with the minutes of the coordinate
892
     * <li><code>%[flags][width][.precision]s</code> The result is formatted as a decimal number with the seconds of the coordinate.
893
     * <li><code>%[flags][width][.precision]D</code> The result is formatted as a decimal number with the degress
894
     * <li><code>%-</code> The result is formatted with the sign if it is negative
895
     * <li><code>%+</code> The result is formatted with the sign
896
     * </ul>
897
     *
898
     * Example:
899
     * <table>
900
     * <tr><td>formatCoordinate("%-%d? %m' %s'' N", 39.89)<td>"39? 53' 24.000'' N"
901
     * <tr><td>formatCoordinate("%-%d? %m' %.0s'' N", 39.89)<td>"39? 53' 24'' N"
902
     * <tr><td>formatCoordinate("%+%d? %m' %.2s'' N (%4.4D)", 39.89)<td>"+39? 53' 24.00'' N (39.8900)"
903
     * <tr><td>formatCoordinate("%-%d? %m' N", 39.89)<td> "39? 53' N"
904
     * <tr><td>formatCoordinate("%-%d? %m' N", -39.89)<td> "-39? 53' N"
905
     * <tr><td>formatCoordinate("%-%d? %m' N (%4.4D)", 39.89)<td> "39? 53' N (39.8900)"
906
     * </table>
907
     *
908
     * @param fmt
909
     * @param coordinate
910
     * @return
911
     */
912
    public static String formatCoordinate(String fmt, double coordinate) {
913
        return formatCoordinate(fmt, null, coordinate);
914
    }
915
916
    public static String formatCoordinate(String fmt, String NS, double coordinate) {
917
918
        double value = Math.abs(coordinate);
919
920
        int deg = (int)(value);
921
        double min = (value - deg) * 60;
922
        double secs = (min - (int) min)*60;
923
924
        String r = fmt;
925
        r = r.replace("%-",coordinate<0 ? "-" : "");
926
        r = r.replace("%+",coordinate<0 ? "-" : "+");
927
        if( StringUtils.isBlank(NS) || value==0) {
928
            r = r.replace("%N","");
929
        } else {
930
            r = r.replace("%N",coordinate>0 ? NS.substring(0,1)  : NS.substring(1,2) );
931
        }
932
        r = formatCoordinate_replace(r,"s","f", secs);
933
        r = formatCoordinate_replace(r,"d","d", deg);
934
        r = formatCoordinate_replace(r,"m","d", (int)min);
935
        r = formatCoordinate_replace(r,"D","f", value);
936
        return r;
937
    }
938 45747 fdiaz
939
    public static String formatAngle(String fmt, double angle) {
940
941
        double value = Math.abs(angle);
942
943
        int deg = (int)(value);
944
        double min = (value - deg) * 60;
945
        double secs = (min - (int) min)*60;
946
947
        String r = fmt;
948
        r = r.replace("%-",angle<0 ? "-" : "");
949
        r = r.replace("%+",angle<0 ? "-" : "+");
950
951
        r = formatCoordinate_replace(r,"s","f", secs);
952
        r = formatCoordinate_replace(r,"d","d", deg);
953
        r = formatCoordinate_replace(r,"m","d", (int)min);
954 46332 fdiaz
        r = formatCoordinate_replace(r,"M","f", min);
955 45747 fdiaz
        r = formatCoordinate_replace(r,"D","f", value);
956
        return r;
957
    }
958 45732 jjdelcerro
959
    private static String formatCoordinate_replace(String fmt, String source_conversion, String target_conversion, Object value) {
960
        String s = fmt;
961
        Pattern p = Pattern.compile("%([-+#0,(]?+[0-9]*[.]*[0-9]*)" + source_conversion);
962
        Matcher macher = p.matcher(s);
963
        if (macher.find()) {
964
            String mod = macher.group(1);
965
            if (StringUtils.isBlank(mod)) {
966
                if( value instanceof Double ) {
967
                    s = fmt.replace("%" + source_conversion, String.format(Locale.ENGLISH,"%.3f", value));
968
                } else {
969
                    s = fmt.replace("%" + source_conversion, String.valueOf(value));
970
                }
971
            } else {
972
                String x = String.format(Locale.ENGLISH,"%" + mod + target_conversion, value);
973
                s = macher.replaceAll(x);
974
            }
975
            return s;
976
        }
977
        return s;
978
    }
979 45747 fdiaz
980
    /**
981
     * Returns the coefficient that expresses the direction in which the angle with vertex at center a and from point1 to point2 is beaten
982
     * coefDirection >= 0 then the direction is CCW
983
     * else the direction is CW
984
     *
985
     * @param center
986
     * @param point1
987
     * @param point2
988
     * @return
989
     */
990
    public static double getCoefDirection(Point center, Point point1, Point point2) {
991 45872 jjdelcerro
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
992
        return euclideanManager.getCoefDirection(
993
                center.getX(), center.getY(),
994
                point1.getX(), point1.getY(),
995
                point2.getX(), point2.getY()
996
        );
997 45747 fdiaz
    }
998 45732 jjdelcerro
999 45880 fdiaz
    /**
1000
     * Calculates a point on the line that passes through two points whose
1001
     * distance to the first is proportional to the distance between them
1002
     * according to the lambda parameter
1003
     *
1004
     * @param p1
1005
     * @param p2
1006
     * @param lambda
1007
     * @return
1008
     * @throws CreateGeometryException
1009
     * @throws GeometryOperationNotSupportedException
1010
     * @throws GeometryOperationException
1011
     */
1012
    public static Point calculateLambdaPoint(Point p1, Point p2, double lambda) throws CreateGeometryException, GeometryOperationNotSupportedException, GeometryOperationException {
1013
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
1014
        GeometryType geomType = p1.getGeometryType();
1015
        int subtype = geomType.getSubType();
1016
        int dimension = geomType.getDimension();
1017
        double[] coords = new double[dimension];
1018
        Point p = geomManager.createPoint(0, 0, subtype);
1019
        double distance = p1.distance(p2);
1020
        for (int d = 0; d < dimension; d++) {
1021
            p.setCoordinateAt(
1022
                    d,
1023
                    p1.getCoordinateAt(d) + (p2.getCoordinateAt(d) - p1.getCoordinateAt(d)) * lambda);
1024
        }
1025
1026
        return p;
1027
    }
1028 45732 jjdelcerro
1029 45747 fdiaz
1030 45917 fdiaz
    /**
1031
     * Returns true if two polygons overlap taking into account the given tolerance
1032
     *
1033
     * @param polygon
1034
     * @param polygon2
1035
     * @param theTolerance
1036
     * @return
1037
     * @throws GeometryOperationNotSupportedException
1038
     * @throws GeometryOperationException
1039
     */
1040
    public static boolean overlaps(Geometry polygon, Geometry polygon2, double theTolerance) throws GeometryOperationNotSupportedException, GeometryOperationException {
1041
        if (polygon != null && polygon2 != null) {
1042
            if (theTolerance > 0) {
1043
                Geometry buffer1 = polygon.buffer(-theTolerance);
1044
                if (buffer1 != null) {
1045
                    return buffer1.overlaps(polygon2);
1046
                } else{
1047
                    Geometry buffer2 = polygon2.buffer(-theTolerance);
1048
                    if (buffer2 != null) {
1049
                        return polygon.overlaps(buffer2);
1050
                    }
1051
                }
1052
            } else {
1053
                return polygon.overlaps(polygon2);
1054
            }
1055
        }
1056
        return false;
1057
    }
1058 45880 fdiaz
1059 46331 fdiaz
    /**
1060
     * A value that indicates an orientation of clockwise, or a right turn.
1061
     */
1062
    public static final int ANGLE_TURN_CLOCKWISE = -1;
1063
1064
    /**
1065
     * A value that indicates an orientation of counterclockwise, or a left
1066
     * turn.
1067
     */
1068
    public static final int ANGLE_TURN_COUNTERCLOCKWISE = 1;
1069
1070
    /**
1071
     * A value that indicates an orientation of collinear, or no turn
1072
     * (straight).
1073
     */
1074
    public static final int ANGLE_TURN_NONE = 0;
1075
1076
    /**
1077
     * Returns whether an angle must turn clockwise or counterclockwise to
1078
     * overlap another angle.
1079
     *
1080
     * @param ang1 an angle (in radians)
1081
     * @param ang2 an angle (in radians)
1082
     * @return whether a1 must turn ANGLE_TURN_CLOCKWISE, COUNTERCLOCKWISE or NONE to
1083
 overlap a2.
1084
     */
1085
    public static int angleGetTurn(double ang1, double ang2) {
1086
        double crossproduct = Math.sin(ang2 - ang1);
1087
1088
        if (crossproduct > 0) {
1089
            return ANGLE_TURN_COUNTERCLOCKWISE;
1090
        }
1091
        if (crossproduct < 0) {
1092
            return ANGLE_TURN_CLOCKWISE;
1093
        }
1094
        return ANGLE_TURN_NONE;
1095
    }
1096
1097
    /**
1098
     * Computes the unoriented smallest difference between two angles. The
1099
     * angles are assumed to be normalized to the range [-Pi, Pi]. The result
1100
     * will be in the range [0, Pi].
1101
     *
1102
     * @param ang1 the angle of one vector (in [-Pi, Pi] )
1103
     * @param ang2 the angle of the other vector (in range [-Pi, Pi] )
1104
     * @return the angle (in radians) between the two vectors (in range [0, Pi]
1105
     * )
1106
     */
1107
    public static double angleDiff(double ang1, double ang2) {
1108
        double delAngle;
1109
1110
        if (ang1 < ang2) {
1111
            delAngle = ang2 - ang1;
1112
        } else {
1113
            delAngle = ang1 - ang2;
1114
        }
1115
1116
        if (delAngle > Math.PI) {
1117
            delAngle = (2 * Math.PI) - delAngle;
1118
        }
1119
1120
        return delAngle;
1121
    }
1122 46332 fdiaz
1123 45747 fdiaz
//    public static void main(String[] args) throws GeometryException {
1124
//        String s;
1125
//        s =  GeometryUtils.formatCoordinate("%-%d\u00B0 %m\u2032 %s\u2033 N", 39.89);
1126 45732 jjdelcerro
//        System.out.println(s);
1127 45747 fdiaz
//        s =  GeometryUtils.formatCoordinate("%-%d\u00B0 %m\u2032 %.0s\u2033 N", 39.89);
1128 45732 jjdelcerro
//        System.out.println(s);
1129 45747 fdiaz
//        s =  GeometryUtils.formatCoordinate("%+%d\u00B0 %m\u2032 %.2s\u2033 N (%4.4D)", 39.89);
1130 45732 jjdelcerro
//        System.out.println(s);
1131 45747 fdiaz
//        s =  GeometryUtils.formatCoordinate("%-%d\u00B0 %m\u2032 N", -39.89);
1132 45732 jjdelcerro
//        System.out.println(s);
1133 45747 fdiaz
//        s =  GeometryUtils.formatCoordinate("%-%d\u00B0 %m\u2032 N (%4.4D)", 39.89);
1134 45732 jjdelcerro
//        System.out.println(s);
1135 45747 fdiaz
//        Geometry g = GeometryUtils.createFrom("00000007d50000000100000007d20000002341258d57c2b73acf4150bf008a45b87241258d5eb2faa5364150befedb0f995841258d6aeb851eb84150befbeeb851ec41258d723d70a3d74150bef9d51eb85241258d7e428f5c294150bef677ae147b41258d9d147ae1484150beeea47ae14841258dbc28f5c28f4150bee72ae147ae41258dc7ae147ae14150bee468f5c28f41258dcc6b851eb84150bee31999999a41258dd1666666664150bee18b851eb841258dd8d70a3d714150bedf1d70a3d741258ddea8f5c28f4150bedc951eb85241258de3eb851eb84150bed99ccccccd41258dea3d70a3d74150bed6351eb85241258defbd70a3d74150bed3728f5c2941258df39999999a4150bed1751eb85241258df6c7ae147b4150bed01c28f5c341258df86b851eb84150becf1f5c28f641258dfa1999999a4150becd4666666641258dfb6147ae144150becbc51eb85241258dfd1999999a4150bec9a000000041258dfec28f5c294150bec753d70a3d41258e001eb851ec4150bec2f666666641258e047ae147ae4150beb73147ae1441258e054ccccccd4150beb3bc28f5c341258e054ccccccd4150beb2d70a3d7141258e05947ae1484150beb2047ae14841258e053d70a3d74150beb17333333341258e03a8f5c28f4150beb0e47ae14841258de69999999a4150beaca3d70a3d41258db10f5c28f64150bea46d70a3d741258dabdc28f5c34150bea3928f5c2941258da8dc28f5c34150bea300a3d70a41258da623d70a3d4150bea26147ae1441258da34ccccccd4150bea19d70a3d7");
1136
//
1137
//        System.out.println(g);
1138
//    }
1139 45732 jjdelcerro
1140 47264 jjdelcerro
    public static final List<Geometry> extractFrom(String s, IProjection proj) {
1141
        try {
1142
            if( StringUtils.isBlank(s) ) {
1143
                return null;
1144
            }
1145
            Geometry geom = createFrom(s,proj);
1146
            if( geom!=null ) {
1147
                if( geom.getProjection()==null ) {
1148
                    geom.setProjection(proj);
1149
                }
1150
                return Collections.singletonList(geom);
1151
            }
1152
            JsonValue json = Json.createObject(s);
1153
            if( json == null ) {
1154
                json = Json.createArray(s);
1155
                if( json == null ) {
1156
                    return null;
1157
                }
1158
            }
1159
            return extractFrom(json, proj);
1160
        } catch(Exception e) {
1161
            return null;
1162
        }
1163
    }
1164
1165
    public static final List<Geometry> extractFrom(JsonValue json, IProjection proj) {
1166
        ArrayList<Geometry> geoms = new ArrayList<>();
1167
        if( extractFrom(json, proj, geoms) && !geoms.isEmpty() ) {
1168
            return geoms;
1169
        }
1170
        return null;
1171
    }
1172 46331 fdiaz
1173 47264 jjdelcerro
    private static boolean extractFrom(JsonValue json, IProjection proj, List<Geometry> geoms) {
1174
        try {
1175
            if( json == null ) {
1176
                return false;
1177
            }
1178
            if( json instanceof JsonObject ) {
1179
                boolean x = false;
1180
                for (JsonValue value : ((JsonObject)json).values()) {
1181
                    if( extractFrom(value, proj, geoms) ) {
1182
                        x = true;
1183
                    }
1184
                }
1185
                return x;
1186
            }
1187
1188
            if( json instanceof JsonArray ) {
1189
                boolean x = false;
1190
                for (JsonValue value : ((JsonArray)json)) {
1191
                    if( extractFrom(value, proj, geoms) ) {
1192
                        x = true;
1193
                    }
1194
                }
1195
                return x;
1196
            }
1197
            Object x = Json.toObject(json);
1198
            if( x == null ) {
1199
                return false;
1200
            }
1201
            if( x instanceof Geometry ) {
1202
                Geometry geom = (Geometry) x;
1203
                if( geom.getProjection()==null ) {
1204
                    geom.setProjection(proj);
1205
                }
1206
                geoms.add(geom);
1207
                return true;
1208
            }
1209
1210
            String s = Objects.toString(x, null);
1211
            if( StringUtils.isBlank(s) ) {
1212
                return false;
1213
            }
1214
            Geometry geom = createFrom(s, proj);
1215
            if( geom!=null ) {
1216
                if( geom.getProjection()==null ) {
1217
                    geom.setProjection(proj);
1218
                }
1219
                geoms.add(geom);
1220
                return true;
1221
            }
1222
            return false;
1223
        } catch(Exception e) {
1224
            return false;
1225
        }
1226
    }
1227 46331 fdiaz
1228 47275 jjdelcerro
    public static final Geometry toAggregate(List<Geometry> geoms, StringBuilder warnings) {
1229 47264 jjdelcerro
        if( geoms==null || geoms.isEmpty() ) {
1230
            return null;
1231
        }
1232
        try {
1233
            GeometryManager manager = GeometryLocator.getGeometryManager();
1234
            Geometry first = geoms.get(0);
1235
            int firsttype = first.getType();
1236
            int type = firsttype;
1237
            if( manager.isSubtype(Geometry.TYPES.SURFACE, type) ) {
1238
                type = Geometry.TYPES.MULTIPOLYGON;
1239
            } else if( manager.isSubtype(Geometry.TYPES.CURVE, type) ) {
1240
                type = Geometry.TYPES.MULTILINE;
1241
            } else if( manager.isSubtype(Geometry.TYPES.POINT, type) ) {
1242
                type = Geometry.TYPES.MULTIPOINT;
1243
            } else if( manager.isSubtype(Geometry.TYPES.MULTISURFACE, type) ) {
1244
                type = Geometry.TYPES.MULTIPOLYGON;
1245
            } else if( manager.isSubtype(Geometry.TYPES.MULTICURVE, type) ) {
1246
                type = Geometry.TYPES.MULTILINE;
1247
            } else if( manager.isSubtype(Geometry.TYPES.MULTIPOINT, type) ) {
1248
                type = Geometry.TYPES.MULTIPOINT;
1249
            } else {
1250 47275 jjdelcerro
                if( warnings!=null ) {
1251
                    warnings.append("The geometry type is not supported.");
1252
                    warnings.append("\n");
1253
                }
1254 47264 jjdelcerro
                return null;
1255
            }
1256
            int firstsubtype = first.getGeometryType().getSubType();
1257
            MultiPrimitive multi = (MultiPrimitive) manager.create(type, firstsubtype);
1258 47272 jjdelcerro
            if( first.getProjection()!=null ) {
1259
                multi.setProjection(first.getProjection());
1260
            }
1261 47264 jjdelcerro
            for (Geometry geom : geoms) {
1262 47272 jjdelcerro
                if( firsttype != geom.getType() ) {
1263 47275 jjdelcerro
                    if( warnings!=null ) {
1264
                        warnings.append("You cannot mix geometries of different types.");
1265
                        warnings.append("\n");
1266
                    }
1267 47264 jjdelcerro
                    return null; // No soportado. El agregado debe ser homogeneo.
1268
                }
1269 47272 jjdelcerro
                if( first.getProjection()!=null && geom.getProjection()!=null && !first.getProjection().equals(geom.getProjection())) {
1270 47275 jjdelcerro
                    if( warnings!=null ) {
1271
                        warnings.append("You cannot mix geometries with different projections.");
1272
                        warnings.append("\n");
1273
                    }
1274 47272 jjdelcerro
                    return null; // No soportado. El agregado debe ser homogeneo.
1275
                }
1276 47264 jjdelcerro
                multi.addPrimitives(geom);
1277
            }
1278
            return multi;
1279
        } catch(Exception e) {
1280 47275 jjdelcerro
            if( warnings!=null ) {
1281
                warnings.append("Can't aggregate geometries.");
1282
                warnings.append("\n(");
1283
                warnings.append(e.getLocalizedMessage());
1284
                warnings.append(")\n");
1285
            }
1286 47264 jjdelcerro
            return null;
1287
        }
1288
1289
    }
1290
1291 43906 jjdelcerro
}