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

History | View | Annotate | Download (36.8 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.GeometryException;
40
import org.gvsig.fmap.geom.GeometryLocator;
41
import org.gvsig.fmap.geom.GeometryManager;
42
import org.gvsig.fmap.geom.InformationbuilderWithGeometrySupport;
43
import org.gvsig.fmap.geom.SpatialIndex;
44
import org.gvsig.fmap.geom.SpatialIndexFactory;
45
import org.gvsig.fmap.geom.aggregate.MultiCurve;
46
import org.gvsig.fmap.geom.aggregate.MultiLine;
47
import org.gvsig.fmap.geom.aggregate.MultiPoint;
48
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
49
import org.gvsig.fmap.geom.aggregate.MultiSurface;
50
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
51
import org.gvsig.fmap.geom.exception.CreateGeometryException;
52
import org.gvsig.fmap.geom.jts.gputils.DefaultGeneralPathX;
53
import org.gvsig.fmap.geom.jts.primitive.DefaultNullGeometry;
54
import org.gvsig.fmap.geom.jts.primitive.Envelope2D;
55
import org.gvsig.fmap.geom.jts.primitive.Envelope3D;
56
import org.gvsig.fmap.geom.jts.spatialindex.SpatialIndexFactoryJSIRTree;
57
import org.gvsig.fmap.geom.jts.spatialindex.SpatialIndexFactoryJTSQuadtree;
58
import org.gvsig.fmap.geom.jts.util.GMLUtils;
59
import org.gvsig.fmap.geom.jts.util.JTSUtils;
60
import org.gvsig.fmap.geom.operation.GeometryOperation;
61
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
62
import org.gvsig.fmap.geom.operation.GeometryOperationException;
63
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
64
import org.gvsig.fmap.geom.primitive.Curve;
65
import org.gvsig.fmap.geom.primitive.Envelope;
66
import org.gvsig.fmap.geom.primitive.GeneralPathX;
67
import org.gvsig.fmap.geom.primitive.IGeneralPathX;
68
import org.gvsig.fmap.geom.primitive.Line;
69
import org.gvsig.fmap.geom.primitive.NullGeometry;
70
import org.gvsig.fmap.geom.primitive.Point;
71
import org.gvsig.fmap.geom.primitive.Polygon;
72
import org.gvsig.fmap.geom.primitive.Surface;
73
import org.gvsig.fmap.geom.type.GeometryType;
74
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
75
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
76
import org.gvsig.tools.dynobject.DynObject;
77
import org.gvsig.tools.service.Service;
78
import org.gvsig.tools.service.ServiceException;
79
import org.gvsig.tools.service.spi.ServiceFactory;
80
import org.slf4j.Logger;
81
import org.slf4j.LoggerFactory;
82

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

    
91
@SuppressWarnings("UseSpecificCatch")
92
public class DefaultGeometryManager implements GeometryManager {
93

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

    
103
    private final Map spatialIndexFactories = new HashMap();
104

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

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

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

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

    
140
    public DefaultGeometryManager() throws GeometryException {
141
        this(DEFAULT_TYPES_SIZE, DEFAULT_SUBTYPES_SIZE);
142
    }
143

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

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

    
159
        int index = getGeometryOperationCode(geomOpName);
160

    
161
        geomType.setGeometryOperation(index, geomOp);
162

    
163
        return index;
164
    }
165

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

    
175
        int index = getGeometryOperationCode(geomOpName);
176

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

    
183
        return index;
184

    
185
    }
186

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

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

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

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

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

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

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

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

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

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

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

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

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

    
331
        return geomType;
332
    }
333

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
457
        throw new GeometryOperationNotSupportedException(opCode, geom.getGeometryType());
458
    }
459

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

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

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

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

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

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

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

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

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

    
568
            } // end switch
569

    
570
            piter.next();
571

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

    
578
        return multiCurve;
579

    
580
    }
581

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

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

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

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

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

    
636
            piter.next();
637

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

    
644
        return multiSurface;
645

    
646
    }
647

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

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

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

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

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

    
679
            piter.next();
680

    
681
        }
682
        return multiPoint;
683

    
684
    }
685

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

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

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

    
709
    @Override
710
    public double getFlatness() {
711
        return flatness;
712
    }
713

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

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

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

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

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

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

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

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

    
794
            GeometryOperationContext context = new GeometryOperationContext();
795
            context.setAttribute("text", wkt);
796
            context.setAttribute("srs", null);
797

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

    
804
    @Override
805
    public Geometry createFrom(byte[] wkb) throws GeometryException {
806
        GeometryOperationContext context = new GeometryOperationContext();
807
        context.setAttribute("data", wkb);
808
        try {
809
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKB, context);
810
        } catch (GeometryOperationNotSupportedException e) {
811
            throw new GeometryException(e);
812
        } catch (GeometryOperationException e) {
813
            throw new GeometryException(e);
814
        }
815
    }
816

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
926
    public class CantExistsService extends ServiceException {
927

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

    
933
    }
934

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

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

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