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

History | View | Annotate | Download (36.5 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.cresques.cts.IProjection;
34

    
35
import org.slf4j.Logger;
36
import org.slf4j.LoggerFactory;
37

    
38
import org.gvsig.fmap.geom.Geometry;
39
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
40
import org.gvsig.fmap.geom.Geometry.TYPES;
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.InformationbuilderWithGeometrySupport;
45
import org.gvsig.fmap.geom.SpatialIndex;
46
import org.gvsig.fmap.geom.SpatialIndexFactory;
47
import org.gvsig.fmap.geom.aggregate.MultiCurve;
48
import org.gvsig.fmap.geom.aggregate.MultiLine;
49
import org.gvsig.fmap.geom.aggregate.MultiPoint;
50
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
51
import org.gvsig.fmap.geom.aggregate.MultiSurface;
52
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
53
import org.gvsig.fmap.geom.exception.CreateGeometryException;
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.apache.commons.codec.binary.Hex;
83
import org.apache.commons.lang3.StringUtils;
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
    private double flatness = 0.8;
98

    
99
    private final Map spatialIndexFactories = new HashMap();
100

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

    
108
    /**
109
     * Common operations are registered here. Type specific operations are
110
     * registered in the corresponding GeometryType instance
111
     */
112
    // private List commonOperations = new ArrayList();
113

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

    
123
    /**
124
     * Matrix of geometry types by type (row) and subtype (column). This matrix
125
     * will contain null values in the cells where a GeometryType hasn't been
126
     * registered.
127
     */
128
    private GeometryType[][] geometryTypes;
129

    
130
    // Initially create a matrix of 26 x 6, which are the current default
131
    // types and subtypes. If another type or subtype is registered, the
132
    // matrix will grow as needed
133
    private static final int DEFAULT_TYPES_SIZE = 26;
134
    private static final int DEFAULT_SUBTYPES_SIZE = 6;
135

    
136
    public DefaultGeometryManager() throws GeometryException {
137
        this(DEFAULT_TYPES_SIZE, DEFAULT_SUBTYPES_SIZE);
138
    }
139

    
140
    public DefaultGeometryManager(int initialTypesSize, int initialSubtypesSize) throws GeometryException {
141
        geometryTypes = new GeometryType[initialTypesSize][initialSubtypesSize];
142
        this.addServiceFactory(new SpatialIndexFactoryJTSQuadtree());
143
        this.addServiceFactory(new SpatialIndexFactoryJSIRTree());
144
    }
145

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

    
155
        int index = getGeometryOperationCode(geomOpName);
156

    
157
        geomType.setGeometryOperation(index, geomOp);
158

    
159
        return index;
160
    }
161

    
162
    @Override
163
    public int registerGeometryOperation(String geomOpName, GeometryOperation geomOp) {
164
        if (geomOpName == null) {
165
            throw new IllegalArgumentException("geomOpName cannot be null.");
166
        }
167
        if (geomOp == null) {
168
            throw new IllegalArgumentException("geomOp cannot be null.");
169
        }
170

    
171
        int index = getGeometryOperationCode(geomOpName);
172

    
173
        Iterator it = geometryTypeName.values().iterator();
174
        while (it.hasNext()) {
175
            GeometryType geometryType = (GeometryType) it.next();
176
            registerGeometryOperation(geomOpName, geomOp, geometryType);
177
        }
178

    
179
        return index;
180

    
181
    }
182

    
183
    @SuppressWarnings("override")
184
    public int registerGeometryOperation(String geomOpName, GeometryOperation geomOp, int type, int subType)
185
        throws GeometryTypeNotSupportedException, GeometryTypeNotValidException {
186
        GeometryType geometryType = getGeometryType(type, subType);
187
        return registerGeometryOperation(geomOpName, geomOp, geometryType);
188
    }
189

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

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

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

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

    
242
    @Override
243
    public GeometryType registerGeometryType(Class geomClass, String name, int type, int subType) {
244
        return registerGeometryType(geomClass, name, type, subType, new int[0], new int[0]);
245
    }
246

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

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

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

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

    
312
        if (!Geometry.class.isAssignableFrom(geomClass)) {
313
            throw new IllegalArgumentException(geomClass.getName() + " must implement the Geometry interface");
314
        }
315

    
316
        // Check if it is registered
317
        GeometryType geomType = null;
318
        if (type >= geometryTypes.length || subType >= geometryTypes[0].length
319
            || (geomType = geometryTypes[type][subType]) == null) {
320
            geomType = new DefaultGeometryType(geomClass, name, type, subType, superTypes, superSubTypes);
321
            registerGeometryType(geomType);
322
        }
323

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

    
326
        return geomType;
327
    }
328

    
329
    @Override
330
    public void registerGeometryType(GeometryType geometryType) {
331
        if (geometryType.getType() >= geometryTypes.length || geometryType.getSubType() >= geometryTypes[0].length) {
332

    
333
            // Recreate the geometry type matrix if the types
334
            // or subtypes don't fit
335
            int newTypesSize =
336
                geometryType.getType() < geometryTypes.length ? geometryTypes.length : geometryType.getType() + 1;
337
            int newSubTypesSize =
338
                geometryType.getSubType() < geometryTypes[0].length ? geometryTypes[0].length : geometryType
339
                    .getSubType() + 1;
340
            GeometryType[][] newMatrix = new GeometryType[newTypesSize][newSubTypesSize];
341

    
342
            for (int i = 0; i < geometryTypes.length; i++) {
343
                System.arraycopy(geometryTypes[i], 0, newMatrix[i], 0, geometryTypes[i].length);
344
            }
345
            geometryTypes = newMatrix;
346
        }
347

    
348
        geometryTypes[geometryType.getType()][geometryType.getSubType()] = geometryType;
349
        geometryTypeName.put(geometryType.getName(), geometryType);
350
    }
351

    
352
    @Override
353
    public GeometryType registerGeometryType(Class geomClass, int type, int subType) {
354
        return registerGeometryType(geomClass, null, type, subType);
355
    }
356

    
357
    @Override
358
    public GeometryType getGeometryType(int type, int subType) throws GeometryTypeNotSupportedException,
359
        GeometryTypeNotValidException {
360
        if (type >= geometryTypes.length || subType >= geometryTypes[0].length) {
361
            throw new GeometryTypeNotValidException(type, subType);
362
        }
363
        GeometryType gType = geometryTypes[type][subType];
364
        if (gType == null) {
365
            throw new GeometryTypeNotSupportedException(type, subType);
366
        }
367
        return gType;
368
    }
369

    
370
    @Override
371
    public Geometry create(GeometryType geomType) throws CreateGeometryException {
372
        return geomType.create();
373
    }
374

    
375
    @Override
376
    public Geometry create(String name) throws CreateGeometryException {
377
        if (!geometryTypeName.containsKey(name)) {
378
            throw new IllegalArgumentException(name + " has not been registered yet.");
379
        }
380
        return ((GeometryType) geometryTypeName.get(name)).create();
381
    }
382

    
383
    @Override
384
    public Geometry create(int type, int subType) throws CreateGeometryException {
385
        try {
386
            return getGeometryType(type, subType).create();
387
        } catch (GeometryException e) {
388
            throw new CreateGeometryException(type, subType, e);
389
        }
390
    }
391

    
392
    @Override
393
    public Curve createCurve(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
394
        Curve curve = (Curve) create(TYPES.CURVE, subType);
395
        curve.setGeneralPath(generalPathX);
396
        return curve;
397
    }
398

    
399
    @Override
400
    public NullGeometry createNullGeometry(int subType) throws CreateGeometryException {
401
        NullGeometry nullGeom = (NullGeometry) create(TYPES.NULL, subType);
402
        return nullGeom;
403
    }
404

    
405
    @Override
406
    public Point createPoint(double x, double y, int subType) throws CreateGeometryException {
407
        Point point = (Point) create(TYPES.POINT, subType);
408
        point.setX(x);
409
        point.setY(y);
410
        return point;
411
    }
412

    
413
    @Override
414
    public Surface createSurface(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
415
        Surface surface = (Surface) create(TYPES.SURFACE, subType);
416
        surface.setGeneralPath(generalPathX);
417
        return surface;
418
    }
419

    
420
    @Override
421
    public GeometryOperation getGeometryOperation(int opCode, int type, int subType)
422
        throws GeometryTypeNotSupportedException, GeometryOperationNotSupportedException, GeometryTypeNotValidException {
423
        GeometryType geometryType = getGeometryType(type, subType);
424
        return geometryType.getGeometryOperation(opCode);
425
    }
426

    
427
    @Override
428
    public GeometryOperation getGeometryOperation(int opCode) throws GeometryOperationNotSupportedException {
429
        if (opCode < 0) {
430
            throw new GeometryOperationNotSupportedException(opCode);
431
        }
432
        GeometryType type = (GeometryType) geometryTypeName.get(DefaultNullGeometry.class.getName());
433
        if (type == null) {
434
            throw new GeometryOperationNotSupportedException(opCode);
435
        }
436
        return type.getGeometryOperation(opCode);
437
    }
438

    
439
    @Override
440
    public Object invokeOperation(int opCode, Geometry geom, GeometryOperationContext ctx)
441
        throws GeometryOperationNotSupportedException, GeometryOperationException {
442
        GeometryOperation geomOp = geom.getGeometryType().getGeometryOperation(opCode);
443

    
444
        if (geomOp != null) {
445
            return geomOp.invoke(geom, ctx);
446
        }
447

    
448
        throw new GeometryOperationNotSupportedException(opCode, geom.getGeometryType());
449
    }
450

    
451
    @Override
452
    public Object invokeOperation(String geomOpName, Geometry geom, GeometryOperationContext ctx)
453
        throws GeometryOperationNotSupportedException, GeometryOperationException {
454
        int index = geometryOperations.indexOf(geomOpName);
455
        if (index == -1) {
456
            throw new GeometryOperationNotSupportedException(-1);
457
        }
458
        return invokeOperation(index, geom, ctx);
459
    }
460

    
461
    @Override
462
    public Object invokeOperation(String geomOpName, GeometryOperationContext ctx)
463
        throws GeometryOperationNotSupportedException, GeometryOperationException {
464
        int index = geometryOperations.indexOf(geomOpName);
465
        GeometryOperation geomOp = getGeometryOperation(index);
466
        return geomOp.invoke(null, ctx);
467
    }
468

    
469
    @Override
470
    public Envelope createEnvelope(int subType) {
471
        // TODO: register the envelopes!!!
472
        switch (subType) {
473
        case SUBTYPES.GEOM3D:
474
            return new Envelope3D();
475
        default:
476
            return new Envelope2D();
477
        }
478
    }
479

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

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

    
531
            case PathIterator.SEG_LINETO:
532
                if (tmpPath == null) {
533
                    System.arraycopy(coords, 0, first, 0, 2);
534
                    tmpPath = new GeneralPathX(piter.getWindingRule());
535
                }
536
                tmpPath.lineTo(coords[0], coords[1]);
537
                break;
538

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

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

    
555
            case PathIterator.SEG_CLOSE:
556
                tmpPath.lineTo(first[0], first[1]);
557
                break;
558

    
559
            } // end switch
560

    
561
            piter.next();
562

    
563
        }
564
        if (tmpPath != null) {
565
            tmpCurve = createCurve(tmpPath, subType);
566
            multiCurve.addCurve(tmpCurve);
567
        }
568

    
569
        return multiCurve;
570

    
571
    }
572

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

    
598
            case PathIterator.SEG_LINETO:
599
                if (tmpPath == null) {
600
                    System.arraycopy(coords, 0, first, 0, 2);
601
                    tmpPath = new GeneralPathX(piter.getWindingRule());
602
                }
603
                tmpPath.lineTo(coords[0], coords[1]);
604
                break;
605

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

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

    
622
            case PathIterator.SEG_CLOSE:
623
                tmpPath.lineTo(first[0], first[1]);
624
                break;
625
            } // end switch
626

    
627
            piter.next();
628

    
629
        }
630
        if (tmpPath != null) {
631
            tmpSurface = createSurface(tmpPath, subType);
632
            multiSurface.addSurface(tmpSurface);
633
        }
634

    
635
        return multiSurface;
636

    
637
    }
638

    
639
    @Override
640
    public MultiPoint createMultiPoint(GeneralPathX generalPathX, int subType) throws CreateGeometryException {
641
        if (subType != SUBTYPES.GEOM2D) {
642
            // FIXME Exception
643
            throw new UnsupportedOperationException();
644
        }
645
        MultiPoint multiPoint = (MultiPoint) create(TYPES.MULTIPOINT, subType);
646
        PathIterator piter = generalPathX.getPathIterator(null);
647
        Point tmpPoint;
648
        double[] coords = new double[6];
649
        int type;
650
        while (!piter.isDone()) {
651
            type = piter.currentSegment(coords);
652
            switch (type) {
653
            case PathIterator.SEG_MOVETO:
654
                tmpPoint = createPoint(coords[0], coords[1], subType);
655
                multiPoint.addPoint(tmpPoint);
656

    
657
            case PathIterator.SEG_LINETO:
658
                throw new IllegalArgumentException("The general have a SEG_LINETO.");
659

    
660
            case PathIterator.SEG_QUADTO:
661
                throw new IllegalArgumentException("The general have a SEG_QUADTO.");
662

    
663
            case PathIterator.SEG_CUBICTO:
664
                throw new IllegalArgumentException("The general have a SEG_CUBICTO.");
665

    
666
            case PathIterator.SEG_CLOSE:
667
                throw new IllegalArgumentException("The general have a SEG_CLOSE.");
668
            } // end switch
669

    
670
            piter.next();
671

    
672
        }
673
        return multiPoint;
674

    
675
    }
676

    
677
    @Override
678
    public int getGeometryOperationCode(String geomOpName) {
679
        if (geomOpName == null) {
680
            throw new IllegalArgumentException("geomOpName cannot be null.");
681
        }
682

    
683
        int index = geometryOperations.indexOf(geomOpName);
684
        if (index == -1) {
685
            geometryOperations.add(geomOpName);
686
            index = geometryOperations.indexOf(geomOpName);
687
        }
688
        return index;
689
    }
690

    
691
    @Override
692
    public List getGeometryOperationNames() {
693
        List operations = new ArrayList();
694
        for (int i = 0; i < operations.size(); i++) {
695
            operations.add(geometryOperations.get(i));
696
        }
697
        return operations;
698
    }
699

    
700
    @Override
701
    public double getFlatness() {
702
        return flatness;
703
    }
704

    
705
    @Override
706
    public void setFlatness(double flatness) {
707
        this.flatness = flatness;
708
    }
709

    
710
    @Override
711
    public Geometry createFrom(Object data) throws CreateGeometryException, GeometryException {
712
        if( data == null ) {
713
            throw new IllegalArgumentException("null data is not allowed");
714
        }
715
        if( data instanceof String ) {
716
            Geometry geom = GMLUtils.GML2Geometry((String) data);
717
            if( geom != null ) {
718
                return geom;
719
            }
720
            return this.createFrom((String)data);
721
        }
722
        if( data instanceof byte[] ) {
723
            return this.createFrom((byte[])data);
724
        }
725
        if( data instanceof com.vividsolutions.jts.geom.Geometry ) {
726
            return this.createFrom((com.vividsolutions.jts.geom.Geometry)data);
727
        }
728
        if( data instanceof Geometry ) {
729
            return ((Geometry)data).cloneGeometry();
730
        }
731
        throw new IllegalArgumentException("Type of data ("+data.getClass().getName()+") not supported.");
732
    }
733

    
734
    @Override
735
    public Geometry createFrom(String wkt, String srs) throws GeometryException {
736
        GeometryOperationContext context = new GeometryOperationContext();
737
        context.setAttribute("text", wkt);
738
        context.setAttribute("srs", srs);
739

    
740
        try {
741
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKT, context);
742
        } catch (Exception e) {
743
            throw new GeometryException(e);
744
        }
745
    }
746

    
747
    @Override
748
    public Geometry createFrom(String wkt, IProjection 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
    public Geometry createFrom(IProjection proj, com.vividsolutions.jts.geom.Geometry geom) throws GeometryException {
761
        return JTSUtils.createGeometry(proj, geom);
762
    }
763

    
764
    @Override
765
    public Geometry createFromQuietly(String wkt) {
766
        try {
767
            return this.createFrom(wkt);
768
        } catch(Exception ex) {
769
            return null;
770
        }
771
    }
772
    
773
    @Override
774
    public Geometry createFrom(String wkt) throws GeometryException {
775
        try {
776
            if( StringUtils.isBlank(wkt) ) {
777
                return null;
778
            }
779
            char ch = wkt.charAt(0);
780
            if( (ch == '0' || ch =='1') && (wkt.length() % 2) == 0  ) {
781
                // it starts with 0 or 1 and the length is even. Assume it is hexwkb.
782
                return createFrom(Hex.decodeHex(wkt.toCharArray()));
783
            }
784

    
785
            GeometryOperationContext context = new GeometryOperationContext();
786
            context.setAttribute("text", wkt);
787
            context.setAttribute("srs", null);
788

    
789
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKT, context);
790
        } catch (Exception e) {
791
            throw new GeometryException(e);
792
        }
793
    }
794

    
795
    @Override
796
    public Geometry createFrom(byte[] wkb) throws GeometryException {
797
        GeometryOperationContext context = new GeometryOperationContext();
798
        context.setAttribute("data", wkb);
799
        try {
800
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKB, context);
801
        } catch (GeometryOperationNotSupportedException e) {
802
            throw new GeometryException(e);
803
        } catch (GeometryOperationException e) {
804
            throw new GeometryException(e);
805
        }
806
    }
807

    
808
    @Override
809
    public Geometry createFrom(byte[] wkb, IProjection srs) throws GeometryException {
810
        GeometryOperationContext context = new GeometryOperationContext();
811
        context.setAttribute("data", wkb);
812
        context.setAttribute("srs", srs);
813
        try {
814
            return (Geometry) this.invokeOperation(OPERATIONS.FROMWKB, context);
815
        } catch (Exception e) {
816
            throw new GeometryException(e);
817
        }
818
    }
819

    
820
    @Override
821
    public IGeneralPathX createGeneralPath(int rule, PathIterator pathIterator) {
822
        if (pathIterator == null) {
823
            return new DefaultGeneralPathX(rule);
824
        }
825
        return new DefaultGeneralPathX(pathIterator, false, 0);
826
    }
827

    
828
    @Override
829
    public MultiPoint createMultiPoint(int subType) throws CreateGeometryException {
830
        return (MultiPoint) create(TYPES.MULTIPOINT, subType);
831
    }
832

    
833
    @Override
834
    public Line createLine(int subType) throws CreateGeometryException {
835
        return (Line) create(TYPES.CURVE, subType);
836
    }
837

    
838
    @Override
839
    public Curve createCurve(int subType) throws CreateGeometryException {
840
        return (Curve) create(TYPES.CURVE, subType);
841
    }
842

    
843
    @Override
844
    public MultiCurve createMultiCurve(int subType) throws CreateGeometryException {
845
        return (MultiCurve) create(TYPES.MULTICURVE, subType);
846
    }
847

    
848
    @Override
849
    public MultiLine createMultiLine(int subType) throws CreateGeometryException {
850
        return (MultiLine) create(TYPES.MULTILINE, subType);
851
    }
852

    
853
    @Override
854
    public MultiSurface createMultiSurface(int subType) throws CreateGeometryException {
855
        return (MultiSurface) create(TYPES.MULTISURFACE, subType);
856
    }
857

    
858
    @Override
859
    public MultiPolygon createMultiPolygon(int subType) throws CreateGeometryException {
860
        return (MultiPolygon) create(TYPES.MULTIPOLYGON, subType);
861
    }
862

    
863
    @Override
864
    public Polygon createPolygon(int subType) throws CreateGeometryException {
865
        return (Polygon) create(TYPES.SURFACE, subType);
866
    }
867

    
868
    @Override
869
    public Surface createSurface(int subType) throws CreateGeometryException {
870
        return (Surface) create(TYPES.SURFACE, subType);
871
    }
872

    
873
    @Override
874
    public SpatialIndex createDefaultMemorySpatialIndex() throws ServiceException {
875
        return this.createSpatialIndex(SpatialIndexFactoryJTSQuadtree.NAME, null);
876
    }
877

    
878
    @Override
879
    public SpatialIndex createSpatialIndex(String name, DynObject parameters) throws ServiceException {
880
        SpatialIndexFactory factory = this.getSpatialIndexFactory(name);
881
        if (factory == null) {
882
            throw new CantExistsService(name);
883
        }
884
        return (SpatialIndex) factory.create(parameters, this);
885
    }
886

    
887
    @Override
888
    public SpatialIndexFactory getSpatialIndexFactory(String name) {
889
        return (SpatialIndexFactory) this.spatialIndexFactories.get(name);
890
    }
891

    
892
    @Override
893
    public void addServiceFactory(ServiceFactory serviceFactory) {
894
        serviceFactory.initialize();
895
        this.spatialIndexFactories.put(serviceFactory.getName(), serviceFactory);
896
    }
897

    
898
    @Override
899
    public Service createService(DynObject serviceParameters) throws ServiceException {
900
        throw new UnsupportedOperationException("Not supported yet.");
901
    }
902

    
903
    @Override
904
    public DynObject createServiceParameters(String serviceName) throws ServiceException {
905
        SpatialIndexFactory factory = this.getSpatialIndexFactory(serviceName);
906
        if (factory == null) {
907
            throw new CantExistsService(serviceName);
908
        }
909
        return factory.createParameters();
910
    }
911

    
912
    @Override
913
    public Service getService(DynObject parameters) throws ServiceException {
914
        return this.createSpatialIndex((String) parameters.getDynValue("serviceName"), parameters);
915
    }
916

    
917
    public class CantExistsService extends ServiceException {
918

    
919
        public CantExistsService(String serviceName) {
920
            super("Can't existe service %(service).", "_Cant_existe_service_XserviceX", 100001);
921
            setValue("service", serviceName);
922
        }
923

    
924
    }
925

    
926
    @Override
927
    public InformationbuilderWithGeometrySupport createInformacionBuilder() {
928
        return new BaseInformationBuilderWithGeometrySupport();
929
    }
930

    
931
    @Override
932
    public boolean isSubtype(int geomTypeParent, int geomTypeChild) {
933
        // Esto es un implementacion patatera que habria que mejorar,
934
        // pero mejor aqui que esparcida por todas partes en donde se
935
        // necesite.
936
        if( geomTypeParent == geomTypeChild ) {
937
            return true;
938
        }
939
        if( geomTypeParent == Geometry.TYPES.GEOMETRY ) {
940
            return true;
941
        }
942
        switch(geomTypeParent) {
943
        case Geometry.TYPES.MULTICURVE:
944
            return geomTypeChild==Geometry.TYPES.MULTILINE ;
945
        case Geometry.TYPES.MULTISURFACE:
946
            return geomTypeChild==Geometry.TYPES.MULTIPOLYGON ;
947
        case Geometry.TYPES.MULTIPOINT:
948
            return geomTypeChild==Geometry.TYPES.MULTIPOINT ;
949

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