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 @ 45673

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

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

    
93
@SuppressWarnings("UseSpecificCatch")
94
public class DefaultGeometryManager implements GeometryManager {
95

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

    
105
    private final Map spatialIndexFactories = new HashMap();
106

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

    
114
    /**
115
     * Common operations are registered here. Type specific operations are
116
     * registered in the corresponding GeometryType instance
117
     */
118
    // private List commonOperations = new ArrayList();
119

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

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

    
142
    public DefaultGeometryManager() throws GeometryException {
143
        this(DEFAULT_TYPES_SIZE, DEFAULT_SUBTYPES_SIZE);
144
    }
145

    
146
    public DefaultGeometryManager(int initialTypesSize, int initialSubtypesSize) throws GeometryException {
147
        geometryTypes = new GeometryType[initialTypesSize][initialSubtypesSize];
148
        this.addServiceFactory(new SpatialIndexFactoryJTSQuadtree());
149
        this.addServiceFactory(new SpatialIndexFactoryJSIRTree());
150
    }
151

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

    
161
        int index = getGeometryOperationCode(geomOpName);
162

    
163
        geomType.setGeometryOperation(index, geomOp);
164

    
165
        return index;
166
    }
167

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

    
177
        int index = getGeometryOperationCode(geomOpName);
178

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

    
185
        return index;
186

    
187
    }
188

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

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

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

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

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

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

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

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

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

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

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

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

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

    
333
        return geomType;
334
    }
335

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
459
        throw new GeometryOperationNotSupportedException(opCode, geom.getGeometryType());
460
    }
461

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

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

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

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

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

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

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

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

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

    
570
            } // end switch
571

    
572
            piter.next();
573

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

    
580
        return multiCurve;
581

    
582
    }
583

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

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

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

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

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

    
638
            piter.next();
639

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

    
646
        return multiSurface;
647

    
648
    }
649

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

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

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

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

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

    
681
            piter.next();
682

    
683
        }
684
        return multiPoint;
685

    
686
    }
687

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

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

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

    
711
    @Override
712
    public double getFlatness() {
713
        return flatness;
714
    }
715

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

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

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

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

    
758
    @Override
759
    public Geometry createFrom(String wkt, IProjection srs) throws GeometryException {
760
        GeometryOperationContext context = new GeometryOperationContext();
761
        context.setAttribute("text", wkt);
762
        context.setAttribute("srs", srs);
763

    
764
        try {
765
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKT, context);
766
        } catch (Exception e) {
767
            throw new GeometryException(e);
768
        }
769
    }
770

    
771
    public Geometry createFrom(IProjection proj, com.vividsolutions.jts.geom.Geometry geom) throws GeometryException {
772
        return JTSUtils.createGeometry(proj, geom);
773
    }
774

    
775
    @Override
776
    public Geometry createFromQuietly(String wkt) {
777
        try {
778
            return this.createFrom(wkt);
779
        } catch(Exception ex) {
780
            return null;
781
        }
782
    }
783
    
784
    @Override
785
    public Geometry createFrom(String wkt) throws GeometryException {
786
        try {
787
            if( StringUtils.isBlank(wkt) ) {
788
                return null;
789
            }
790
            char ch = wkt.charAt(0);
791
            if( (ch == '0' || ch =='1') && (wkt.length() % 2) == 0  ) {
792
                // it starts with 0 or 1 and the length is even. Assume it is hexwkb.
793
                return createFrom(Hex.decodeHex(wkt.toCharArray()));
794
            }
795

    
796
            GeometryOperationContext context = new GeometryOperationContext();
797
            context.setAttribute("text", wkt);
798
            context.setAttribute("srs", null);
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(byte[] wkb) throws GeometryException {
808
        GeometryOperationContext context = new GeometryOperationContext();
809
        context.setAttribute("data", wkb);
810
        try {
811
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKB, context);
812
        } catch (GeometryOperationNotSupportedException e) {
813
            throw new GeometryException(e);
814
        } catch (GeometryOperationException e) {
815
            throw new GeometryException(e);
816
        }
817
    }
818

    
819
    @Override
820
    public Geometry createFrom(byte[] wkb, IProjection srs) throws GeometryException {
821
        GeometryOperationContext context = new GeometryOperationContext();
822
        context.setAttribute("data", wkb);
823
        context.setAttribute("srs", srs);
824
        try {
825
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKB, context);
826
        } catch (Exception e) {
827
            throw new GeometryException(e);
828
        }
829
    }
830

    
831
    @Override
832
    public IGeneralPathX createGeneralPath(int rule, PathIterator pathIterator) {
833
        if (pathIterator == null) {
834
            return new DefaultGeneralPathX(rule);
835
        }
836
        return new DefaultGeneralPathX(pathIterator, false, 0);
837
    }
838

    
839
    @Override
840
    public MultiPoint createMultiPoint(int subType) throws CreateGeometryException {
841
        return (MultiPoint) create(TYPES.MULTIPOINT, subType);
842
    }
843

    
844
    @Override
845
    public Line createLine(int subType) throws CreateGeometryException {
846
        return (Line) create(TYPES.CURVE, subType);
847
    }
848

    
849
    @Override
850
    public Curve createCurve(int subType) throws CreateGeometryException {
851
        return (Curve) create(TYPES.CURVE, subType);
852
    }
853

    
854
    @Override
855
    public MultiCurve createMultiCurve(int subType) throws CreateGeometryException {
856
        return (MultiCurve) create(TYPES.MULTICURVE, subType);
857
    }
858

    
859
    @Override
860
    public MultiLine createMultiLine(int subType) throws CreateGeometryException {
861
        return (MultiLine) create(TYPES.MULTILINE, subType);
862
    }
863

    
864
    @Override
865
    public MultiSurface createMultiSurface(int subType) throws CreateGeometryException {
866
        return (MultiSurface) create(TYPES.MULTISURFACE, subType);
867
    }
868

    
869
    @Override
870
    public MultiPolygon createMultiPolygon(int subType) throws CreateGeometryException {
871
        return (MultiPolygon) create(TYPES.MULTIPOLYGON, subType);
872
    }
873

    
874
    @Override
875
    public Polygon createPolygon(int subType) throws CreateGeometryException {
876
        return (Polygon) create(TYPES.SURFACE, subType);
877
    }
878

    
879
    @Override
880
    public Surface createSurface(int subType) throws CreateGeometryException {
881
        return (Surface) create(TYPES.SURFACE, subType);
882
    }
883

    
884
    @Override
885
    public SpatialIndex createDefaultMemorySpatialIndex() throws ServiceException {
886
        return this.createSpatialIndex(SpatialIndexFactoryJTSQuadtree.NAME, null);
887
    }
888

    
889
    @Override
890
    public SpatialIndex createSpatialIndex(String name, DynObject parameters) throws ServiceException {
891
        SpatialIndexFactory factory = this.getSpatialIndexFactory(name);
892
        if (factory == null) {
893
            throw new CantExistsService(name);
894
        }
895
        return (SpatialIndex) factory.create(parameters, this);
896
    }
897

    
898
    @Override
899
    public SpatialIndexFactory getSpatialIndexFactory(String name) {
900
        return (SpatialIndexFactory) this.spatialIndexFactories.get(name);
901
    }
902

    
903
    @Override
904
    public void addServiceFactory(ServiceFactory serviceFactory) {
905
        serviceFactory.initialize();
906
        this.spatialIndexFactories.put(serviceFactory.getName(), serviceFactory);
907
    }
908

    
909
    @Override
910
    public Service createService(DynObject serviceParameters) throws ServiceException {
911
        throw new UnsupportedOperationException("Not supported yet.");
912
    }
913

    
914
    @Override
915
    public DynObject createServiceParameters(String serviceName) throws ServiceException {
916
        SpatialIndexFactory factory = this.getSpatialIndexFactory(serviceName);
917
        if (factory == null) {
918
            throw new CantExistsService(serviceName);
919
        }
920
        return factory.createParameters();
921
    }
922

    
923
    @Override
924
    public Service getService(DynObject parameters) throws ServiceException {
925
        return this.createSpatialIndex((String) parameters.getDynValue("serviceName"), parameters);
926
    }
927

    
928
    public class CantExistsService extends ServiceException {
929

    
930
        public CantExistsService(String serviceName) {
931
            super("Can't existe service %(service).", "_Cant_existe_service_XserviceX", 100001);
932
            setValue("service", serviceName);
933
        }
934

    
935
    }
936

    
937
    @Override
938
    public InformationbuilderWithGeometrySupport createInformacionBuilder() {
939
        return new BaseInformationBuilderWithGeometrySupport();
940
    }
941

    
942
    @Override
943
    public boolean isSubtype(int geomTypeParent, int geomTypeChild) {
944
        // Esto es un implementacion patatera que habria que mejorar,
945
        // pero mejor aqui que esparcida por todas partes en donde se
946
        // necesite.
947
        if( geomTypeParent == geomTypeChild ) {
948
            return true;
949
        }
950
        if( geomTypeParent == Geometry.TYPES.GEOMETRY ) {
951
            return true;
952
        }
953
        switch(geomTypeParent) {
954
        case Geometry.TYPES.MULTICURVE:
955
            return geomTypeChild==Geometry.TYPES.MULTILINE ;
956
        case Geometry.TYPES.MULTISURFACE:
957
            return geomTypeChild==Geometry.TYPES.MULTIPOLYGON ;
958
        case Geometry.TYPES.MULTIPOINT:
959
            return geomTypeChild==Geometry.TYPES.MULTIPOINT ;
960

    
961
        case Geometry.TYPES.CURVE:
962
            return
963
                geomTypeChild == Geometry.TYPES.CURVE ||
964
                geomTypeChild == Geometry.TYPES.LINE ||
965
                geomTypeChild == Geometry.TYPES.ARC ||
966
                geomTypeChild == Geometry.TYPES.SPLINE ||
967
                geomTypeChild == Geometry.TYPES.CIRCUMFERENCE ||
968
                geomTypeChild == Geometry.TYPES.PERIELLIPSE
969
                ;
970
        case Geometry.TYPES.SURFACE:
971
            return
972
            geomTypeChild==Geometry.TYPES.SURFACE ||
973
            geomTypeChild==Geometry.TYPES.POLYGON ||
974
            geomTypeChild == Geometry.TYPES.CIRCLE ||
975
            geomTypeChild == Geometry.TYPES.ELLIPSE ||
976
            geomTypeChild == Geometry.TYPES.RING ||
977
            geomTypeChild == Geometry.TYPES.FILLEDSPLINE ||
978
            geomTypeChild == Geometry.TYPES.ELLIPTICARC
979
            ;
980
        case Geometry.TYPES.POINT:
981
            return geomTypeChild==Geometry.TYPES.POINT ;
982
        }
983
        return false;
984
    }
985
    
986
    @Override
987
    public boolean canAggregate(int geomTypeParent, int geomTypeChild) {
988
        
989
        switch(geomTypeParent) {
990
        case Geometry.TYPES.MULTICURVE:
991
        case Geometry.TYPES.MULTILINE:
992
            return isSubtype(Geometry.TYPES.CURVE, geomTypeChild);
993
        case Geometry.TYPES.MULTISURFACE:
994
        case Geometry.TYPES.MULTIPOLYGON:
995
            return isSubtype(Geometry.TYPES.SURFACE, geomTypeChild);
996
        case Geometry.TYPES.MULTIPOINT:
997
            return isSubtype(Geometry.TYPES.POINT, geomTypeChild);
998
        }
999
        return false;
1000
    }
1001

    
1002
    @Override
1003
    public GeometryCoercionContext createGeometryCoercionContext() {
1004
        return new DefaultGeometryCoercionContext();
1005
    }
1006
    
1007
}