Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialUtils.java @ 14291

History | View | Annotate | Download (66.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 Prodevelop and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *   Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *   +34 963862235
28
 *   gvsig@gva.es
29
 *   www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   Prodevelop Integraci?n de Tecnolog?as SL
34
 *   Conde Salvatierra de ?lava , 34-10
35
 *   46004 Valencia
36
 *   Spain
37
 *
38
 *   +34 963 510 612
39
 *   +34 963 510 968
40
 *   gis@prodevelop.es
41
 *   http://www.prodevelop.es
42
 */
43
package es.prodevelop.cit.gvsig.fmap.drivers.jdbc.oracle;
44

    
45
import java.awt.geom.PathIterator;
46
import java.awt.geom.Point2D;
47
import java.io.BufferedReader;
48
import java.io.File;
49
import java.io.FileReader;
50
import java.lang.reflect.Array;
51
import java.net.URL;
52
import java.sql.Connection;
53
import java.sql.PreparedStatement;
54
import java.sql.ResultSet;
55
import java.sql.SQLException;
56
import java.text.DecimalFormat;
57
import java.text.DecimalFormatSymbols;
58
import java.util.ArrayList;
59
import java.util.Random;
60

    
61
import oracle.sql.ARRAY;
62
import oracle.sql.Datum;
63
import oracle.sql.NUMBER;
64
import oracle.sql.STRUCT;
65
import oracle.sql.StructDescriptor;
66

    
67
import org.apache.log4j.Logger;
68

    
69
import com.iver.cit.gvsig.fmap.core.FCircle2D;
70
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
71
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
72
import com.iver.cit.gvsig.fmap.core.FMultipoint3D;
73
import com.iver.cit.gvsig.fmap.core.FPoint2D;
74
import com.iver.cit.gvsig.fmap.core.FPoint3D;
75
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
76
import com.iver.cit.gvsig.fmap.core.FPolygon3D;
77
import com.iver.cit.gvsig.fmap.core.FPolyline3D;
78
import com.iver.cit.gvsig.fmap.core.FShape;
79
import com.iver.cit.gvsig.fmap.core.FShape3D;
80
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
81
import com.iver.cit.gvsig.fmap.core.IGeometry;
82
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
83
import com.iver.cit.gvsig.fmap.drivers.ConnectionJDBC;
84
import com.iver.cit.gvsig.fmap.drivers.IConnection;
85
import com.vividsolutions.jts.algorithm.CGAlgorithms;
86
import com.vividsolutions.jts.geom.Coordinate;
87
import com.vividsolutions.jts.geom.CoordinateArrays;
88
import com.vividsolutions.jts.geom.Envelope;
89
import com.vividsolutions.jts.geom.GeometryFactory;
90
import com.vividsolutions.jts.geom.LineString;
91
import com.vividsolutions.jts.geom.LinearRing;
92
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
93

    
94

    
95
/**
96
 * Utility class with static methods.
97
 *
98
 * @author jldominguez
99
 *
100
 */
101
public class OracleSpatialUtils {
102
    private static Logger logger = Logger.getLogger(OracleSpatialUtils.class.getName());
103
    private static double FLATNESS = 0.8;
104
    private static GeometryFactory geomFactory = new GeometryFactory();
105
    private static final double IRRELEVANT_DISTANCE = 0.00000001;
106
    private static Random rnd = new Random();
107
    private static DecimalFormat df = new DecimalFormat();
108
    private static DecimalFormatSymbols dfs = new DecimalFormatSymbols();
109
    public static final int ORACLE_GTYPE_UNKNOWN = 0;
110
    public static final int ORACLE_GTYPE_POINT = 1;
111
    public static final int ORACLE_GTYPE_LINE = 2;
112
    public static final int ORACLE_GTYPE_POLYGON = 3;
113
    public static final int ORACLE_GTYPE_COLLECTION = 4;
114
    public static final int ORACLE_GTYPE_MULTIPOINT = 5;
115
    public static final int ORACLE_GTYPE_MULTILINE = 6;
116
    public static final int ORACLE_GTYPE_MULTIPOLYGON = 7;
117

    
118
    /**
119
     * COnstructs a geometry from a file that contains a vertex per line:
120
     *
121
     * x1 y1 z1
122
     * x2 y2 z2
123
     * ...
124
     *
125
     * @param filepath vertices text file path
126
     * @param polygon whether it is a polygon or not
127
     * @return the created geometry
128
     */
129
    public static IGeometry readGeometry3D(URL filepath, boolean polygon) {
130
        GeneralPathX resp = new GeneralPathX();
131
        File file = new File(filepath.getFile());
132
        ArrayList z = new ArrayList();
133

    
134
        try {
135
            FileReader fr = new FileReader(file);
136
            BufferedReader br = new BufferedReader(fr);
137
            double[] coords = new double[3];
138

    
139
            boolean move = true;
140

    
141
            String line = br.readLine();
142

    
143
            while (line != null) {
144
                coords = parseLine(line);
145

    
146
                if (line.length() == 0) {
147
                    move = true;
148
                }
149
                else {
150
                    if (move) {
151
                        resp.moveTo(coords[0], coords[1]);
152
                        z.add(new Double(coords[2]));
153
                    }
154
                    else {
155
                        resp.lineTo(coords[0], coords[1]);
156
                        z.add(new Double(coords[2]));
157
                    }
158

    
159
                    move = false;
160
                }
161

    
162
                line = br.readLine();
163
            }
164
        }
165
        catch (Exception ex) {
166
                logger.error("While creating GeneralPathX: " +
167
                ex.getMessage());
168

    
169
            return null;
170
        }
171

    
172
        double[] zz = new double[z.size()];
173

    
174
        for (int i = 0; i < z.size(); i++) {
175
            zz[i] = ((Double) z.get(i)).doubleValue();
176
        }
177

    
178
        if (polygon) {
179
            return ShapeFactory.createPolygon3D(resp, zz);
180
        }
181
        else {
182
            return ShapeFactory.createPolyline3D(resp, zz);
183
        }
184
    }
185

    
186
    private static double[] parseLine(String line) {
187
        String[] sep = line.split(" ");
188
        double[] resp = new double[3];
189

    
190
        for (int i = 0; i < 3; i++)
191
            resp[i] = 0.0;
192

    
193
        try {
194
            resp[0] = Double.parseDouble(sep[0]);
195
        }
196
        catch (Exception ex) {
197
        }
198

    
199
        if (sep.length > 1) {
200
            try {
201
                resp[1] = Double.parseDouble(sep[1]);
202
            }
203
            catch (Exception ex) {
204
            }
205

    
206
            if (sep.length > 2) {
207
                try {
208
                    resp[2] = Double.parseDouble(sep[2]);
209
                }
210
                catch (Exception ex) {
211
                }
212
            }
213
        }
214

    
215
        return resp;
216
    }
217

    
218
    /**
219
     * Utility method to convert a gvSIG FShape into a oracle struct
220
     *
221
     * @param fshp the FShape object
222
     * @param c the connection
223
     * @param srid the SRS (oarcle code)
224
     * @param agu_b whether to check holes validity
225
     * @param hasSrid whether the SRS is non-NULL
226
     * @return a oracle struct representing the geometry
227
     *
228
     * @throws SQLException
229
     */
230
    public static STRUCT fShapeToSTRUCT(Object fshp, IConnection c, int srid,
231
        boolean agu_b, boolean hasSrid) throws SQLException {
232
        boolean three = false;
233

    
234
        if (fshp instanceof FShape3D) {
235
            three = true;
236
        }
237

    
238
        STRUCT resp = null;
239

    
240
        if (fshp instanceof FMultiPoint2D) {
241
            resp = multiPoint2DToStruct((FMultiPoint2D) fshp, c, srid, hasSrid);
242

    
243
            return resp;
244
        }
245

    
246
        if (!(fshp instanceof FShape)) {
247
            logger.error("Unknown geometry: " + fshp.toString());
248

    
249
            return null;
250
        }
251

    
252
        if (fshp instanceof FPoint2D) { // point 2/3d
253

    
254
            // resp = pointToWKT((FPoint2D) fshp, three);
255
            Coordinate p = getSingleCoordinate((FPoint2D) fshp);
256
            resp = getMultiPointAsStruct(p, srid, three, c, hasSrid);
257
        }
258
        else {
259
            if (fshp instanceof FPolygon2D) { // polygon 2/3d
260

    
261
                if (fshp instanceof FCircle2D) {
262
                    resp = getCircleAsStruct((FCircle2D) fshp, srid, c, hasSrid);
263
                }
264
                else {
265
                    // also FEllipse2D
266
                    resp = getMultiPolygonAsStruct((FShape) fshp, srid, three,
267
                            c, agu_b, hasSrid);
268

    
269
                    // ArrayList polys = getPolygonsEasily(fshp);
270
                    // resp = getMultiPolygonAsStruct(polys, srid, three, c);
271
                }
272
            }
273
            else { // line 2/3d
274

    
275
                ArrayList _lines = getLineStrings((FShape) fshp);
276
                resp = getMultiLineAsStruct(_lines, srid, three, c, hasSrid);
277
            }
278
        }
279

    
280
        return resp;
281
    }
282

    
283
    private static STRUCT multiPoint2DToStruct(FMultiPoint2D mp2d,
284
        IConnection c, int srid, boolean hasSrid) throws SQLException {
285
        int np = mp2d.getNumPoints();
286
        boolean threed = (mp2d instanceof FMultipoint3D);
287
        int gtype = 2005;
288
        int dim = 2;
289
        FMultipoint3D mp3d = null;
290

    
291
        if (threed) {
292
            gtype = 3005;
293
            dim = 3;
294
            mp3d = (FMultipoint3D) mp2d;
295
        }
296

    
297
        NUMBER[] indices = new NUMBER[3];
298
        indices[0] = new NUMBER(1);
299
        indices[1] = new NUMBER(1);
300
        indices[2] = new NUMBER(np);
301

    
302
        NUMBER[] ords = new NUMBER[dim * np];
303

    
304
        for (int i = 0; i < np; i++) {
305
            ords[dim * i] = new NUMBER(mp2d.getPoint(i).getX());
306
            ords[(dim * i) + 1] = new NUMBER(mp2d.getPoint(i).getY());
307

    
308
            if (threed) {
309
                ords[(dim * i) + 2] = new NUMBER(mp3d.getZs()[i]);
310
            }
311
        }
312

    
313
        STRUCT resp;
314
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
315
                        ((ConnectionJDBC)c).getConnection());
316
        Object[] obj = new Object[5];
317
        obj[0] = new NUMBER(gtype);
318

    
319
        if (hasSrid) {
320
            obj[1] = new NUMBER(srid);
321
        }
322
        else { // , boolean hasSrid
323
            obj[1] = null;
324
        }
325

    
326
        obj[2] = null;
327
        obj[3] = indices;
328
        obj[4] = ords;
329
        resp = new STRUCT(dsc, ((ConnectionJDBC)c).getConnection(), obj);
330

    
331
        return resp;
332
    }
333

    
334
    private static STRUCT getCircleAsStruct(FCircle2D fcirc, int srid,
335
        IConnection _conn, boolean hasSrid) throws SQLException {
336
        int geotype = 2003;
337
        NUMBER[] indices = new NUMBER[3];
338
        indices[0] = new NUMBER(1);
339
        indices[1] = new NUMBER(1003);
340
        indices[2] = new NUMBER(4);
341

    
342
        NUMBER[] ords = new NUMBER[6];
343
        Coordinate[] three_points = getThreePointsOfCircumference(fcirc.getCenter(),
344
                fcirc.getRadio());
345

    
346
        for (int i = 0; i < three_points.length; i++) {
347
            ords[i * 2] = new NUMBER(three_points[i].x);
348
            ords[(i * 2) + 1] = new NUMBER(three_points[i].y);
349
        }
350

    
351
        STRUCT resp;
352
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
353
                        ((ConnectionJDBC)_conn).getConnection());
354
        Object[] obj = new Object[5];
355
        obj[0] = new NUMBER(geotype);
356

    
357
        if (hasSrid) {
358
            obj[1] = new NUMBER(srid);
359
        }
360
        else {
361
            obj[1] = null;
362
        }
363

    
364
        obj[2] = null;
365
        obj[3] = indices;
366
        obj[4] = ords;
367
        resp = new STRUCT(dsc, ((ConnectionJDBC)_conn).getConnection(), obj);
368

    
369
        return resp;
370
    }
371

    
372
    private static Coordinate[] getThreePointsOfCircumference(Point2D cntr,
373
        double radius) {
374
        Coordinate[] resp = new Coordinate[3];
375
        double x;
376
        double y;
377
        double alpha = 0;
378

    
379
        for (int i = 0; i < 3; i++) {
380
            alpha = (i * 120.0 * Math.PI) / 180.0;
381
            x = cntr.getX() + (radius * Math.cos(alpha));
382
            y = cntr.getY() + (radius * Math.sin(alpha));
383
            resp[i] = new Coordinate(x, y);
384
        }
385

    
386
        return resp;
387
    }
388

    
389
    private static Coordinate getSingleCoordinate(FPoint2D p2d) {
390
        // TODO Auto-generated method stub
391
        Coordinate resp = new Coordinate();
392
        resp.x = p2d.getX();
393
        resp.y = p2d.getY();
394

    
395
        if (p2d instanceof FPoint3D) {
396
            resp.z = ((FPoint3D) p2d).getZs()[0];
397
        }
398

    
399
        return resp;
400
    }
401

    
402
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
403
        if (cc.size() == 2) {
404
            if (sameCoordinate((Coordinate) cc.get(0),
405
                        (Coordinate) cc.get(cc.size() - 1))) {
406
                ArrayList resp = new ArrayList();
407
                resp.add(cc.get(0));
408

    
409
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
410
                newc.x = newc.x + IRRELEVANT_DISTANCE;
411
                resp.add(newc);
412

    
413
                return resp;
414
            }
415
        }
416

    
417
        return cc;
418
    }
419

    
420
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
421
        if (c1.x != c2.x) {
422
            return false;
423
        }
424

    
425
        if (c1.y != c2.y) {
426
            return false;
427
        }
428

    
429
        return true;
430
    }
431

    
432
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
433
        if (cc.size() == 2) {
434
            return getMinClosedCoords((Coordinate) cc.get(0));
435
        }
436

    
437
        if (cc.size() == 3) {
438
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
439
                return getMinClosedCoords((Coordinate) cc.get(0));
440
            }
441

    
442
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
443
                return getMinClosedCoords((Coordinate) cc.get(0));
444
            }
445

    
446
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
447
                return getMinClosedCoords((Coordinate) cc.get(1));
448
            }
449

    
450
            cc.add(cc.get(0));
451

    
452
            return cc;
453
        }
454

    
455
        if (!sameCoordinate((Coordinate) cc.get(0),
456
                    (Coordinate) cc.get(cc.size() - 1))) {
457
            cc.add(cc.get(0));
458
        }
459

    
460
        return cc;
461
    }
462

    
463
    private static ArrayList getMinClosedCoords(Coordinate c) {
464
        ArrayList resp = new ArrayList();
465
        resp.add(c);
466

    
467
        Coordinate nc = new Coordinate(c);
468
        nc.x = nc.x + IRRELEVANT_DISTANCE;
469
        resp.add(nc);
470

    
471
        Coordinate nc2 = new Coordinate(nc);
472
        nc2.y = nc2.y + IRRELEVANT_DISTANCE;
473
        resp.add(nc2);
474

    
475
        resp.add(new Coordinate(c));
476

    
477
        return resp;
478
    }
479

    
480
    private static LinearRing getMinLinearRing(Coordinate c) {
481
        Coordinate[] p = new Coordinate[4];
482
        p[0] = c;
483

    
484
        Coordinate nc = new Coordinate(c);
485
        nc.x = nc.x + IRRELEVANT_DISTANCE;
486

    
487
        Coordinate nc2 = new Coordinate(nc);
488
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
489
        p[1] = nc;
490
        p[2] = nc2;
491
        p[3] = new Coordinate(c);
492

    
493
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
494
        LinearRing ls = new LinearRing(cs, geomFactory);
495

    
496
        return ls;
497
    }
498

    
499
    private static double[] getMinLinearRingZ() {
500
        double[] resp = new double[4];
501

    
502
        for (int i = 0; i < 4; i++)
503
            resp[i] = 0.0;
504

    
505
        return resp;
506
    }
507

    
508
    private static boolean pointInList(Coordinate testPoint,
509
        Coordinate[] pointList) {
510
        int t;
511
        int numpoints;
512
        Coordinate p;
513

    
514
        numpoints = Array.getLength(pointList);
515

    
516
        for (t = 0; t < numpoints; t++) {
517
            p = pointList[t];
518

    
519
            if ((testPoint.x == p.x) && (testPoint.y == p.y) &&
520
                    ((testPoint.z == p.z) || (!(testPoint.z == testPoint.z))) //nan test; x!=x iff x is nan
521
            ) {
522
                return true;
523
            }
524
        }
525

    
526
        return false;
527
    }
528

    
529
    private static ArrayList getPolygonsEasily(FShape mpolygon) {
530
        boolean threed = false;
531

    
532
        if (mpolygon instanceof FPolygon3D) {
533
            threed = true;
534
        }
535

    
536
        int start_ind = 0;
537
        int end_ind = 0;
538
        int ind = 0;
539
        int new_size;
540
        ArrayList arrayCoords = null;
541
        ArrayList resp = new ArrayList();
542
        Coordinate[] points = null;
543
        int theType = -99;
544
        double[] theData = new double[6];
545
        Coordinate onlyCoord = null;
546
        int numParts = 0;
547

    
548
        PathIterator theIterator = mpolygon.getPathIterator(null, FLATNESS);
549

    
550
        while (!theIterator.isDone()) {
551
            //while not done
552
            theType = theIterator.currentSegment(theData);
553

    
554
            if (onlyCoord == null) {
555
                onlyCoord = new Coordinate();
556
                onlyCoord.x = theData[0];
557
                onlyCoord.y = theData[1];
558
            }
559

    
560
            switch (theType) {
561
            case PathIterator.SEG_MOVETO:
562

    
563
                if (arrayCoords == null) {
564
                    arrayCoords = new ArrayList();
565
                }
566
                else {
567
                    end_ind = ind - 1;
568

    
569
                    arrayCoords = getClosedRelevantPolygon(arrayCoords);
570
                    new_size = arrayCoords.size();
571

    
572
                    if (arrayCoords != null) {
573
                        points = CoordinateArrays.toCoordinateArray(arrayCoords);
574

    
575
                        try {
576
                            LinearRing aux = geomFactory.createLinearRing(points);
577
                            double[] z = null;
578

    
579
                            if (threed) {
580
                                z = getZ((FPolygon3D) mpolygon, start_ind,
581
                                        end_ind, new_size);
582
                            }
583

    
584
                            LineString3D ring = new LineString3D(aux, z);
585

    
586
                            if (CGAlgorithms.isCCW(points)) {
587
                                resp.add(ring);
588
                            }
589
                            else {
590
                                resp.add(ring.createReverse());
591
                            }
592
                        }
593
                        catch (Exception e) {
594
                                logger.error("Topology exception: " +
595
                                e.getMessage());
596

    
597
                            return null;
598
                        }
599
                    }
600

    
601
                    arrayCoords = new ArrayList();
602

    
603
                    start_ind = ind;
604
                }
605

    
606
                numParts++;
607

    
608
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
609
                ind++;
610

    
611
                break;
612

    
613
            case PathIterator.SEG_LINETO:
614
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
615
                ind++;
616

    
617
                break;
618

    
619
            case PathIterator.SEG_QUADTO:
620
                    logger.info("SEG_QUADTO Not supported here");
621
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
622
                arrayCoords.add(new Coordinate(theData[2], theData[3]));
623
                ind++;
624
                ind++;
625

    
626
                break;
627

    
628
            case PathIterator.SEG_CUBICTO:
629
                    logger.info("SEG_CUBICTO Not supported here");
630
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
631
                arrayCoords.add(new Coordinate(theData[2], theData[3]));
632
                arrayCoords.add(new Coordinate(theData[4], theData[5]));
633
                ind++;
634
                ind++;
635
                ind++;
636

    
637
                break;
638

    
639
            case PathIterator.SEG_CLOSE:
640

    
641
                // Coordinate firstCoord = (Coordinate) arrayCoords.get(0);
642
                // arrayCoords.add(new Coordinate(firstCoord.x, firstCoord.y));
643
                break;
644
            } //end switch
645

    
646
            theIterator.next();
647
        } //end while loop
648

    
649
        end_ind = ind - 1;
650

    
651
        // null shape:
652
        if (arrayCoords == null) {
653
            arrayCoords = new ArrayList();
654

    
655
            Coordinate _c = new Coordinate(0, 0, 0);
656
            arrayCoords.add(new Coordinate(_c));
657
            arrayCoords.add(new Coordinate(_c));
658
        }
659

    
660
        // --------------------------------------------
661
        arrayCoords = getClosedRelevantPolygon(arrayCoords);
662
        new_size = arrayCoords.size();
663

    
664
        if (arrayCoords != null) {
665
            points = CoordinateArrays.toCoordinateArray(arrayCoords);
666

    
667
            try {
668
                LinearRing aux = geomFactory.createLinearRing(points);
669
                double[] z = null;
670

    
671
                if (threed) {
672
                    z = getZ((FPolygon3D) mpolygon, start_ind, end_ind, new_size);
673
                }
674

    
675
                LineString3D ring = new LineString3D(aux, z);
676

    
677
                if (CGAlgorithms.isCCW(points)) {
678
                    resp.add(ring);
679
                }
680
                else {
681
                    resp.add(ring.createReverse());
682
                }
683
            }
684
            catch (Exception e) {
685
                    logger.error("Topology exception: " + e.getMessage());
686

    
687
                return null;
688
            }
689
        }
690

    
691
        if (resp.size() == 0) {
692
            resp.add(new LineString3D(getMinLinearRing(onlyCoord),
693
                    getMinLinearRingZ()));
694
        }
695

    
696
        return resp;
697
    }
698

    
699
    /**
700
     * Utility method to reverse an array of doubles.
701
     *
702
     * @param _z an array of doubles to be reversed.
703
     *
704
     * @return the reversed array of doubles
705
     */
706
    public static double[] reverseArray(double[] _z) {
707
        int size = _z.length;
708
        double[] resp = new double[size];
709

    
710
        for (int i = 0; i < size; i++) {
711
            resp[i] = _z[size - 1 - i];
712
        }
713

    
714
        return resp;
715
    }
716

    
717
    /**
718
     * Utility method to reverse an array of coordinates
719
     *
720
     * @param _z an array of coordinaes to be reversed.
721
     *
722
     * @return the reversed array of coordinates
723
     */
724
    public static Coordinate[] reverseCoordinateArray(Coordinate[] _z) {
725
        int size = _z.length;
726
        Coordinate[] resp = new Coordinate[size];
727

    
728
        for (int i = 0; i < size; i++) {
729
            resp[i] = _z[size - 1 - i];
730
        }
731

    
732
        return resp;
733
    }
734

    
735
    private static double[] getZ(FShape3D p3d, int _str, int _end, int size) {
736
        double[] resp = new double[size];
737
        double[] allz = p3d.getZs();
738

    
739
        for (int i = _str; ((i <= _end) && ((i - _str) < size)); i++) {
740
            resp[i - _str] = allz[i];
741
        }
742

    
743
        if ((_end - _str + 1) < size) {
744
            double repe = allz[_end];
745

    
746
            for (int i = (_end - _str + 1); i < size; i++) {
747
                resp[i] = repe;
748
            }
749
        }
750

    
751
        return resp;
752
    }
753

    
754
    private static ArrayList getLineStrings(FShape mlines) {
755
        boolean threed = false;
756

    
757
        if (mlines instanceof FPolyline3D) {
758
            threed = true;
759
        }
760

    
761
        int start_ind = 0;
762
        int end_ind = 0;
763
        int ind = 0;
764
        int new_size = 0;
765

    
766
        LineString3D lin;
767

    
768
        ArrayList arrayLines = new ArrayList();
769
        PathIterator theIterator = mlines.getPathIterator(null, FLATNESS);
770
        int theType = -99;
771
        double[] theData = new double[6];
772
        ArrayList arrayCoords = null;
773
        int numParts = 0;
774

    
775
        while (!theIterator.isDone()) {
776
            //while not done
777
            theType = theIterator.currentSegment(theData);
778

    
779
            switch (theType) {
780
            case PathIterator.SEG_MOVETO:
781

    
782
                if (arrayCoords == null) {
783
                    arrayCoords = new ArrayList();
784
                }
785
                else {
786
                    end_ind = ind - 1;
787
                    arrayCoords = ensureSensibleLineString(arrayCoords);
788
                    new_size = arrayCoords.size();
789

    
790
                    LineString aux = geomFactory.createLineString(CoordinateArrays.toCoordinateArray(
791
                                arrayCoords));
792
                    double[] z = null;
793

    
794
                    if (threed) {
795
                        z = getZ((FPolyline3D) mlines, start_ind, end_ind,
796
                                new_size);
797
                    }
798

    
799
                    lin = new LineString3D(aux, z);
800
                    arrayLines.add(lin);
801
                    arrayCoords = new ArrayList();
802

    
803
                    start_ind = ind;
804
                }
805

    
806
                numParts++;
807
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
808

    
809
                break;
810

    
811
            case PathIterator.SEG_LINETO:
812
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
813

    
814
                break;
815

    
816
            case PathIterator.SEG_QUADTO:
817
                    logger.info("Not supported here: SEG_QUADTO");
818

    
819
                break;
820

    
821
            case PathIterator.SEG_CUBICTO:
822
                    logger.info("Not supported here: SEG_CUBICTO");
823

    
824
                break;
825

    
826
            case PathIterator.SEG_CLOSE:
827

    
828
                Coordinate firstCoord = (Coordinate) arrayCoords.get(0);
829
                arrayCoords.add(new Coordinate(firstCoord.x, firstCoord.y));
830

    
831
                break;
832
            } //end switch
833

    
834
            theIterator.next();
835
            ind++;
836
        } //end while loop
837

    
838
        arrayCoords = ensureSensibleLineString(arrayCoords);
839
        new_size = arrayCoords.size();
840

    
841
        LineString aux = geomFactory.createLineString(CoordinateArrays.toCoordinateArray(
842
                    arrayCoords));
843
        double[] z = null;
844

    
845
        if (threed) {
846
            z = getZ((FPolyline3D) mlines, start_ind, end_ind, new_size);
847
        }
848

    
849
        lin = new LineString3D(aux, z);
850
        arrayLines.add(lin);
851

    
852
        return arrayLines;
853
    }
854

    
855
    private static String lineStringToWKT(LineString3D ls, boolean threed) {
856
        String resp = "(";
857
        Coordinate[] cc = ls.getLs().getCoordinates();
858
        double[] z = ls.getZc();
859
        int size = cc.length;
860

    
861
        if (threed) {
862
            for (int i = 0; i < size; i++) {
863
                resp = resp + cc[i].x + " " + cc[i].y + " " + z[i] + ", ";
864
            }
865

    
866
            resp = resp.substring(0, resp.length() - 2);
867
            resp = resp + ")";
868
        }
869
        else {
870
            for (int i = 0; i < size; i++) {
871
                resp = resp + cc[i].x + " " + cc[i].y + ", ";
872
            }
873

    
874
            resp = resp.substring(0, resp.length() - 2);
875
            resp = resp + ")";
876
        }
877

    
878
        return resp;
879
    }
880

    
881
    private static String multiLineStringToWKT(ArrayList ml, boolean threed) {
882
        String resp = "MULTILINESTRING(";
883

    
884
        for (int i = 0; i < ml.size(); i++) {
885
            LineString3D ls = (LineString3D) ml.get(i);
886
            resp = resp + lineStringToWKT(ls, threed) + ", ";
887
        }
888

    
889
        resp = resp.substring(0, resp.length() - 2) + ")";
890

    
891
        return resp;
892
    }
893

    
894
    private static String polygonsToWKT(ArrayList pols, boolean threed) {
895
        String resp = "MULTIPOLYGON(";
896
        LineString3D ls = null;
897

    
898
        for (int i = 0; i < pols.size(); i++) {
899
            ls = (LineString3D) pols.get(i);
900
            resp = resp + "(" + lineStringToWKT(ls, threed) + "), ";
901
        }
902

    
903
        resp = resp.substring(0, resp.length() - 2) + ")";
904

    
905
        return resp;
906
    }
907

    
908
    private static String shellAndHolesToWKT(LineString3D shell,
909
        ArrayList holes, boolean threed) {
910
        String resp = "(";
911
        resp = resp + lineStringToWKT(shell, threed);
912

    
913
        if (holes.size() > 0) {
914
            for (int i = 0; i < holes.size(); i++) {
915
                LineString3D ls = (LineString3D) holes.get(i);
916
                resp = resp + ", " + lineStringToWKT(ls, threed);
917
            }
918
        }
919

    
920
        resp = resp + ")";
921

    
922
        return resp;
923
    }
924

    
925
    private static String multiPolygonToWKT(ArrayList shells, ArrayList hFs,
926
        boolean threed) {
927
        String resp = "MULTIPOLYGON(";
928
        LineString3D ls = null;
929
        ArrayList holes;
930

    
931
        for (int i = 0; i < shells.size(); i++) {
932
            ls = (LineString3D) shells.get(i);
933
            holes = (ArrayList) hFs.get(i);
934
            resp = resp + shellAndHolesToWKT(ls, holes, threed) + ", ";
935
        }
936

    
937
        resp = resp.substring(0, resp.length() - 2) + ")";
938

    
939
        return resp;
940
    }
941

    
942
    private static String pointToWKT(FPoint2D point, boolean threed) {
943
        String resp = "POINT(" + point.getX() + " " + point.getY();
944

    
945
        if ((threed) && (point instanceof FPoint3D)) {
946
            resp = resp + " " + ((FPoint3D) point).getZs()[0];
947
        }
948

    
949
        resp = resp + ")";
950

    
951
        return resp;
952
    }
953

    
954
    private static int twoDIndexToDimsIndex(int n, int d) {
955
        return ((d * (n - 1)) / 2) + 1;
956
    }
957

    
958
    private static ARRAY setSubelementsToDim(ARRAY old, int d)
959
        throws SQLException {
960
        Datum[] infos = (Datum[]) old.getOracleArray();
961

    
962
        for (int i = 3; i < infos.length; i = i + 3) {
963
            int oldind = infos[i].intValue();
964
            oldind = twoDIndexToDimsIndex(oldind, d);
965
            infos[i] = new NUMBER(oldind);
966

    
967
            //
968
            oldind = infos[i + 1].intValue();
969
            infos[i + 1] = new NUMBER(infos[1].intValue());
970
        }
971

    
972
        ARRAY resp = new ARRAY(old.getDescriptor(), old.getOracleConnection(),
973
                infos);
974

    
975
        return resp;
976
    }
977

    
978
    private static boolean isPointInsideLineString(Coordinate p, LineString ls) {
979
        Envelope env = ls.getEnvelopeInternal();
980

    
981
        if (!env.contains(p)) {
982
            return false;
983
        }
984

    
985
        return CGAlgorithms.isPointInRing(p, ls.getCoordinates());
986
    }
987

    
988
    private static boolean lineString3DIsContainedBy(LineString3D contained,
989
        LineString3D container) {
990
        int samples = 10;
991
        LineString _in = contained.getLs();
992
        LineString _out = container.getLs();
993
        Coordinate[] inc = _in.getCoordinates();
994
        Coordinate aux;
995
        int size = inc.length;
996

    
997
        if (size <= 10) {
998
            for (int i = 0; i < size; i++) {
999
                aux = inc[i];
1000

    
1001
                if (!isPointInsideLineString(aux, _out)) {
1002
                    return false;
1003
                }
1004
            }
1005

    
1006
            return true;
1007
        }
1008
        else {
1009
            for (int i = 0; i < samples; i++) {
1010
                aux = inc[rnd.nextInt(size)];
1011

    
1012
                if (!isPointInsideLineString(aux, _out)) {
1013
                    return false;
1014
                }
1015
            }
1016

    
1017
            return true;
1018
        }
1019
    }
1020

    
1021
    private static STRUCT getMultiPolygonAsStruct(ArrayList pols, int srid,
1022
        boolean threed, IConnection _conn, boolean agu_bien, boolean hasSrid)
1023
        throws SQLException {
1024
        int size = pols.size();
1025
        int geotype = 2007;
1026
        int dim = 2;
1027
        int acum = 0;
1028

    
1029
        if (threed) {
1030
            geotype = 3007;
1031
            dim = 3;
1032
        }
1033

    
1034
        NUMBER[] indices = new NUMBER[3 * size];
1035

    
1036
        for (int i = 0; i < size; i++) {
1037
            indices[3 * i] = new NUMBER(acum + 1);
1038
            indices[(3 * i) + 1] = new NUMBER(1003);
1039
            indices[(3 * i) + 2] = new NUMBER(1);
1040
            acum = acum +
1041
                (dim * ((LineString3D) pols.get(i)).getLs().getNumPoints());
1042
        }
1043

    
1044
        int _ind = 0;
1045
        NUMBER[] ords = new NUMBER[acum];
1046

    
1047
        for (int i = 0; i < size; i++) {
1048
            LineString3D ls = (LineString3D) pols.get(i);
1049
            int num_p = ls.getLs().getNumPoints();
1050

    
1051
            for (int j = 0; j < num_p; j++) {
1052
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1053
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1054

    
1055
                if (threed) {
1056
                    ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1057
                }
1058

    
1059
                _ind = _ind + dim;
1060
            }
1061
        }
1062

    
1063
        STRUCT resp;
1064
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1065
                        ((ConnectionJDBC)_conn).getConnection());
1066
        Object[] obj = new Object[5];
1067
        obj[0] = new NUMBER(geotype);
1068

    
1069
        if (hasSrid) {
1070
            obj[1] = new NUMBER(srid);
1071
        }
1072
        else {
1073
            obj[1] = null;
1074
        }
1075

    
1076
        obj[2] = null;
1077
        obj[3] = indices;
1078
        obj[4] = ords;
1079
        resp = new STRUCT(dsc, ((ConnectionJDBC)_conn).getConnection(), obj);
1080

    
1081
        return resp;
1082
    }
1083

    
1084
    private static STRUCT getMultiLineAsStruct(ArrayList lines, int srid,
1085
        boolean threed, IConnection _conn, boolean hasSrid)
1086
        throws SQLException {
1087
        /*
1088
        if (lines.size() == 1) {
1089
                return getOneLineStringAsStruct((LineString3D) lines.get(0), srid, threed, _conn);
1090
        }
1091
        */
1092
        int size = lines.size();
1093
        int geotype = 2006;
1094
        int dim = 2;
1095
        int acum = 0;
1096

    
1097
        if (threed) {
1098
            geotype = 3006;
1099
            dim = 3;
1100
        }
1101

    
1102
        NUMBER[] indices = new NUMBER[3 * size];
1103

    
1104
        for (int i = 0; i < size; i++) {
1105
            indices[3 * i] = new NUMBER(acum + 1);
1106
            indices[(3 * i) + 1] = new NUMBER(2);
1107
            indices[(3 * i) + 2] = new NUMBER(1);
1108
            acum = acum +
1109
                (dim * ((LineString3D) lines.get(i)).getLs().getNumPoints());
1110
        }
1111

    
1112
        int _ind = 0;
1113
        NUMBER[] ords = new NUMBER[acum];
1114

    
1115
        for (int i = 0; i < size; i++) {
1116
            LineString3D ls = (LineString3D) lines.get(i);
1117
            int num_p = ls.getLs().getNumPoints();
1118

    
1119
            for (int j = 0; j < num_p; j++) {
1120
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1121
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1122

    
1123
                if (threed) {
1124
                    ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1125
                }
1126

    
1127
                _ind = _ind + dim;
1128
            }
1129
        }
1130

    
1131
        STRUCT resp;
1132
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1133
                        ((ConnectionJDBC)_conn).getConnection());
1134
        Object[] obj = new Object[5];
1135
        obj[0] = new NUMBER(geotype);
1136

    
1137
        if (hasSrid) {
1138
            obj[1] = new NUMBER(srid);
1139
        }
1140
        else {
1141
            obj[1] = null;
1142
        }
1143

    
1144
        obj[2] = null;
1145
        obj[3] = indices;
1146
        obj[4] = ords;
1147
        resp = new STRUCT(dsc,((ConnectionJDBC)_conn).getConnection(), obj);
1148

    
1149
        return resp;
1150
    }
1151

    
1152
    private static STRUCT getMultiPointAsStruct(Coordinate pnt, int srid,
1153
        boolean threed, IConnection _conn, boolean hasSrid)
1154
        throws SQLException {
1155
        int geotype = 2001;
1156
        int dim = 2;
1157

    
1158
        if (threed) {
1159
            geotype = 3001;
1160
            dim = 3;
1161
        }
1162

    
1163
        Object[] ords = new Object[3];
1164
        ords[0] = new NUMBER(pnt.x);
1165
        ords[1] = new NUMBER(pnt.y);
1166
        ords[2] = (dim == 3) ? new NUMBER(pnt.z) : null; // ole ole y ole
1167

    
1168
        StructDescriptor ord_dsc = StructDescriptor.createDescriptor("MDSYS.SDO_POINT_TYPE",
1169
                        ((ConnectionJDBC)_conn).getConnection());
1170
        STRUCT ords_st = new STRUCT(ord_dsc, ((ConnectionJDBC)_conn).getConnection(), ords);
1171

    
1172
        STRUCT resp;
1173

    
1174
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1175
                        ((ConnectionJDBC)_conn).getConnection());
1176
        Object[] obj = new Object[5];
1177

    
1178
        obj[0] = new NUMBER(geotype);
1179

    
1180
        if (hasSrid) {
1181
            obj[1] = new NUMBER(srid);
1182
        }
1183
        else {
1184
            obj[1] = null;
1185
        }
1186

    
1187
        obj[2] = ords_st;
1188
        obj[3] = null;
1189
        obj[4] = null;
1190
        resp = new STRUCT(dsc, ((ConnectionJDBC)_conn).getConnection(), obj);
1191

    
1192
        return resp;
1193
    }
1194

    
1195
    /**
1196
     * Utility method to compute a circle's center and radius from three given points.
1197
     *
1198
     * @param points three points of a circumference
1199
     * @return a 2-item array with the circumference's center (Point2D) and radius (Double)
1200
     */
1201
    public static Object[] getCenterAndRadiousOfCirc(Point2D[] points) {
1202
        Object[] resp = new Object[2];
1203
        resp[0] = new Point2D.Double(0, 0);
1204
        resp[1] = new Double(0);
1205

    
1206
        double m11;
1207
        double m12;
1208
        double m13;
1209
        double m14;
1210

    
1211
        if (points.length != 3) {
1212
            logger.error("Needs 3 points (found " + points.length +
1213
                ") - circle cannot be computed.");
1214

    
1215
            // not a circle
1216
            return resp;
1217
        }
1218

    
1219
        double[][] a = new double[3][3];
1220

    
1221
        for (int i = 0; i < 3; i++) { // find minor 11
1222
            a[i][0] = points[i].getX();
1223
            a[i][1] = points[i].getY();
1224
            a[i][2] = 1;
1225
        }
1226

    
1227
        m11 = determinant(a, 3);
1228

    
1229
        for (int i = 0; i < 3; i++) { // find minor 12
1230
            a[i][0] = (points[i].getX() * points[i].getX()) +
1231
                (points[i].getY() * points[i].getY());
1232
            a[i][1] = points[i].getY();
1233
            a[i][2] = 1;
1234
        }
1235

    
1236
        m12 = determinant(a, 3);
1237

    
1238
        for (int i = 0; i < 3; i++) // find minor 13
1239
         {
1240
            a[i][0] = (points[i].getX() * points[i].getX()) +
1241
                (points[i].getY() * points[i].getY());
1242
            a[i][1] = points[i].getX();
1243
            a[i][2] = 1;
1244
        }
1245

    
1246
        m13 = determinant(a, 3);
1247

    
1248
        for (int i = 0; i < 3; i++) { // find minor 14
1249
            a[i][0] = (points[i].getX() * points[i].getX()) +
1250
                (points[i].getY() * points[i].getY());
1251
            a[i][1] = points[i].getX();
1252
            a[i][2] = points[i].getY();
1253
        }
1254

    
1255
        m14 = determinant(a, 3);
1256

    
1257
        Double resp_radius = new Double(0);
1258
        Point2D resp_center = new Point2D.Double(0, 0);
1259

    
1260
        if (m11 == 0) {
1261
            logger.error("Three points aligned - circle cannot be computed."); // not a circle
1262
        }
1263
        else {
1264
            double x = (0.5 * m12) / m11;
1265
            double y = (-0.5 * m13) / m11;
1266
            resp_center.setLocation(x, y);
1267
            resp_radius = new Double(Math.sqrt((x * x) + (y * y) + (m14 / m11)));
1268
            resp[0] = resp_center;
1269
            resp[1] = resp_radius;
1270
        }
1271

    
1272
        return resp;
1273
    }
1274

    
1275
    /**
1276
     * Utility method to compute a matrix determinant
1277
     * @param a the matrix
1278
     * @param n matrix size
1279
     * @return the matrix's determinant
1280
     */
1281
    public static double determinant(double[][] a, int n) {
1282
        double resp = 0;
1283
        double[][] m = new double[3][3];
1284

    
1285
        if (n == 2) { // terminate recursion
1286
            resp = (a[0][0] * a[1][1]) - (a[1][0] * a[0][1]);
1287
        }
1288
        else {
1289
            resp = 0;
1290

    
1291
            for (int j1 = 0; j1 < n; j1++) { // do each column
1292

    
1293
                for (int i = 1; i < n; i++) { // create minor
1294

    
1295
                    int j2 = 0;
1296

    
1297
                    for (int j = 0; j < n; j++) {
1298
                        if (j == j1) {
1299
                            continue;
1300
                        }
1301

    
1302
                        m[i - 1][j2] = a[i][j];
1303
                        j2++;
1304
                    }
1305
                }
1306

    
1307
                // sum (+/-)cofactor * minor
1308
                resp = resp +
1309
                    (Math.pow(-1.0, j1) * a[0][j1] * determinant(m, n - 1));
1310
            }
1311
        }
1312

    
1313
        return resp;
1314
    }
1315

    
1316
    private static int getSmallestContainerExcept(LineString3D ls,
1317
        ArrayList list, int self) {
1318
        int resp = -1;
1319
        ArrayList provList = new ArrayList();
1320

    
1321
        int size = list.size();
1322

    
1323
        for (int i = 0; i < self; i++) {
1324
            if (lineString3DIsContainedBy(ls, (LineString3D) list.get(i))) {
1325
                provList.add(new Integer(i));
1326
            }
1327
        }
1328

    
1329
        for (int i = (self + 1); i < size; i++) {
1330
            if (lineString3DIsContainedBy(ls, (LineString3D) list.get(i))) {
1331
                provList.add(new Integer(i));
1332
            }
1333
        }
1334

    
1335
        if (provList.size() == 0) {
1336
            // logger.debug("LineString is not contained by any other ls.");
1337
        }
1338
        else {
1339
            if (provList.size() == 1) {
1340
                resp = ((Integer) provList.get(0)).intValue();
1341
            }
1342
            else {
1343
                if (provList.size() == 2) {
1344
                    int ind_1 = ((Integer) provList.get(0)).intValue();
1345
                    int ind_2 = ((Integer) provList.get(1)).intValue();
1346
                    LineString3D ls1 = (LineString3D) list.get(ind_1);
1347
                    LineString3D ls2 = (LineString3D) list.get(ind_2);
1348

    
1349
                    if (lineString3DIsContainedBy(ls1, ls2)) {
1350
                        resp = ind_1;
1351
                    }
1352
                    else {
1353
                        resp = ind_2;
1354
                    }
1355
                }
1356
                else {
1357
                    // not so deep, sorry!
1358
                    // it's going to be a shell: resp = -1;
1359
                }
1360
            }
1361
        }
1362

    
1363
        return resp;
1364
    }
1365

    
1366
    private static int[] getIndicesOfShells(int[] containings) {
1367
        ArrayList resp = new ArrayList();
1368

    
1369
        for (int i = 0; i < containings.length; i++) {
1370
            if (containings[i] == -1) {
1371
                resp.add(new Integer(i));
1372
            }
1373
        }
1374

    
1375
        int size = resp.size();
1376
        int[] _resp = new int[size];
1377

    
1378
        for (int i = 0; i < size; i++) {
1379
            _resp[i] = ((Integer) resp.get(i)).intValue();
1380
        }
1381

    
1382
        return _resp;
1383
    }
1384

    
1385
    private static int[] getIndicesOfHoles(int[] containings, int[] shells) {
1386
        ArrayList resp = new ArrayList();
1387

    
1388
        for (int i = 0; i < containings.length; i++) {
1389
            int cont_by = containings[i];
1390

    
1391
            if ((cont_by != -1) && (isOneOf(cont_by, shells))) {
1392
                resp.add(new Integer(i));
1393
            }
1394
        }
1395

    
1396
        int size = resp.size();
1397
        int[] _resp = new int[size];
1398

    
1399
        for (int i = 0; i < size; i++) {
1400
            _resp[i] = ((Integer) resp.get(i)).intValue();
1401
        }
1402

    
1403
        return _resp;
1404
    }
1405

    
1406
    private static int[] getFinalContainings(int[] containings, int[] holes) {
1407
        ArrayList resp = new ArrayList();
1408

    
1409
        for (int i = 0; i < containings.length; i++) {
1410
            int cont_by = containings[i];
1411

    
1412
            if (isOneOf(cont_by, holes)) {
1413
                resp.add(new Integer(-1));
1414
            }
1415
            else {
1416
                resp.add(new Integer(cont_by));
1417
            }
1418
        }
1419

    
1420
        int size = resp.size();
1421
        int[] _resp = new int[size];
1422

    
1423
        for (int i = 0; i < size; i++) {
1424
            _resp[i] = ((Integer) resp.get(i)).intValue();
1425
        }
1426

    
1427
        return _resp;
1428
    }
1429

    
1430
    private static ArrayList getHolesOf(int ind, int[] final_contn,
1431
        ArrayList all) {
1432
        ArrayList resp_ind = new ArrayList();
1433

    
1434
        for (int i = 0; i < final_contn.length; i++) {
1435
            if (final_contn[i] == ind) {
1436
                resp_ind.add(new Integer(i));
1437
            }
1438
        }
1439

    
1440
        ArrayList resp = new ArrayList();
1441

    
1442
        for (int i = 0; i < resp_ind.size(); i++) {
1443
            Integer aux = (Integer) resp_ind.get(i);
1444
            resp.add(all.get(aux.intValue()));
1445
        }
1446

    
1447
        return resp;
1448
    }
1449

    
1450
    private static ArrayList getShellsIn(int[] final_contn, ArrayList all) {
1451
        ArrayList resp_ind = new ArrayList();
1452

    
1453
        for (int i = 0; i < final_contn.length; i++) {
1454
            if (final_contn[i] == -1) {
1455
                resp_ind.add(new Integer(i));
1456
            }
1457
        }
1458

    
1459
        ArrayList resp = new ArrayList();
1460

    
1461
        for (int i = 0; i < resp_ind.size(); i++) {
1462
            Integer aux = (Integer) resp_ind.get(i);
1463
            resp.add(all.get(aux.intValue()));
1464
        }
1465

    
1466
        return resp;
1467
    }
1468

    
1469
    /**
1470
     * This method tries to guess who is a shell and who is a hole from a set of
1471
     * linestrings.
1472
     *
1473
     * @param all_ls a set of linestrings to be checked.
1474
     *
1475
     * @return a 2-item array. the first is an arraylist of linestrings thought to be shells.
1476
     * the second is an array of arraylists containing the holes of each shell found in the
1477
     * first item
1478
     *
1479
     */
1480
    public static Object[] getHolesForShells(ArrayList all_ls) {
1481
        int no_of_ls = all_ls.size();
1482
        int[] containedby = new int[no_of_ls];
1483
        int[] shells;
1484
        int[] holes;
1485
        int[] final_cont;
1486

    
1487
        for (int i = 0; i < no_of_ls; i++) {
1488
            LineString3D ls_aux = (LineString3D) all_ls.get(i);
1489
            containedby[i] = getSmallestContainerExcept(ls_aux, all_ls, i);
1490
        }
1491

    
1492
        shells = getIndicesOfShells(containedby);
1493
        holes = getIndicesOfHoles(containedby, shells);
1494
        final_cont = getFinalContainings(containedby, holes);
1495

    
1496
        // true shells:
1497
        shells = getIndicesOfShells(final_cont);
1498

    
1499
        ArrayList resp_shells = new ArrayList();
1500
        ArrayList resp_holes_for_shells = new ArrayList();
1501
        ArrayList aux_holes;
1502

    
1503
        for (int i = 0; i < shells.length; i++) {
1504
            resp_shells.add(all_ls.get(shells[i]));
1505
            aux_holes = getHolesOf(i, final_cont, all_ls);
1506
            resp_holes_for_shells.add(aux_holes);
1507
        }
1508

    
1509
        Object[] _resp = new Object[2];
1510
        _resp[0] = resp_shells;
1511
        _resp[1] = resp_holes_for_shells;
1512

    
1513
        return _resp;
1514
    }
1515

    
1516
    private static int getTotalSize(ArrayList listOfLists) {
1517
        int resp = 0;
1518

    
1519
        for (int i = 0; i < listOfLists.size(); i++) {
1520
            resp = resp + ((ArrayList) listOfLists.get(i)).size();
1521
        }
1522

    
1523
        return resp;
1524
    }
1525

    
1526
    // private static STRUCT // private static ArrayList getPolygonsEasily(FShape mpolygon) {
1527
    private static STRUCT getMultiPolygonAsStruct(FShape mpol, int srid,
1528
        boolean threed, IConnection _conn, boolean agu_bien, boolean hasSrid)
1529
        throws SQLException {
1530
        ArrayList all_ls = getPolygonsEasily(mpol);
1531
        Object[] hs = getHolesForShells(all_ls);
1532
        ArrayList sh = (ArrayList) hs[0];
1533
        ArrayList _ho = (ArrayList) hs[1];
1534
        ArrayList ho = reverseHoles(_ho);
1535

    
1536
        return getMultiPolygonAsStruct(sh, ho, srid, threed, _conn, agu_bien,
1537
            hasSrid);
1538
    }
1539

    
1540
    private static ArrayList reverseHoles(ArrayList hh) {
1541
        ArrayList resp = new ArrayList();
1542

    
1543
        for (int i = 0; i < hh.size(); i++) {
1544
            ArrayList item = (ArrayList) hh.get(i);
1545
            ArrayList newitem = new ArrayList();
1546

    
1547
            for (int j = 0; j < item.size(); j++) {
1548
                LineString3D ls = (LineString3D) item.get(j);
1549
                newitem.add(ls.createReverse());
1550
            }
1551

    
1552
            resp.add(newitem);
1553
        }
1554

    
1555
        return resp;
1556
    }
1557

    
1558
    private static STRUCT getMultiPolygonAsStruct(ArrayList shells,
1559
        ArrayList holes, int srid, boolean threed, IConnection _conn,
1560
        boolean explicito, boolean hasSrid) throws SQLException {
1561
        int t = 1003;
1562

    
1563
        if (explicito) {
1564
            t = 2003;
1565
        }
1566

    
1567
        int size = shells.size() + getTotalSize(holes);
1568
        int geotype = 2003;
1569
        if (size > 1) geotype = 2007;
1570

    
1571
        int dim = 2;
1572

    
1573
        if (threed) {
1574
            geotype = geotype + 1000;
1575
            dim = 3;
1576
        }
1577

    
1578
        NUMBER[] indices = new NUMBER[3 * size];
1579

    
1580
        int acum = 0;
1581
        int start_ind = 0;
1582

    
1583
        for (int i = 0; i < shells.size(); i++) {
1584
            indices[start_ind] = new NUMBER(acum + 1);
1585
            indices[start_ind + 1] = new NUMBER(1003);
1586
            indices[start_ind + 2] = new NUMBER(1);
1587
            start_ind = start_ind + 3;
1588
            acum = acum +
1589
                (dim * ((LineString3D) shells.get(i)).getLs().getNumPoints());
1590

    
1591
            ArrayList item_holes = (ArrayList) holes.get(i);
1592

    
1593
            for (int j = 0; j < item_holes.size(); j++) {
1594
                indices[start_ind] = new NUMBER(acum + 1);
1595
                indices[start_ind + 1] = new NUMBER(t); // 1003
1596
                indices[start_ind + 2] = new NUMBER(1);
1597
                start_ind = start_ind + 3;
1598
                acum = acum +
1599
                    (dim * ((LineString3D) item_holes.get(j)).getLs()
1600
                            .getNumPoints());
1601
            }
1602
        }
1603

    
1604
        int _ind = 0;
1605
        NUMBER[] ords = new NUMBER[acum];
1606

    
1607
        for (int i = 0; i < shells.size(); i++) {
1608
            // --------------------------------
1609
            LineString3D ls = (LineString3D) shells.get(i);
1610
            int num_p = ls.getLs().getNumPoints();
1611

    
1612
            for (int j = 0; j < num_p; j++) {
1613
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1614
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1615

    
1616
                if (threed) {
1617
                    ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1618
                }
1619

    
1620
                _ind = _ind + dim;
1621
            }
1622

    
1623
            // -------------------------------
1624
            ArrayList item_holes = (ArrayList) holes.get(i);
1625

    
1626
            for (int j = 0; j < item_holes.size(); j++) {
1627
                ls = (LineString3D) item_holes.get(j);
1628
                num_p = ls.getLs().getNumPoints();
1629

    
1630
                for (int k = 0; k < num_p; k++) {
1631
                    ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(k).x);
1632
                    ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(k).y);
1633

    
1634
                    if (threed) {
1635
                        ords[_ind + 2] = new NUMBER(ls.getZc()[k]);
1636
                    }
1637

    
1638
                    _ind = _ind + dim;
1639
                }
1640
            }
1641
        }
1642

    
1643
        STRUCT resp;
1644
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1645
                        ((ConnectionJDBC)_conn).getConnection());
1646
        Object[] obj = new Object[5];
1647
        obj[0] = new NUMBER(geotype);
1648

    
1649
        if (hasSrid) {
1650
            obj[1] = new NUMBER(srid);
1651
        }
1652
        else {
1653
            obj[1] = null;
1654
        }
1655

    
1656
        obj[2] = null;
1657
        obj[3] = indices;
1658
        obj[4] = ords;
1659

    
1660
        // String ind_str = printArray(indices);
1661
        // String ord_str = printArray(ords);
1662
        resp = new STRUCT(dsc, ((ConnectionJDBC)_conn).getConnection(), obj);
1663

    
1664
        return resp;
1665
    }
1666

    
1667
    public static String printArray(NUMBER[] array) {
1668
        String resp = "[ ";
1669

    
1670
        for (int i = 0; i < array.length; i++) {
1671
            resp = resp + " " + array[i].doubleValue() + " , ";
1672
        }
1673

    
1674
        resp = resp.substring(0, resp.length() - 2) + "]";
1675

    
1676
        return resp;
1677
    }
1678

    
1679
    private static boolean isOneOf(int ind, int[] list) {
1680
        for (int i = 0; i < list.length; i++) {
1681
            if (list[i] == ind) {
1682
                return true;
1683
            }
1684
        }
1685

    
1686
        return false;
1687
    }
1688

    
1689
    /**
1690
     * This method appends the geometries from a geometry collection in one STRUCT.
1691
     *
1692
     * @param co the geometry collection
1693
     * @param _forced_type a type that has to be used as the struct's main type
1694
     * @param _conn the connection
1695
     * @param _o_srid the geometry's SRS (oracle code)
1696
     * @param withSrid whether the SRS is non-NULL
1697
     * @param agu_bien whether to check holes' validity
1698
     * @param _isGeoCS whether the SRS is geodetic
1699
     * @return the STRUCT with the appended geometries
1700
     */
1701
    public static STRUCT appendGeometriesInStruct(FGeometryCollection co,
1702
        int _forced_type, IConnection _conn, String _o_srid, boolean withSrid,
1703
        boolean agu_bien, boolean _isGeoCS) {
1704
        IGeometry[] geoms = co.getGeometries();
1705
        int size = geoms.length;
1706
        STRUCT[] sts = new STRUCT[size];
1707

    
1708
        for (int i = 0; i < size; i++) {
1709
            sts[i] = OracleSpatialDriver.iGeometryToSTRUCT(geoms[i],
1710
                    _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
1711
        }
1712

    
1713
        if (size == 1) {
1714
            return sts[0];
1715
        }
1716

    
1717
        STRUCT aux = sts[0];
1718

    
1719
        for (int i = 1; i < size; i++) {
1720
            aux = appendStructs(aux, sts[i], _conn);
1721
        }
1722

    
1723
        return aux;
1724
    }
1725

    
1726
    private static STRUCT appendStructs(STRUCT st1, STRUCT st2, IConnection _conn) {
1727
        try {
1728
            ARRAY _ords = (ARRAY) st1.getOracleAttributes()[4];
1729
            int length_of_head_ords = _ords.getOracleArray().length;
1730

    
1731
            NUMBER gtype = new NUMBER(4 +
1732
                    (((NUMBER) st1.getOracleAttributes()[0]).intValue() / 1000));
1733
            NUMBER srid = (NUMBER) st1.getOracleAttributes()[1];
1734
            NUMBER middle = (NUMBER) st1.getOracleAttributes()[2];
1735

    
1736
            ARRAY info1 = (ARRAY) st1.getOracleAttributes()[3];
1737
            ARRAY info2 = (ARRAY) st2.getOracleAttributes()[3];
1738
            ARRAY ords1 = (ARRAY) st1.getOracleAttributes()[4];
1739
            ARRAY ords2 = (ARRAY) st2.getOracleAttributes()[4];
1740

    
1741
            Datum[] info = appendDatumArrays(info1.getOracleArray(),
1742
                    info2.getOracleArray(), length_of_head_ords);
1743

    
1744
            Datum[] ords = appendDatumArrays(ords1.getOracleArray(),
1745
                    ords2.getOracleArray(), 0);
1746

    
1747
            StructDescriptor dsc = st1.getDescriptor();
1748

    
1749
            Object[] atts = new Object[5];
1750
            atts[0] = gtype;
1751
            atts[1] = srid;
1752
            atts[2] = middle;
1753
            atts[3] = info;
1754
            atts[4] = ords;
1755

    
1756
            STRUCT resp = new STRUCT(dsc, ((ConnectionJDBC)_conn).getConnection(), atts);
1757

    
1758
            return resp;
1759
        }
1760
        catch (SQLException sqle) {
1761
            logger.error("While appending structs: " + sqle.getMessage(), sqle);
1762
        }
1763

    
1764
        return null;
1765
    }
1766

    
1767
    private static Datum[] appendDatumArrays(Datum[] head, Datum[] tail,
1768
        int offset) {
1769
        int head_l = head.length;
1770
        int tail_l = tail.length;
1771
        Datum[] resp = new Datum[head_l + tail_l];
1772

    
1773
        for (int i = 0; i < head_l; i++)
1774
            resp[i] = head[i];
1775

    
1776
        if (offset == 0) {
1777
            for (int i = 0; i < tail_l; i++)
1778
                resp[head_l + i] = tail[i];
1779
        }
1780
        else {
1781
            try {
1782
                for (int i = 0; i < tail_l; i++) {
1783
                    if ((i % 3) == 0) {
1784
                        resp[head_l + i] = new NUMBER(tail[i].intValue() +
1785
                                offset);
1786
                    }
1787
                    else {
1788
                        resp[head_l + i] = tail[i];
1789
                    }
1790
                }
1791
            }
1792
            catch (SQLException se) {
1793
                logger.error("Unexpected error: " + se.getMessage());
1794
            }
1795
        }
1796

    
1797
        return resp;
1798
    }
1799

    
1800
    /**
1801
     * Utility method to get an ineteger as a formatted string.
1802
     *
1803
     * @param n the integer
1804
     * @return the formatted string
1805
     */
1806
    public static String getFormattedInteger(int n) {
1807
        df.setGroupingUsed(true);
1808
        df.setGroupingSize(3);
1809
        dfs.setGroupingSeparator('.');
1810
        df.setDecimalFormatSymbols(dfs);
1811

    
1812
        return df.format(n);
1813
    }
1814

    
1815
    /**
1816
     * Tells whether these arrays belong to a rectangle polygon.
1817
     *
1818
     * @param info the struct's element info array
1819
     * @param ords the struct's coordinate array
1820
     * @return true if it is a rectangle polygon. false otherwise.
1821
     */
1822
    public static boolean polStructIsRectStruct(ARRAY info, ARRAY ords) {
1823
        try {
1824
            int[] infos = info.getIntArray();
1825

    
1826
            return ((infos[2] == 3) && (infos.length == 3));
1827
        }
1828
        catch (SQLException se) {
1829
            logger.error("While ckecking rectangle: " + se.getMessage(), se);
1830
        }
1831

    
1832
        return false;
1833
    }
1834

    
1835
    /**
1836
     * Utility method to deal with oracle info arrays.
1837
     */
1838
    public static ARRAY getDevelopedInfoArray(ARRAY info) {
1839
        ARRAY _resp = null;
1840

    
1841
        try {
1842
            Datum[] resp = new Datum[3];
1843
            Datum[] in = info.getOracleArray();
1844
            resp[0] = in[0];
1845
            resp[1] = in[1];
1846
            resp[2] = new NUMBER(1);
1847
            _resp = new ARRAY(info.getDescriptor(),
1848
                    info.getInternalConnection(), resp);
1849
        }
1850
        catch (SQLException se) {
1851
            logger.error("While creating ARRAY: " + se.getMessage(), se);
1852
        }
1853

    
1854
        return _resp;
1855
    }
1856

    
1857
    /**
1858
     * Utility method to deal with oracle coordinate arrays.
1859
     */
1860
    public static ARRAY getDevelopedOrdsArray(ARRAY ords) {
1861
        ARRAY _resp = null;
1862

    
1863
        try {
1864
            Datum[] resp = new Datum[10];
1865
            Datum[] corners = ords.getOracleArray();
1866

    
1867
            // x
1868
            resp[0] = corners[0];
1869
            resp[2] = corners[2];
1870
            resp[4] = corners[2];
1871
            resp[6] = corners[0];
1872
            resp[8] = corners[0];
1873

    
1874
            // y
1875
            resp[1] = corners[1];
1876
            resp[3] = corners[1];
1877
            resp[5] = corners[3];
1878
            resp[7] = corners[3];
1879
            resp[9] = corners[1];
1880
            _resp = new ARRAY(ords.getDescriptor(),
1881
                    ords.getInternalConnection(), resp);
1882
        }
1883
        catch (SQLException se) {
1884
            logger.error("While creating ARRAY: " + se.getMessage(), se);
1885
        }
1886

    
1887
        return _resp;
1888
    }
1889

    
1890
    /**
1891
     * utility method to convert a STRUCT into a GeneralPathX
1892
     * @param aux the struct's datum array
1893
     * @return the GeneralPathX instance created
1894
     */
1895
    public static GeneralPathX structToGPX(Datum[] aux) {
1896
        GeneralPathX resp = new GeneralPathX();
1897
        ARRAY infoARRAY = null;
1898
        ARRAY ordsARRAY = null;
1899
        Datum[] info_array = null;
1900
        Datum[] ords_array = null;
1901
        int info_array_size = 0;
1902
        int[] start_ind;
1903
        int[] end_ind;
1904
        int dims = 0;
1905
        boolean next_must_do_first = true;
1906

    
1907
        try {
1908
            infoARRAY = (ARRAY) aux[3];
1909
            ordsARRAY = (ARRAY) aux[4];
1910

    
1911
            if (polStructIsRectStruct(infoARRAY, ordsARRAY)) {
1912
                infoARRAY = getDevelopedInfoArray(infoARRAY);
1913
                ordsARRAY = getDevelopedOrdsArray(ordsARRAY);
1914
            }
1915

    
1916
            dims = ((NUMBER) aux[0]).intValue() / 1000;
1917

    
1918
            if (dims == 0) {
1919
                dims = 2;
1920
            }
1921

    
1922
            info_array = (Datum[]) infoARRAY.getOracleArray();
1923
            ords_array = (Datum[]) ordsARRAY.getOracleArray();
1924
            info_array_size = info_array.length / 3;
1925

    
1926
            if (info_array_size  > 1) {
1927
                    info_array_size++;
1928
                    info_array_size--;
1929
            } else {
1930
                    info_array_size++;
1931
                    info_array_size--;
1932
            }
1933

    
1934
            int last_index = ords_array.length - dims + 1;
1935

    
1936
            // set indices:
1937
            start_ind = new int[info_array_size];
1938
            end_ind = new int[info_array_size];
1939

    
1940
            for (int i = 0; i < info_array_size; i++)
1941
                start_ind[i] = ((NUMBER) info_array[3 * i]).intValue();
1942

    
1943
            for (int i = 0; i < (info_array_size - 1); i++)
1944
                end_ind[i] = start_ind[i + 1] - 1;
1945

    
1946
            end_ind[info_array_size - 1] = last_index;
1947

    
1948
            int lineType = PathIterator.SEG_LINETO;
1949

    
1950
            if (end_ind[0] == 0) { // collection of paths
1951

    
1952
                for (int i = 1; i < info_array_size; i++) {
1953
                    lineType = getLineToType(info_array, i);
1954

    
1955
                    // -----------------------
1956
                    if (end_ind[i] == (start_ind[i] - 1))
1957
                            lineType = PathIterator.SEG_MOVETO;
1958
                    // -----------------------
1959

    
1960
                    next_must_do_first = addOrdsToGPX(resp, start_ind[i] - 1,
1961
                            end_ind[i] - 1, ords_array, dims, lineType,
1962
                            (i == 1) || (lineType == PathIterator.SEG_MOVETO),
1963
                            next_must_do_first);
1964
                }
1965
            }
1966
            else {
1967
                // standard case, do the moveto always
1968
                for (int i = 0; i < info_array_size; i++) {
1969
                    lineType = getLineToType(info_array, i);
1970
                    addOrdsToGPX(resp, start_ind[i] - 1, end_ind[i] - 1,
1971
                        ords_array, dims, lineType, true, true);
1972
                }
1973
            }
1974

    
1975
            // boolean do_the_moves = true;
1976
        }
1977
        catch (SQLException se) {
1978
            logger.error("While creating GPX: " + se.getMessage(), se);
1979
        }
1980

    
1981
        return resp;
1982
    }
1983

    
1984
    private static int getLineToType(Datum[] infos, int i) {
1985
        int resp = PathIterator.SEG_LINETO;
1986

    
1987
        try {
1988
            if (((NUMBER) infos[(3 * i) + 2]).intValue() == 2) {
1989
                resp = PathIterator.SEG_QUADTO;
1990
            }
1991
        }
1992
        catch (SQLException e) {
1993
            logger.error("While getting line-to type: " + e.getMessage() +
1994
                " (returned SEG_LINETO)");
1995
        }
1996

    
1997
        return resp;
1998
    }
1999

    
2000
    private static boolean addOrdsToGPX(GeneralPathX gpx, int zero_based_start,
2001
        int zero_based_include_end, Datum[] ords, int d, int ltype,
2002
        boolean do_the_move, boolean must_do_first) {
2003
        int length = ords.length;
2004
        boolean return_following_must_do_first = true;
2005

    
2006
        double x = ((NUMBER) ords[zero_based_start]).doubleValue();
2007
        double y = ((NUMBER) ords[zero_based_start + 1]).doubleValue();
2008

    
2009
        if (must_do_first) {
2010
            if (do_the_move) {
2011
                gpx.moveTo(x, y);
2012
            }
2013
            else {
2014
                gpx.lineTo(x, y);
2015
            }
2016
        }
2017

    
2018
        int ind = 1;
2019

    
2020
        int size = ((zero_based_include_end - zero_based_start) / d) + 1;
2021
        int indx;
2022
        int indx2;
2023

    
2024
        if (ltype == PathIterator.SEG_QUADTO) { // (interpretation = 2)
2025

    
2026
            double x2;
2027
            double y2;
2028

    
2029
            while (ind < size) {
2030
                indx = zero_based_start + (ind * d);
2031
                x = ((NUMBER) ords[indx]).doubleValue();
2032
                y = ((NUMBER) ords[indx + 1]).doubleValue();
2033

    
2034
                indx2 = zero_based_start + ((ind + 1) * d);
2035

    
2036
                if (indx >= length) {
2037
                    indx2 = zero_based_start;
2038
                }
2039

    
2040
                x2 = ((NUMBER) ords[indx2]).doubleValue();
2041
                y2 = ((NUMBER) ords[indx2 + 1]).doubleValue();
2042
                gpx.quadTo(x, y, x2, y2);
2043
                ind++;
2044
                ind++;
2045
            }
2046

    
2047
            return_following_must_do_first = false;
2048
        }
2049
        else { // PathIterator.SEG_LINETO (interpretation = 1)
2050

    
2051
            while (ind < size) {
2052
                indx = zero_based_start + (ind * d);
2053
                x = ((NUMBER) ords[indx]).doubleValue();
2054
                y = ((NUMBER) ords[indx + 1]).doubleValue();
2055
                gpx.lineTo(x, y);
2056
                ind++;
2057
            }
2058
        }
2059

    
2060
        return return_following_must_do_first;
2061
    }
2062

    
2063
    /**
2064
     * Utility method. Gets FShape type from oracle geometry type.
2065
     * @param otype
2066
     * @return FShape type
2067
     */
2068
    public static int oracleGTypeToFShapeType(int otype) {
2069
        switch (otype) {
2070
        case ORACLE_GTYPE_UNKNOWN:
2071
            return FShape.NULL;
2072

    
2073
        case ORACLE_GTYPE_POINT:
2074
        case ORACLE_GTYPE_MULTIPOINT:
2075
            return FShape.POINT;
2076

    
2077
        case ORACLE_GTYPE_LINE:
2078
        case ORACLE_GTYPE_MULTILINE:
2079
            return FShape.LINE;
2080

    
2081
        case ORACLE_GTYPE_POLYGON:
2082
        case ORACLE_GTYPE_MULTIPOLYGON:
2083
            return FShape.POLYGON;
2084

    
2085
        case ORACLE_GTYPE_COLLECTION:
2086
            return FShape.MULTI;
2087
        }
2088

    
2089
        logger.warn("Unknown oracle geometry type: " + otype);
2090

    
2091
        return FShape.NULL;
2092
    }
2093

    
2094
    /**
2095
     * Utility method to get struct's type.
2096
     * @param the_data the struct's datum array
2097
     * @return the struct type
2098
     */
2099
    public static int getStructType(Datum[] the_data) {
2100
        int resp = -1;
2101

    
2102
        try {
2103
            resp = ((NUMBER) the_data[0]).intValue() % 1000;
2104
        }
2105
        catch (SQLException se) {
2106
            logger.error("Error: " + se.getMessage(), se);
2107
        }
2108

    
2109
        return resp;
2110
    }
2111

    
2112
    /**
2113
     * Utility method to get struct's SRID.
2114
     * @param the_data the struct's datum array
2115
     * @return the struct0's SRID
2116
     */
2117
    public static int getStructSRID(Datum[] the_data) {
2118
        int resp = -1;
2119

    
2120
        try {
2121
            resp = ((NUMBER) the_data[1]).intValue();
2122
        }
2123
        catch (SQLException se) {
2124
            logger.error("Error: " + se.getMessage(), se);
2125
        }
2126

    
2127
        return resp;
2128
    }
2129

    
2130
    /**
2131
     * Utility method to find out if  a struct is a circle.
2132
     *
2133
     * @param the_data the struct's datum array
2134
     * @return whether it is a circle
2135
     */
2136
    public static boolean isCircle(Datum[] the_data) {
2137
        int[] info = null;
2138

    
2139
        try {
2140
            info = ((ARRAY) the_data[3]).getIntArray();
2141
        }
2142
        catch (SQLException se) {
2143
            logger.error("While cheking circle: " + se.getMessage(), se);
2144

    
2145
            return false;
2146
        }
2147

    
2148
        if (info == null) {
2149
            return false;
2150
        }
2151

    
2152
        boolean resp = ((info.length == 3) && (info[2] == 4));
2153

    
2154
        return resp;
2155
    }
2156

    
2157
    /**
2158
     * Gets the struct's dimension size.
2159
     * @param st the struct
2160
     * @return the structs dimension
2161
     */
2162
    public static int getStructDimensions(STRUCT st) {
2163
        int resp = -1;
2164

    
2165
        try {
2166
            resp = ((NUMBER) st.getOracleAttributes()[0]).intValue() / 1000;
2167
        }
2168
        catch (SQLException se) {
2169
            logger.error("Error: " + se.getMessage(), se);
2170
        }
2171

    
2172
        if (resp < 2) {
2173
            resp = 2;
2174
        }
2175

    
2176
        return resp;
2177
    }
2178

    
2179
    /**
2180
     * Gets a struct's coordinates array.
2181
     * @param the_data the struct's datum array
2182
     * @return the coordinates array
2183
     */
2184
    public static double[] getOrds(Datum[] the_data) {
2185
        double[] resp = null;
2186

    
2187
        try {
2188
            ARRAY aux = (ARRAY) the_data[4];
2189

    
2190
            if (aux == null) {
2191
                return null;
2192
            }
2193

    
2194
            resp = aux.getDoubleArray();
2195
        }
2196
        catch (SQLException se) {
2197
            logger.error("While getting ordinates: " + se.getMessage(), se);
2198
        }
2199

    
2200
        return resp;
2201
    }
2202

    
2203
    /**
2204
     * Utility method to create a struct with the given data.
2205
     * @param type struct type
2206
     * @param srid coordinate system
2207
     * @param info element info array
2208
     * @param ords coordinates array
2209
     * @param conn connection
2210
     * @return the created struct
2211
     */
2212
    public static STRUCT createStruct(NUMBER type, NUMBER srid, Datum[] info,
2213
        Datum[] ords, Connection conn) {
2214
        try {
2215
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2216
                    conn);
2217
            Object[] obj = new Object[5];
2218
            obj[0] = type;
2219
            obj[1] = srid;
2220
            obj[2] = null;
2221
            obj[3] = info;
2222
            obj[4] = ords;
2223

    
2224
            return new STRUCT(dsc, conn, obj);
2225
        }
2226
        catch (SQLException se) {
2227
            logger.error("While creating STRUCT: " + se.getMessage(), se);
2228
        }
2229

    
2230
        return null;
2231
    }
2232

    
2233
    public static String getDimInfoAsString(ARRAY dim_info) {
2234
            String resp = "DIMENSIONS: ";
2235

    
2236
        if (dim_info == null) {
2237
            return "NULL" + "\n";
2238
        }
2239
        else {
2240
                try {
2241
                                Datum[] da = dim_info.getOracleArray();
2242
                                int size = da.length;
2243
                                resp = resp + size + "\n";
2244
                                for (int i = 0; i < size; i++) {
2245
                                        STRUCT dim_itemx = (STRUCT) da[i];
2246
                                        Object[] dim_desc = dim_itemx.getAttributes();
2247
                                        resp = resp + "DIMENSION " + i + ": " + ", NAME: "
2248
                                                        + dim_desc[0].toString() + ", MIN: "
2249
                                                        + dim_desc[1].toString() + ", MAX: "
2250
                                                        + dim_desc[2].toString() + ", TOL: "
2251
                                                        + dim_desc[3].toString();
2252
                                        if (i != (size -1)) {
2253
                                                resp = resp + "\n";
2254
                                        }
2255
                                }
2256
                        } catch (Exception ex) {
2257
                                return "ERROR: " + ex.getMessage() + "\n";
2258
                        }
2259
        }
2260
        return resp;
2261
    }
2262

    
2263
    public static STRUCT reprojectGeometry(IConnection conn, STRUCT fromStruct, String toSrid) {
2264

    
2265
            String qry = "SELECT SDO_CS.TRANSFORM( ?, " + toSrid + ") FROM DUAL";
2266
            STRUCT resp = null;
2267

    
2268
            try {
2269
                        PreparedStatement _st = ((ConnectionJDBC)conn).getConnection().prepareStatement(qry);
2270
                        _st.setObject(1, fromStruct);
2271
                        ResultSet _rs = _st.executeQuery();
2272

    
2273
                        if (_rs.next()) {
2274
                                resp = (STRUCT) _rs.getObject(1);
2275
                        } else {
2276
                                logger.error("While executing reprojection: empty resultset (?)");
2277
                                return fromStruct;
2278
                        }
2279
                } catch (Exception ex) {
2280
                        logger.error("While reprojecting: " + ex.getMessage());
2281
                        return fromStruct;
2282
                }
2283

    
2284
        if (resp == null) {
2285
                return fromStruct;
2286
        } else {
2287
                return resp;
2288
        }
2289
    }
2290

    
2291
}