Statistics
| Revision:

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

History | View | Annotate | Download (41.6 KB)

1
/**
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

    
25
package org.gvsig.fmap.geom.jts;
26

    
27
import com.vividsolutions.jts.io.geojson.GeoJsonReader;
28
import java.awt.geom.PathIterator;
29
import java.util.ArrayList;
30
import java.util.HashMap;
31
import java.util.Iterator;
32
import java.util.List;
33
import java.util.Map;
34
import org.apache.commons.codec.binary.Hex;
35
import org.apache.commons.lang3.StringUtils;
36
import org.cresques.cts.IProjection;
37
import org.gvsig.fmap.geom.Geometry;
38
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
39
import org.gvsig.fmap.geom.Geometry.TYPES;
40
import org.gvsig.fmap.geom.GeometryCoercionContext;
41
import org.gvsig.fmap.geom.GeometryException;
42
import org.gvsig.fmap.geom.GeometryLocator;
43
import org.gvsig.fmap.geom.GeometryManager;
44
import org.gvsig.fmap.geom.GeometryUtils;
45
import org.gvsig.fmap.geom.InformationbuilderWithGeometrySupport;
46
import org.gvsig.fmap.geom.SpatialIndex;
47
import org.gvsig.fmap.geom.SpatialIndexFactory;
48
import org.gvsig.fmap.geom.aggregate.MultiCurve;
49
import org.gvsig.fmap.geom.aggregate.MultiLine;
50
import org.gvsig.fmap.geom.aggregate.MultiPoint;
51
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
52
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
53
import org.gvsig.fmap.geom.aggregate.MultiSurface;
54
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
55
import org.gvsig.fmap.geom.exception.CreateGeometryException;
56
import org.gvsig.fmap.geom.jts.coerce.DefaultGeometryCoercionContext;
57
import org.gvsig.fmap.geom.jts.gputils.DefaultGeneralPathX;
58
import org.gvsig.fmap.geom.jts.primitive.DefaultNullGeometry;
59
import org.gvsig.fmap.geom.jts.primitive.Envelope2D;
60
import org.gvsig.fmap.geom.jts.primitive.Envelope3D;
61
import org.gvsig.fmap.geom.jts.spatialindex.SpatialIndexFactoryJSIRTree;
62
import org.gvsig.fmap.geom.jts.spatialindex.SpatialIndexFactoryJTSQuadtree;
63
import org.gvsig.fmap.geom.jts.util.GMLUtils;
64
import org.gvsig.fmap.geom.jts.util.JTSUtils;
65
import org.gvsig.fmap.geom.operation.GeometryOperation;
66
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
67
import org.gvsig.fmap.geom.operation.GeometryOperationException;
68
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
69
import org.gvsig.fmap.geom.primitive.Curve;
70
import org.gvsig.fmap.geom.primitive.Envelope;
71
import org.gvsig.fmap.geom.primitive.GeneralPathX;
72
import org.gvsig.fmap.geom.primitive.IGeneralPathX;
73
import org.gvsig.fmap.geom.primitive.Line;
74
import org.gvsig.fmap.geom.primitive.NullGeometry;
75
import org.gvsig.fmap.geom.primitive.Point;
76
import org.gvsig.fmap.geom.primitive.Polygon;
77
import org.gvsig.fmap.geom.primitive.Surface;
78
import org.gvsig.fmap.geom.type.GeometryType;
79
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
80
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
81
import org.gvsig.tools.dynobject.DynObject;
82
import org.gvsig.tools.library.impl.DefaultLibrariesInitializer;
83
import org.gvsig.tools.service.Service;
84
import org.gvsig.tools.service.ServiceException;
85
import org.gvsig.tools.service.spi.ServiceFactory;
86
import org.slf4j.Logger;
87
import org.slf4j.LoggerFactory;
88

    
89
/**
90
 * Default implementation for the {@link GeometryManager}. When the
91
 * application starts, this class is registered in the {@link GeometryLocator}
92
 * using the {@link DefaultGeometryLibrary}.
93
 *
94
 * @author <a href="mailto:jpiera@gvsig.org">Jorge Piera</a>
95
 */
96

    
97
@SuppressWarnings("UseSpecificCatch")
98
public class DefaultGeometryManager implements GeometryManager {
99

    
100
    private static final Logger LOGGER = LoggerFactory.getLogger(GeometryManager.class);
101
    
102
    /**
103
     * Offset for GeometryType -1 value (UNKNOWN)
104
     */
105
    private final int GEOMETRY_TYPE_OFFSET = 1;
106
    
107
    private double flatness = 0.8;
108

    
109
    private final Map spatialIndexFactories = new HashMap();
110

    
111
    /**
112
     * This list holds the unique name of all registered geometry operations.
113
     * The index in which they are stored is also the operation code used to
114
     * invoke each one of them
115
     */
116
    private final List geometryOperations = new ArrayList();
117

    
118
    /**
119
     * Common operations are registered here. Type specific operations are
120
     * registered in the corresponding GeometryType instance
121
     */
122
    // private List commonOperations = new ArrayList();
123

    
124
    /**
125
     * This map holds the instances of all registered GeometryType. The key is
126
     * the name of the specific Geometry subclass.
127
     * In other words, the string "org.gvsig.fmap.geom.primitive.Point2D" is the
128
     * hash key to obtain an instance of GeometryType holding the
129
     * operations associated to the class org.gvsig.fmap.geom.primitive.Point2D.
130
     */
131
    private final Map geometryTypeName = new HashMap();
132

    
133
    /**
134
     * Matrix of geometry types by type (row) and subtype (column). This matrix
135
     * will contain null values in the cells where a GeometryType hasn't been
136
     * registered.
137
     */
138
    private GeometryType[][] geometryTypes;
139
    
140
    // Initially create a matrix of 27 x 6, which are the current default
141
    // types and subtypes. If another type or subtype is registered, the
142
    // matrix will grow as needed
143
    private static final int DEFAULT_TYPES_SIZE = 27; // [-1, 25]
144
    private static final int DEFAULT_SUBTYPES_SIZE = 6;
145

    
146
    public DefaultGeometryManager() throws GeometryException {
147
        this(DEFAULT_TYPES_SIZE, DEFAULT_SUBTYPES_SIZE);
148
    }
149

    
150
    public DefaultGeometryManager(int initialTypesSize, int initialSubtypesSize) throws GeometryException {
151
        geometryTypes = new GeometryType[initialTypesSize][initialSubtypesSize];
152
    }
153

    
154
    @Override
155
    public int registerGeometryOperation(String geomOpName, GeometryOperation geomOp, GeometryType geomType) {
156
        if (geomOp == null) {
157
            throw new IllegalArgumentException("geomOp cannot be null.");
158
        }
159
        if (geomType == null) {
160
            throw new IllegalArgumentException("geomType cannot be null.");
161
        }
162

    
163
        int index = getGeometryOperationCode(geomOpName);
164

    
165
        geomType.setGeometryOperation(index, geomOp);
166

    
167
        return index;
168
    }
169

    
170
    @Override
171
    public int registerGeometryOperation(String geomOpName, GeometryOperation geomOp) {
172
        if (geomOpName == null) {
173
            throw new IllegalArgumentException("geomOpName cannot be null.");
174
        }
175
        if (geomOp == null) {
176
            throw new IllegalArgumentException("geomOp cannot be null.");
177
        }
178

    
179
        int index = getGeometryOperationCode(geomOpName);
180

    
181
        Iterator it = geometryTypeName.values().iterator();
182
        while (it.hasNext()) {
183
            GeometryType geometryType = (GeometryType) it.next();
184
            registerGeometryOperation(geomOpName, geomOp, geometryType);
185
        }
186

    
187
        return index;
188

    
189
    }
190

    
191
    @SuppressWarnings("override")
192
    public int registerGeometryOperation(String geomOpName, GeometryOperation geomOp, int type, int subType)
193
        throws GeometryTypeNotSupportedException, GeometryTypeNotValidException {
194
        GeometryType geometryType = getGeometryType(type, subType);
195
        return registerGeometryOperation(geomOpName, geomOp, geometryType);
196
    }
197

    
198
    @Override
199
    public int registerGeometryOperation(String geomOpName, GeometryOperation geomOp, int type) {
200
        int code = -1;
201
        Iterator it = geometryTypeName.values().iterator();
202
        while (it.hasNext()) {
203
            GeometryType geometryType = (GeometryType) it.next();
204
            if ((type == geometryType.getType())) {
205
                code = registerGeometryOperation(geomOpName, geomOp, geometryType);
206
            }
207
        }
208
        return code;
209
    }
210

    
211
    @Override
212
    public int registerGeometryOperationBySubtype(String geomOpName, GeometryOperation geomOp, int subType) {
213
        int code = -1;
214
        Iterator it = geometryTypeName.values().iterator();
215
        while (it.hasNext()) {
216
            GeometryType geometryType = (GeometryType) it.next();
217
            if ((subType == geometryType.getSubType())) {
218
                code = registerGeometryOperation(geomOpName, geomOp, geometryType);
219
            }
220
        }
221
        return code;
222
    }
223

    
224
    @Override
225
    public int registerGeometryOperationBySuperType(String geomOpName, GeometryOperation geomOp, int superType) {
226
        int code = -1;
227
        Iterator it = geometryTypeName.values().iterator();
228
        while (it.hasNext()) {
229
            GeometryType geometryType = (GeometryType) it.next();
230
            if (geometryType.isTypeOf(superType)) {
231
                code = registerGeometryOperation(geomOpName, geomOp, geometryType);
232
            }
233
        }
234
        return code;
235
    }
236

    
237
    @Override
238
    public int registerGeometryOperationBySuperSubType(String geomOpName, GeometryOperation geomOp, int superSubType) {
239
        int code = -1;
240
        Iterator it = geometryTypeName.values().iterator();
241
        while (it.hasNext()) {
242
            GeometryType geometryType = (GeometryType) it.next();
243
            if (geometryType.isSubTypeOf(superSubType)) {
244
                code = registerGeometryOperation(geomOpName, geomOp, geometryType);
245
            }
246
        }
247
        return code;
248
    }
249

    
250
    @Override
251
    public GeometryType registerGeometryType(Class geomClass, String name, int type, int subType) {
252
        return registerGeometryType(geomClass, name, type, subType, new int[0], new int[0]);
253
    }
254

    
255
    @Override
256
    public GeometryType registerGeometryType(Class geomClass, String name, int type, int subType, int superType,
257
        int superSubType) {
258
        return registerGeometryType(geomClass, name, type, subType, new int[] { superType }, new int[] { superSubType });
259
    }
260

    
261
    @Override
262
    public GeometryType registerGeometryType(Class geomClass, String name, int type, int subType, int superType) {
263
        return registerGeometryType(geomClass, name, type, subType, new int[] { superType }, new int[0]);
264
    }
265

    
266
    @Override
267
    public GeometryType registerGeometryType(Class geomClass, String name, int type, int subType, int[] superTypes) {
268
        return registerGeometryType(geomClass, name, type, subType, superTypes, new int[0]);
269
    }
270

    
271
    /**
272
     * Registers a Geometry implementation class with a predefined geometry type
273
     * and returns the
274
     * associated GeometryType instance. Available predefined types are defined
275
     * in {@link Geometry.TYPES} If the class is already registered then this
276
     * method throws an IllegalArgumentException.<br>
277
     *
278
     * How to register a geometry class with a predefined type:
279
     *
280
     * <pre>
281
     *
282
     * public class Point2D implements Point {
283
     *   private static final GeometryType geomType = GeometryManager.getInstance()
284
     *    .registerBasicGeometryType(Point2D.class, "Point2D", Geometry.TYPES.POINT);
285
     *
286
     * ...
287
     *   public int getType() {
288
     *      return geomType.getType();
289
     *   }
290
     * }
291
     * </pre>
292
     *
293
     * @param geomClass
294
     *            Geometry subclass. It must not be null and must implement
295
     *            Geometry, otherwise an exception
296
     *            is raised.
297
     * @param name
298
     *            Symbolic name for the geometry type, it can be null. If it is
299
     *            null then the symbolic name
300
     *            will be the simple class name.
301
     * @param type
302
     *            Type of geometry. Must be a value defined in
303
     *            {@link Geometry.TYPES}
304
     * @param subType
305
     *            SubType of geometry. Must be a value defined in
306
     *            {@link Geometry.SUBTYPES}
307
     * @return Instance of GeometryType associated to the Geometry
308
     *         implementation class
309
     *         geomClass
310
     * @throws IllegalArgumentException
311
     *             If geomClass is null or does not implement Geometry
312
     */
313
    @Override
314
    public GeometryType registerGeometryType(Class geomClass, String name, int type, int subType, int[] superTypes,
315
        int superSubTypes[]) {
316
        if (geomClass == null) {
317
            throw new IllegalArgumentException("geomClass cannot be null.");
318
        }
319

    
320
        if (!Geometry.class.isAssignableFrom(geomClass)) {
321
            throw new IllegalArgumentException(geomClass.getName() + " must implement the Geometry interface");
322
        }
323

    
324
        int offsettedType = type + GEOMETRY_TYPE_OFFSET;
325
        // Check if it is registered
326
        GeometryType geomType = null;
327
        if (offsettedType >= geometryTypes.length || subType >= geometryTypes[0].length
328
            || (geomType = geometryTypes[offsettedType][subType]) == null) {
329
            geomType = new DefaultGeometryType(geomClass, name, type, subType, superTypes, superSubTypes); //Attention!
330
            registerGeometryType(geomType);
331
        }
332

    
333
        LOGGER.debug("Class {} registered with name {}", geomClass, geomType.getName());
334

    
335
        return geomType;
336
    }
337

    
338
    @Override
339
    public void registerGeometryType(GeometryType geometryType) {
340
        int offsettedType = geometryType.getType() + GEOMETRY_TYPE_OFFSET;
341
        if (offsettedType >= geometryTypes.length || geometryType.getSubType() >= geometryTypes[0].length) {
342

    
343
            // Recreate the geometry type matrix if the types
344
            // or subtypes don't fit
345
            int newTypesSize =
346
                offsettedType < geometryTypes.length ? geometryTypes.length : offsettedType + 1;
347
            int newSubTypesSize =
348
                geometryType.getSubType() < geometryTypes[0].length ? geometryTypes[0].length : geometryType
349
                    .getSubType() + 1;
350
            GeometryType[][] newMatrix = new GeometryType[newTypesSize][newSubTypesSize];
351

    
352
            for (int i = 0; i < geometryTypes.length; i++) {
353
                System.arraycopy(geometryTypes[i], 0, newMatrix[i], 0, geometryTypes[i].length);
354
            }
355
            geometryTypes = newMatrix;
356
        }
357

    
358
        geometryTypes[offsettedType][geometryType.getSubType()] = geometryType;
359
        geometryTypeName.put(geometryType.getName(), geometryType);
360
    }
361

    
362
    @Override
363
    public GeometryType registerGeometryType(Class geomClass, int type, int subType) {
364
        return registerGeometryType(geomClass, null, type, subType);
365
    }
366

    
367
    @Override
368
    public GeometryType getGeometryType(int type, int subType) throws GeometryTypeNotSupportedException,
369
        GeometryTypeNotValidException {
370

    
371
        int offsettedType = type + GEOMETRY_TYPE_OFFSET;
372
        
373
        if (offsettedType >= geometryTypes.length || subType >= geometryTypes[0].length) {
374
            throw new GeometryTypeNotValidException(type, subType);
375
        }
376
        GeometryType gType = geometryTypes[offsettedType][subType];
377
        if (gType == null) {
378
            throw new GeometryTypeNotSupportedException(type, subType);
379
        }
380
        return gType;
381
    }
382

    
383
    @Override
384
    public Geometry create(GeometryType geomType) throws CreateGeometryException {
385
        return geomType.create();
386
    }
387

    
388
    @Override
389
    public Geometry create(String name) throws CreateGeometryException {
390
        if (!geometryTypeName.containsKey(name)) {
391
            throw new IllegalArgumentException(name + " has not been registered yet.");
392
        }
393
        return ((GeometryType) geometryTypeName.get(name)).create();
394
    }
395

    
396
    @Override
397
    public Geometry create(int type, int subType) throws CreateGeometryException {
398
        try {
399
            return getGeometryType(type, subType).create();
400
        } catch (GeometryException e) {
401
            throw new CreateGeometryException(type, subType, e);
402
        }
403
    }
404

    
405
    @Override
406
    public Curve createCurve(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
407
        Curve curve = (Curve) create(TYPES.CURVE, subType);
408
        curve.setGeneralPath(generalPathX);
409
        return curve;
410
    }
411

    
412
    @Override
413
    public NullGeometry createNullGeometry(int subType) throws CreateGeometryException {
414
        NullGeometry nullGeom = (NullGeometry) create(TYPES.NULL, subType);
415
        return nullGeom;
416
    }
417

    
418
    @Override
419
    public Point createPoint(double x, double y, int subType) throws CreateGeometryException {
420
        Point point = (Point) create(TYPES.POINT, subType);
421
        point.setX(x);
422
        point.setY(y);
423
        return point;
424
    }
425

    
426
    @Override
427
    public Surface createSurface(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
428
        Surface surface = (Surface) create(TYPES.SURFACE, subType);
429
        surface.setGeneralPath(generalPathX);
430
        return surface;
431
    }
432

    
433
    @Override
434
    public GeometryOperation getGeometryOperation(int opCode, int type, int subType)
435
        throws GeometryTypeNotSupportedException, GeometryOperationNotSupportedException, GeometryTypeNotValidException {
436
        GeometryType geometryType = getGeometryType(type, subType);
437
        return geometryType.getGeometryOperation(opCode);
438
    }
439

    
440
    @Override
441
    public GeometryOperation getGeometryOperation(int opCode) throws GeometryOperationNotSupportedException {
442
        if (opCode < 0) {
443
            throw new GeometryOperationNotSupportedException(opCode);
444
        }
445
        GeometryType type = (GeometryType) geometryTypeName.get(DefaultNullGeometry.class.getName());
446
        if (type == null) {
447
            throw new GeometryOperationNotSupportedException(opCode);
448
        }
449
        return type.getGeometryOperation(opCode);
450
    }
451

    
452
    @Override
453
    public Object invokeOperation(int opCode, Geometry geom, GeometryOperationContext ctx)
454
        throws GeometryOperationNotSupportedException, GeometryOperationException {
455
        GeometryOperation geomOp = geom.getGeometryType().getGeometryOperation(opCode);
456

    
457
        if (geomOp != null) {
458
            return geomOp.invoke(geom, ctx);
459
        }
460

    
461
        throw new GeometryOperationNotSupportedException(opCode, geom.getGeometryType());
462
    }
463

    
464
    @Override
465
    public Object invokeOperation(String geomOpName, Geometry geom, GeometryOperationContext ctx)
466
        throws GeometryOperationNotSupportedException, GeometryOperationException {
467
        int index = geometryOperations.indexOf(geomOpName);
468
        if (index == -1) {
469
            throw new GeometryOperationNotSupportedException(-1);
470
        }
471
        return invokeOperation(index, geom, ctx);
472
    }
473

    
474
    @Override
475
    public Object invokeOperation(String geomOpName, GeometryOperationContext ctx)
476
        throws GeometryOperationNotSupportedException, GeometryOperationException {
477
        int index = geometryOperations.indexOf(geomOpName);
478
        GeometryOperation geomOp = getGeometryOperation(index);
479
        return geomOp.invoke(null, ctx);
480
    }
481

    
482
    @Override
483
    public Envelope createEnvelope(int subType) {
484
        // TODO: register the envelopes!!!
485
        switch (subType) {
486
        case SUBTYPES.GEOM3D:
487
            return new Envelope3D();
488
        default:
489
            return new Envelope2D();
490
        }
491
    }
492

    
493
    @Override
494
    public Envelope createEnvelope(double minX, double minY, double maxX, double maxY, int subType)
495
        throws CreateEnvelopeException {
496
        org.gvsig.fmap.geom.primitive.Point min = null;
497
        org.gvsig.fmap.geom.primitive.Point max = null;
498
        try {
499
            min = createPoint(minX, minY, subType);
500
            max = createPoint(maxX, maxY, subType);
501
        } catch (CreateGeometryException e) {
502
            throw new CreateEnvelopeException(subType, e);
503
        }
504
        switch (subType) {
505
        case SUBTYPES.GEOM2D:
506
        case SUBTYPES.GEOM2DM:
507
            // Small optimization to directly create an Envelope2D
508
            // return new Envelope2D(minX, minY, maxX, maxY);
509
            return new Envelope2D(min, max, null);
510
        default:
511
            Envelope envelope = createEnvelope(subType);
512
            envelope.setLowerCorner(min);
513
            envelope.setUpperCorner(max);
514
            return envelope;
515
        }
516
    }
517

    
518
    @Override
519
    public MultiCurve createMultiCurve(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
520
        if (subType != SUBTYPES.GEOM2D) {
521
            // FIXME Exception
522
            throw new UnsupportedOperationException();
523
        }
524
        MultiCurve multiCurve = (MultiCurve) create(TYPES.MULTICURVE, subType);
525
        PathIterator piter = generalPathX.getPathIterator(null);
526
        GeneralPathX tmpPath = null;
527
        Curve tmpCurve;
528
        double[] coords = new double[6];
529
        double[] first = new double[6];
530
        int type;
531
        while (!piter.isDone()) {
532
            type = piter.currentSegment(coords);
533
            switch (type) {
534
            case PathIterator.SEG_MOVETO:
535
                if (tmpPath != null) {
536
                    tmpCurve = createCurve(tmpPath, subType);
537
                    multiCurve.addCurve(tmpCurve);
538
                }
539
                System.arraycopy(coords, 0, first, 0, 2);
540
                tmpPath = new GeneralPathX(piter.getWindingRule());
541
                tmpPath.moveTo(coords[0], coords[1]);
542
                break;
543

    
544
            case PathIterator.SEG_LINETO:
545
                if (tmpPath == null) {
546
                    System.arraycopy(coords, 0, first, 0, 2);
547
                    tmpPath = new GeneralPathX(piter.getWindingRule());
548
                }
549
                tmpPath.lineTo(coords[0], coords[1]);
550
                break;
551

    
552
            case PathIterator.SEG_QUADTO:
553
                if (tmpPath == null) {
554
                    System.arraycopy(coords, 0, first, 0, 2);
555
                    tmpPath = new GeneralPathX(piter.getWindingRule());
556
                }
557
                tmpPath.quadTo(coords[0], coords[1], coords[2], coords[3]);
558
                break;
559

    
560
            case PathIterator.SEG_CUBICTO:
561
                if (tmpPath == null) {
562
                    System.arraycopy(coords, 0, first, 0, 2);
563
                    tmpPath = new GeneralPathX(piter.getWindingRule());
564
                }
565
                tmpPath.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
566
                break;
567

    
568
            case PathIterator.SEG_CLOSE:
569
                tmpPath.lineTo(first[0], first[1]);
570
                break;
571

    
572
            } // end switch
573

    
574
            piter.next();
575

    
576
        }
577
        if (tmpPath != null) {
578
            tmpCurve = createCurve(tmpPath, subType);
579
            multiCurve.addCurve(tmpCurve);
580
        }
581

    
582
        return multiCurve;
583

    
584
    }
585

    
586
    @Override
587
    public MultiSurface createMultiSurface(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
588
        if (subType != SUBTYPES.GEOM2D) {
589
            // FIXME Exception
590
            throw new UnsupportedOperationException();
591
        }
592
        MultiSurface multiSurface = (MultiSurface) create(TYPES.MULTISURFACE, subType);
593
        PathIterator piter = generalPathX.getPathIterator(null);
594
        GeneralPathX tmpPath = null;
595
        Surface tmpSurface;
596
        double[] coords = new double[6];
597
        double[] first = new double[6];
598
        int type;
599
        while (!piter.isDone()) {
600
            type = piter.currentSegment(coords);
601
            switch (type) {
602
            case PathIterator.SEG_MOVETO:
603
                if (tmpPath != null) {
604
                    tmpSurface = createSurface(tmpPath, subType);
605
                    multiSurface.addSurface(tmpSurface);
606
                }
607
                System.arraycopy(coords, 0, first, 0, 2);
608
                tmpPath = new GeneralPathX(piter.getWindingRule());
609
                tmpPath.moveTo(coords[0], coords[1]);
610

    
611
            case PathIterator.SEG_LINETO:
612
                if (tmpPath == null) {
613
                    System.arraycopy(coords, 0, first, 0, 2);
614
                    tmpPath = new GeneralPathX(piter.getWindingRule());
615
                }
616
                tmpPath.lineTo(coords[0], coords[1]);
617
                break;
618

    
619
            case PathIterator.SEG_QUADTO:
620
                if (tmpPath == null) {
621
                    System.arraycopy(coords, 0, first, 0, 2);
622
                    tmpPath = new GeneralPathX(piter.getWindingRule());
623
                }
624
                tmpPath.quadTo(coords[0], coords[1], coords[2], coords[3]);
625
                break;
626

    
627
            case PathIterator.SEG_CUBICTO:
628
                if (tmpPath == null) {
629
                    System.arraycopy(coords, 0, first, 0, 2);
630
                    tmpPath = new GeneralPathX(piter.getWindingRule());
631
                }
632
                tmpPath.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
633
                break;
634

    
635
            case PathIterator.SEG_CLOSE:
636
                tmpPath.lineTo(first[0], first[1]);
637
                break;
638
            } // end switch
639

    
640
            piter.next();
641

    
642
        }
643
        if (tmpPath != null) {
644
            tmpSurface = createSurface(tmpPath, subType);
645
            multiSurface.addSurface(tmpSurface);
646
        }
647

    
648
        return multiSurface;
649

    
650
    }
651

    
652
    @Override
653
    public MultiPoint createMultiPoint(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
654
        if (subType != SUBTYPES.GEOM2D) {
655
            // FIXME Exception
656
            throw new UnsupportedOperationException();
657
        }
658
        MultiPoint multiPoint = (MultiPoint) create(TYPES.MULTIPOINT, subType);
659
        PathIterator piter = generalPathX.getPathIterator(null);
660
        Point tmpPoint;
661
        double[] coords = new double[6];
662
        int type;
663
        while (!piter.isDone()) {
664
            type = piter.currentSegment(coords);
665
            switch (type) {
666
            case PathIterator.SEG_MOVETO:
667
                tmpPoint = createPoint(coords[0], coords[1], subType);
668
                multiPoint.addPoint(tmpPoint);
669

    
670
            case PathIterator.SEG_LINETO:
671
                throw new IllegalArgumentException("The general have a SEG_LINETO.");
672

    
673
            case PathIterator.SEG_QUADTO:
674
                throw new IllegalArgumentException("The general have a SEG_QUADTO.");
675

    
676
            case PathIterator.SEG_CUBICTO:
677
                throw new IllegalArgumentException("The general have a SEG_CUBICTO.");
678

    
679
            case PathIterator.SEG_CLOSE:
680
                throw new IllegalArgumentException("The general have a SEG_CLOSE.");
681
            } // end switch
682

    
683
            piter.next();
684

    
685
        }
686
        return multiPoint;
687

    
688
    }
689

    
690
    @Override
691
    public int getGeometryOperationCode(String geomOpName) {
692
        if (geomOpName == null) {
693
            throw new IllegalArgumentException("geomOpName cannot be null.");
694
        }
695

    
696
        int index = geometryOperations.indexOf(geomOpName);
697
        if (index == -1) {
698
            geometryOperations.add(geomOpName);
699
            index = geometryOperations.indexOf(geomOpName);
700
        }
701
        return index;
702
    }
703

    
704
    @Override
705
    public List getGeometryOperationNames() {
706
        List operations = new ArrayList();
707
        for (int i = 0; i < operations.size(); i++) {
708
            operations.add(geometryOperations.get(i));
709
        }
710
        return operations;
711
    }
712

    
713
    @Override
714
    public double getFlatness() {
715
        return flatness;
716
    }
717

    
718
    @Override
719
    public void setFlatness(double flatness) {
720
        this.flatness = flatness;
721
    }
722

    
723
    @Override
724
    public Geometry createFrom(Object data) throws CreateGeometryException, GeometryException {
725
        if( data == null ) {
726
            throw new IllegalArgumentException("null data is not allowed");
727
        }
728
        if( data instanceof String ) {
729
            Geometry geom = GMLUtils.GML2Geometry((String) data);
730
            if( geom != null ) {
731
                return geom;
732
            }
733
            return this.createFrom((String)data);
734
        }
735
        if( data instanceof byte[] ) {
736
            return this.createFrom((byte[])data);
737
        }
738
        if( data instanceof com.vividsolutions.jts.geom.Geometry ) {
739
            return this.createFrom((com.vividsolutions.jts.geom.Geometry)data);
740
        }
741
        if( data instanceof Geometry ) {
742
            return ((Geometry)data).cloneGeometry();
743
        }
744
        throw new IllegalArgumentException("Type of data ("+data.getClass().getName()+") not supported.");
745
    }
746

    
747
    @Override
748
    public Geometry createFrom(String wkt, String srs) throws GeometryException {
749
        GeometryOperationContext context = new GeometryOperationContext();
750
        context.setAttribute("text", wkt);
751
        context.setAttribute("srs", srs);
752

    
753
        try {
754
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKT, context);
755
        } catch (Exception e) {
756
            throw new GeometryException(e);
757
        }
758
    }
759

    
760
    private int firstNonBlank(String s) {
761
        char ch;
762
        int i=0;
763
        while(i < s.length()) {
764
            if( !Character.isSpaceChar(ch = s.charAt(i++)) ) {
765
                return ch;
766
            }
767
        }
768
        return -1;
769
    } 
770
    
771
    @Override
772
    public Geometry createFrom(String wkt, IProjection srs) throws GeometryException {
773
        try {
774
            if( StringUtils.isBlank(wkt) ) {
775
                return null;
776
            }
777
            int ch = firstNonBlank(wkt);
778
            switch(ch) {
779
                case '0':
780
                case '1':
781
                    if( (wkt.length() % 2) == 0  ) {
782
                        // it starts with 0 or 1 and the length is even. Assume it is hexwkb.
783
                        return createFrom(Hex.decodeHex(wkt.toCharArray()), srs);
784
                    }
785
                    break;
786
                case '{':
787
                    try {
788
                        GeoJsonReader reader = new GeoJsonReader();
789
                        com.vividsolutions.jts.geom.Geometry geom_jts = reader.read(wkt);
790
                        return JTSUtils.createGeometry(srs, geom_jts);
791
                    } catch(Exception ex) {
792
                        LOGGER.debug("Can't parse as GeoJson");
793
                    }
794
                    break;
795
            }
796
            GeometryOperationContext context = new GeometryOperationContext();
797
            context.setAttribute("text", wkt);
798
            context.setAttribute("srs", srs);
799

    
800
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKT, context);
801
        } catch (Exception e) {
802
            throw new GeometryException(e);
803
        }
804
    }
805

    
806
    @Override
807
    public Geometry createFrom(String wkt) throws GeometryException {
808
        return this.createFrom(wkt, (IProjection)null);
809
    }
810

    
811
    public Geometry createFrom(IProjection proj, com.vividsolutions.jts.geom.Geometry geom) throws GeometryException {
812
        return JTSUtils.createGeometry(proj, geom);
813
    }
814

    
815
    @Override
816
    public Geometry createFromQuietly(String wkt) {
817
        try {
818
            return this.createFrom(wkt);
819
        } catch(Exception ex) {
820
            return null;
821
        }
822
    }
823
    
824
    @Override
825
    public Geometry createFrom(byte[] wkb) throws GeometryException {
826
        GeometryOperationContext context = new GeometryOperationContext();
827
        context.setAttribute("data", wkb);
828
        try {
829
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKB, context);
830
        } catch (GeometryOperationNotSupportedException e) {
831
            throw new GeometryException(e);
832
        } catch (GeometryOperationException e) {
833
            throw new GeometryException(e);
834
        }
835
    }
836

    
837
    @Override
838
    public Geometry createFrom(byte[] wkb, IProjection srs) throws GeometryException {
839
        GeometryOperationContext context = new GeometryOperationContext();
840
        context.setAttribute("data", wkb);
841
        context.setAttribute("srs", srs);
842
        try {
843
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKB, context);
844
        } catch (Exception e) {
845
            throw new GeometryException(e);
846
        }
847
    }
848

    
849
    @Override
850
    public IGeneralPathX createGeneralPath(int rule, PathIterator pathIterator) {
851
        if (pathIterator == null) {
852
            return new DefaultGeneralPathX(rule);
853
        }
854
        return new DefaultGeneralPathX(pathIterator, false, 0);
855
    }
856

    
857
    @Override
858
    public MultiPoint createMultiPoint(int subType) throws CreateGeometryException {
859
        return (MultiPoint) create(TYPES.MULTIPOINT, subType);
860
    }
861

    
862
    @Override
863
    public Line createLine(int subType) throws CreateGeometryException {
864
        return (Line) create(TYPES.CURVE, subType);
865
    }
866

    
867
    @Override
868
    public Curve createCurve(int subType) throws CreateGeometryException {
869
        return (Curve) create(TYPES.CURVE, subType);
870
    }
871

    
872
    @Override
873
    public MultiCurve createMultiCurve(int subType) throws CreateGeometryException {
874
        return (MultiCurve) create(TYPES.MULTICURVE, subType);
875
    }
876

    
877
    @Override
878
    public MultiLine createMultiLine(int subType) throws CreateGeometryException {
879
        return (MultiLine) create(TYPES.MULTILINE, subType);
880
    }
881

    
882
    @Override
883
    public MultiSurface createMultiSurface(int subType) throws CreateGeometryException {
884
        return (MultiSurface) create(TYPES.MULTISURFACE, subType);
885
    }
886

    
887
    @Override
888
    public MultiPolygon createMultiPolygon(int subType) throws CreateGeometryException {
889
        return (MultiPolygon) create(TYPES.MULTIPOLYGON, subType);
890
    }
891

    
892
    @Override
893
    public Polygon createPolygon(int subType) throws CreateGeometryException {
894
        return (Polygon) create(TYPES.SURFACE, subType);
895
    }
896

    
897
    @Override
898
    public Surface createSurface(int subType) throws CreateGeometryException {
899
        return (Surface) create(TYPES.SURFACE, subType);
900
    }
901

    
902
    @Override
903
    public SpatialIndex createDefaultMemorySpatialIndex() throws ServiceException {
904
        return this.createSpatialIndex(SpatialIndexFactoryJTSQuadtree.NAME, null);
905
    }
906

    
907
    @Override
908
    public SpatialIndex createSpatialIndex(String name, DynObject parameters) throws ServiceException {
909
        SpatialIndexFactory factory = this.getSpatialIndexFactory(name);
910
        if (factory == null) {
911
            throw new CantExistsService(name);
912
        }
913
        return (SpatialIndex) factory.create(parameters, this);
914
    }
915

    
916
    @Override
917
    public SpatialIndexFactory getSpatialIndexFactory(String name) {
918
        return (SpatialIndexFactory) this.spatialIndexFactories.get(name);
919
    }
920

    
921
    @Override
922
    public void addServiceFactory(ServiceFactory serviceFactory) {
923
        serviceFactory.initialize();
924
        this.spatialIndexFactories.put(serviceFactory.getName(), serviceFactory);
925
    }
926

    
927
    @Override
928
    public Service createService(DynObject serviceParameters) throws ServiceException {
929
        throw new UnsupportedOperationException("Not supported yet.");
930
    }
931

    
932
    @Override
933
    public DynObject createServiceParameters(String serviceName) throws ServiceException {
934
        SpatialIndexFactory factory = this.getSpatialIndexFactory(serviceName);
935
        if (factory == null) {
936
            throw new CantExistsService(serviceName);
937
        }
938
        return factory.createParameters();
939
    }
940

    
941
    @Override
942
    public Service getService(DynObject parameters) throws ServiceException {
943
        return this.createSpatialIndex((String) parameters.getDynValue("serviceName"), parameters);
944
    }
945

    
946
    @Override
947
    public MultiPrimitive createMultiPrimitive(GeometryType geometryType) throws CreateGeometryException {
948
        int type = geometryType.getType();
949
        int subtype = geometryType.getSubType();
950
        if(isSubtype(Geometry.TYPES.POINT, type)){
951
            return createMultiPoint(subtype);
952
        }
953
        if(isSubtype(Geometry.TYPES.CURVE, type)){
954
            return createMultiCurve(subtype);
955
        }
956
        if(isSubtype(Geometry.TYPES.SURFACE, type)){
957
            return createMultiSurface(subtype);
958
        }
959
        
960
        throw new CreateGeometryException(type, subtype, null);
961
    }
962

    
963
    public class CantExistsService extends ServiceException {
964

    
965
        public CantExistsService(String serviceName) {
966
            super("Can't existe service %(service).", "_Cant_existe_service_XserviceX", 100001);
967
            setValue("service", serviceName);
968
        }
969

    
970
    }
971

    
972
    @Override
973
    public InformationbuilderWithGeometrySupport createInformacionBuilder() {
974
        return new BaseInformationBuilderWithGeometrySupport();
975
    }
976

    
977
    @Override
978
    public boolean isSubtype(int geomTypeParent, int geomTypeChild) {
979
        // Esto es un implementacion patatera que habria que mejorar,
980
        // pero mejor aqui que esparcida por todas partes en donde se
981
        // necesite.
982
        if( geomTypeParent == geomTypeChild ) {
983
            return true;
984
        }
985
        if( geomTypeParent == Geometry.TYPES.GEOMETRY ) {
986
            return true;
987
        }
988
        switch(geomTypeParent) {
989
        case Geometry.TYPES.MULTICURVE:
990
            return geomTypeChild==Geometry.TYPES.MULTILINE ;
991
        case Geometry.TYPES.MULTISURFACE:
992
            return geomTypeChild==Geometry.TYPES.MULTIPOLYGON ;
993
        case Geometry.TYPES.MULTIPOINT:
994
            return geomTypeChild==Geometry.TYPES.MULTIPOINT ;
995

    
996
        case Geometry.TYPES.CURVE:
997
            return
998
                geomTypeChild == Geometry.TYPES.CURVE ||
999
                geomTypeChild == Geometry.TYPES.LINE ||
1000
                geomTypeChild == Geometry.TYPES.ARC ||
1001
                geomTypeChild == Geometry.TYPES.SPLINE ||
1002
                geomTypeChild == Geometry.TYPES.CIRCUMFERENCE ||
1003
                geomTypeChild == Geometry.TYPES.PERIELLIPSE
1004
                ;
1005
        case Geometry.TYPES.SURFACE:
1006
            return
1007
            geomTypeChild==Geometry.TYPES.SURFACE ||
1008
            geomTypeChild==Geometry.TYPES.POLYGON ||
1009
            geomTypeChild == Geometry.TYPES.CIRCLE ||
1010
            geomTypeChild == Geometry.TYPES.ELLIPSE ||
1011
            geomTypeChild == Geometry.TYPES.RING ||
1012
            geomTypeChild == Geometry.TYPES.FILLEDSPLINE ||
1013
            geomTypeChild == Geometry.TYPES.ELLIPTICARC
1014
            ;
1015
        case Geometry.TYPES.POINT:
1016
            return geomTypeChild==Geometry.TYPES.POINT ;
1017
        }
1018
        return false;
1019
    }
1020
    
1021
    @Override
1022
    public boolean canAggregate(int geomTypeParent, int geomTypeChild) {
1023
        
1024
        switch(geomTypeParent) {
1025
        case Geometry.TYPES.MULTICURVE:
1026
        case Geometry.TYPES.MULTILINE:
1027
            return isSubtype(Geometry.TYPES.CURVE, geomTypeChild);
1028
        case Geometry.TYPES.MULTISURFACE:
1029
        case Geometry.TYPES.MULTIPOLYGON:
1030
            return isSubtype(Geometry.TYPES.SURFACE, geomTypeChild);
1031
        case Geometry.TYPES.MULTIPOINT:
1032
            return isSubtype(Geometry.TYPES.POINT, geomTypeChild);
1033
        }
1034
        return false;
1035
    }
1036

    
1037
    @Override
1038
    public GeometryCoercionContext createGeometryCoercionContext() {
1039
        return new DefaultGeometryCoercionContext();
1040
    }
1041
    
1042
    
1043
    public static void main(String[] args) throws GeometryException, GeometryOperationNotSupportedException, GeometryOperationException {
1044
        String s;
1045
        new DefaultLibrariesInitializer().fullInitialize();
1046
//        s =  GeometryUtils.formatCoordinate("%-%d? %m' %s'' N", 39.89);
1047
//        System.out.println(s);
1048
//        s =  GeometryUtils.formatCoordinate("%-%d? %m' %.0s'' N", 39.89);
1049
//        System.out.println(s);
1050
//        s =  GeometryUtils.formatCoordinate("%+%d? %m' %.2s'' N (%4.4D)", 39.89);
1051
//        System.out.println(s);
1052
//        s =  GeometryUtils.formatCoordinate("%-%d? %m' N", -39.89);
1053
//        System.out.println(s);
1054
//        s =  GeometryUtils.formatCoordinate("%-%d? %m' N (%4.4D)", 39.89);
1055
//        System.out.println(s);
1056
        //Geometry g = GeometryUtils.createFrom("00000007d50000000100000007d20000002341258d57c2b73acf4150bf008a45b87241258d5eb2faa5364150befedb0f995841258d6aeb851eb84150befbeeb851ec41258d723d70a3d74150bef9d51eb85241258d7e428f5c294150bef677ae147b41258d9d147ae1484150beeea47ae14841258dbc28f5c28f4150bee72ae147ae41258dc7ae147ae14150bee468f5c28f41258dcc6b851eb84150bee31999999a41258dd1666666664150bee18b851eb841258dd8d70a3d714150bedf1d70a3d741258ddea8f5c28f4150bedc951eb85241258de3eb851eb84150bed99ccccccd41258dea3d70a3d74150bed6351eb85241258defbd70a3d74150bed3728f5c2941258df39999999a4150bed1751eb85241258df6c7ae147b4150bed01c28f5c341258df86b851eb84150becf1f5c28f641258dfa1999999a4150becd4666666641258dfb6147ae144150becbc51eb85241258dfd1999999a4150bec9a000000041258dfec28f5c294150bec753d70a3d41258e001eb851ec4150bec2f666666641258e047ae147ae4150beb73147ae1441258e054ccccccd4150beb3bc28f5c341258e054ccccccd4150beb2d70a3d7141258e05947ae1484150beb2047ae14841258e053d70a3d74150beb17333333341258e03a8f5c28f4150beb0e47ae14841258de69999999a4150beaca3d70a3d41258db10f5c28f64150bea46d70a3d741258dabdc28f5c34150bea3928f5c2941258da8dc28f5c34150bea300a3d70a41258da623d70a3d4150bea26147ae1441258da34ccccccd4150bea19d70a3d7");
1057
        //Geometry g = GeometryUtils.createFrom("MULTILINESTRING M ((745920.412801 4319733.74841197 -9999,745923.444481 4319733.242374 -9999,745930.962949 4319734.760282 -9999,745937.102608 4319738.899755 -9999,745941.242081 4319745.039415 -9999,745942.759989 4319752.557882 -9999,745941.242081 4319760.07635 -9999,745937.102608 4319766.216009 -9999,745930.962949 4319770.355482 -9999,745923.444481 4319771.87339 -9999,745915.926014 4319770.355482 -9999,745914.042603266 4319769.08565144 -9999,745911.2302267 4319767.2327453 -9999))");
1058
        Geometry g = GeometryUtils.createFrom("0105000060E66400000100000001020000400D00000016A75AD380C3264156FBE56F7D7A5041000000008087C3C07D0393E386C326413D0E834F7D7A5041000000008087C3C0BDA607ED95C32641D575A8B07D7A5041000000008087C3C029098934A2C32641FF9595B97E7A5041000000008087C3C0740AF27BAAC326417EC68542807A5041000000008087C3C039471D85ADC32641B456B423827A5041000000008087C3C0740AF27BAAC326411CEBE204847A5041000000008087C3C029098934A2C326416A17D38D857A5041000000008087C3C0BDA607ED95C326419337C096867A5041000000008087C3C07D0393E386C326412C9FE5F7867A5041000000008087C3C0CB811EDA77C326419337C096867A5041000000008087C3C06518D01574C3264130507B45867A5041000000008087C3C02646E0756EC32641894CE5CE857A5041000000008087C3C0");
1059
        String hexwkb = g.convertToHexWKB();
1060
        String hexewkb = g.convertToHexEWKB();
1061
        //byte[] b = g.convertToEWKB();
1062
        
1063
        System.out.println(hexwkb);
1064
        System.out.println(hexewkb);
1065
    }
1066
}