Statistics
| Revision:

root / branches / v10 / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialUtils.java @ 13996

History | View | Annotate | Download (65.3 KB)

1 13991 jldominguez@prodevelop.es
/* 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 com.iver.cit.gvsig.fmap.core.FCircle2D;
46
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
47
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
48
import com.iver.cit.gvsig.fmap.core.FMultipoint3D;
49
import com.iver.cit.gvsig.fmap.core.FPoint2D;
50
import com.iver.cit.gvsig.fmap.core.FPoint3D;
51
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
52
import com.iver.cit.gvsig.fmap.core.FPolygon3D;
53
import com.iver.cit.gvsig.fmap.core.FPolyline3D;
54
import com.iver.cit.gvsig.fmap.core.FShape;
55
import com.iver.cit.gvsig.fmap.core.FShape3D;
56
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
57
import com.iver.cit.gvsig.fmap.core.IGeometry;
58
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
59
60
import com.vividsolutions.jts.algorithm.CGAlgorithms;
61
import com.vividsolutions.jts.geom.Coordinate;
62
import com.vividsolutions.jts.geom.CoordinateArrays;
63
import com.vividsolutions.jts.geom.Envelope;
64
import com.vividsolutions.jts.geom.GeometryFactory;
65
import com.vividsolutions.jts.geom.LineString;
66
import com.vividsolutions.jts.geom.LinearRing;
67
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
68
69
import oracle.sql.ARRAY;
70
import oracle.sql.Datum;
71
import oracle.sql.NUMBER;
72
import oracle.sql.STRUCT;
73
import oracle.sql.StructDescriptor;
74
75
import org.apache.log4j.Logger;
76
77
import java.awt.geom.PathIterator;
78
import java.awt.geom.Point2D;
79
import java.awt.geom.Rectangle2D;
80
81
import java.io.BufferedReader;
82
import java.io.File;
83
import java.io.FileReader;
84
85
import java.lang.reflect.Array;
86
87
import java.net.URL;
88
89
import java.sql.Connection;
90
import java.sql.PreparedStatement;
91
import java.sql.ResultSet;
92
import java.sql.SQLException;
93
import java.sql.Statement;
94
95
import java.text.DecimalFormat;
96
import java.text.DecimalFormatSymbols;
97
98
import java.util.ArrayList;
99
import java.util.Random;
100
101
102
/**
103
 * Utility class with static methods.
104
 *
105
 * @author jldominguez
106
 *
107
 */
108
public class OracleSpatialUtils {
109
    private static Logger logger = Logger.getLogger(OracleSpatialUtils.class.getName());
110
    private static double FLATNESS = 0.8;
111
    private static GeometryFactory geomFactory = new GeometryFactory();
112
    private static final double IRRELEVANT_DISTANCE = 0.00000001;
113
    private static Random rnd = new Random();
114
    private static DecimalFormat df = new DecimalFormat();
115
    private static DecimalFormatSymbols dfs = new DecimalFormatSymbols();
116
    public static final int ORACLE_GTYPE_UNKNOWN = 0;
117
    public static final int ORACLE_GTYPE_POINT = 1;
118
    public static final int ORACLE_GTYPE_LINE = 2;
119
    public static final int ORACLE_GTYPE_POLYGON = 3;
120
    public static final int ORACLE_GTYPE_COLLECTION = 4;
121
    public static final int ORACLE_GTYPE_MULTIPOINT = 5;
122
    public static final int ORACLE_GTYPE_MULTILINE = 6;
123
    public static final int ORACLE_GTYPE_MULTIPOLYGON = 7;
124
125
    /**
126
     * COnstructs a geometry from a file that contains a vertex per line:
127
     *
128
     * x1 y1 z1
129
     * x2 y2 z2
130
     * ...
131
     *
132
     * @param filepath vertices text file path
133
     * @param polygon whether it is a polygon or not
134
     * @return the created geometry
135
     */
136
    public static IGeometry readGeometry3D(URL filepath, boolean polygon) {
137
        GeneralPathX resp = new GeneralPathX();
138
        File file = new File(filepath.getFile());
139
        ArrayList z = new ArrayList();
140
141
        try {
142
            FileReader fr = new FileReader(file);
143
            BufferedReader br = new BufferedReader(fr);
144
            double[] coords = new double[3];
145
146
            boolean move = true;
147
148
            String line = br.readLine();
149
150
            while (line != null) {
151
                coords = parseLine(line);
152
153
                if (line.length() == 0) {
154
                    move = true;
155
                }
156
                else {
157
                    if (move) {
158
                        resp.moveTo(coords[0], coords[1]);
159
                        z.add(new Double(coords[2]));
160
                    }
161
                    else {
162
                        resp.lineTo(coords[0], coords[1]);
163
                        z.add(new Double(coords[2]));
164
                    }
165
166
                    move = false;
167
                }
168
169
                line = br.readLine();
170
            }
171
        }
172
        catch (Exception ex) {
173
            System.err.println("Error while creating GeneralPathX: " +
174
                ex.getMessage());
175
176
            return null;
177
        }
178
179
        double[] zz = new double[z.size()];
180
181
        for (int i = 0; i < z.size(); i++) {
182
            zz[i] = ((Double) z.get(i)).doubleValue();
183
        }
184
185
        if (polygon) {
186
            return ShapeFactory.createPolygon3D(resp, zz);
187
        }
188
        else {
189
            return ShapeFactory.createPolyline3D(resp, zz);
190
        }
191
    }
192
193
    private static double[] parseLine(String line) {
194
        String[] sep = line.split(" ");
195
        double[] resp = new double[3];
196
197
        for (int i = 0; i < 3; i++)
198
            resp[i] = 0.0;
199
200
        try {
201
            resp[0] = Double.parseDouble(sep[0]);
202
        }
203
        catch (Exception ex) {
204
        }
205
206
        if (sep.length > 1) {
207
            try {
208
                resp[1] = Double.parseDouble(sep[1]);
209
            }
210
            catch (Exception ex) {
211
            }
212
213
            if (sep.length > 2) {
214
                try {
215
                    resp[2] = Double.parseDouble(sep[2]);
216
                }
217
                catch (Exception ex) {
218
                }
219
            }
220
        }
221
222
        return resp;
223
    }
224
225
    /**
226
     * Utility method to convert a gvSIG FShape into a oracle struct
227
     *
228
     * @param fshp the FShape object
229
     * @param c the connection
230
     * @param srid the SRS (oarcle code)
231
     * @param agu_b whether to check holes validity
232
     * @param hasSrid whether the SRS is non-NULL
233
     * @return a oracle struct representing the geometry
234
     *
235
     * @throws SQLException
236
     */
237
    public static STRUCT fShapeToSTRUCT(Object fshp, Connection c, int srid,
238
        boolean agu_b, boolean hasSrid) throws SQLException {
239
        boolean three = false;
240
241
        if (fshp instanceof FShape3D) {
242
            three = true;
243
        }
244
245
        STRUCT resp = null;
246
247
        if (fshp instanceof FMultiPoint2D) {
248
            resp = multiPoint2DToStruct((FMultiPoint2D) fshp, c, srid, hasSrid);
249
250
            return resp;
251
        }
252
253
        if (!(fshp instanceof FShape)) {
254
            logger.error("Unknown geometry: " + fshp.toString());
255
256
            return null;
257
        }
258
259
        if (fshp instanceof FPoint2D) { // point 2/3d
260
261
            // resp = pointToWKT((FPoint2D) fshp, three);
262
            Coordinate p = getSingleCoordinate((FPoint2D) fshp);
263
            resp = getMultiPointAsStruct(p, srid, three, c, hasSrid);
264
        }
265
        else {
266
            if (fshp instanceof FPolygon2D) { // polygon 2/3d
267
268
                if (fshp instanceof FCircle2D) {
269
                    resp = getCircleAsStruct((FCircle2D) fshp, srid, c, hasSrid);
270
                }
271
                else {
272
                    // also FEllipse2D
273
                    resp = getMultiPolygonAsStruct((FShape) fshp, srid, three,
274
                            c, agu_b, hasSrid);
275
276
                    // ArrayList polys = getPolygonsEasily(fshp);
277
                    // resp = getMultiPolygonAsStruct(polys, srid, three, c);
278
                }
279
            }
280
            else { // line 2/3d
281
282
                ArrayList _lines = getLineStrings((FShape) fshp);
283
                resp = getMultiLineAsStruct(_lines, srid, three, c, hasSrid);
284
            }
285
        }
286
287
        return resp;
288
    }
289
290
    private static STRUCT multiPoint2DToStruct(FMultiPoint2D mp2d,
291
        Connection c, int srid, boolean hasSrid) throws SQLException {
292
        int np = mp2d.getNumPoints();
293
        boolean threed = (mp2d instanceof FMultipoint3D);
294
        int gtype = 2005;
295
        int dim = 2;
296
        FMultipoint3D mp3d = null;
297
298
        if (threed) {
299
            gtype = 3005;
300
            dim = 3;
301
            mp3d = (FMultipoint3D) mp2d;
302
        }
303
304
        NUMBER[] indices = new NUMBER[3];
305
        indices[0] = new NUMBER(1);
306
        indices[1] = new NUMBER(1);
307
        indices[2] = new NUMBER(np);
308
309
        NUMBER[] ords = new NUMBER[dim * np];
310
311
        for (int i = 0; i < np; i++) {
312
            ords[dim * i] = new NUMBER(mp2d.getPoint(i).getX());
313
            ords[(dim * i) + 1] = new NUMBER(mp2d.getPoint(i).getY());
314
315
            if (threed) {
316
                ords[(dim * i) + 2] = new NUMBER(mp3d.getZs()[i]);
317
            }
318
        }
319
320
        STRUCT resp;
321
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
322
                c);
323
        Object[] obj = new Object[5];
324
        obj[0] = new NUMBER(gtype);
325
326
        if (hasSrid) {
327
            obj[1] = new NUMBER(srid);
328
        }
329
        else { // , boolean hasSrid
330
            obj[1] = null;
331
        }
332
333
        obj[2] = null;
334
        obj[3] = indices;
335
        obj[4] = ords;
336
        resp = new STRUCT(dsc, c, obj);
337
338
        return resp;
339
    }
340
341
    private static STRUCT getCircleAsStruct(FCircle2D fcirc, int srid,
342
        Connection _conn, boolean hasSrid) throws SQLException {
343
        int geotype = 2003;
344
        NUMBER[] indices = new NUMBER[3];
345
        indices[0] = new NUMBER(1);
346
        indices[1] = new NUMBER(1003);
347
        indices[2] = new NUMBER(4);
348
349
        NUMBER[] ords = new NUMBER[6];
350
        Coordinate[] three_points = getThreePointsOfCircumference(fcirc.getCenter(),
351
                fcirc.getRadio());
352
353
        for (int i = 0; i < three_points.length; i++) {
354
            ords[i * 2] = new NUMBER(three_points[i].x);
355
            ords[(i * 2) + 1] = new NUMBER(three_points[i].y);
356
        }
357
358
        STRUCT resp;
359
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
360
                _conn);
361
        Object[] obj = new Object[5];
362
        obj[0] = new NUMBER(geotype);
363
364
        if (hasSrid) {
365
            obj[1] = new NUMBER(srid);
366
        }
367
        else {
368
            obj[1] = null;
369
        }
370
371
        obj[2] = null;
372
        obj[3] = indices;
373
        obj[4] = ords;
374
        resp = new STRUCT(dsc, _conn, obj);
375
376
        return resp;
377
    }
378
379
    private static Coordinate[] getThreePointsOfCircumference(Point2D cntr,
380
        double radius) {
381
        Coordinate[] resp = new Coordinate[3];
382
        double x;
383
        double y;
384
        double alpha = 0;
385
386
        for (int i = 0; i < 3; i++) {
387
            alpha = (i * 120.0 * Math.PI) / 180.0;
388
            x = cntr.getX() + (radius * Math.cos(alpha));
389
            y = cntr.getY() + (radius * Math.sin(alpha));
390
            resp[i] = new Coordinate(x, y);
391
        }
392
393
        return resp;
394
    }
395
396
    private static Coordinate getSingleCoordinate(FPoint2D p2d) {
397
        // TODO Auto-generated method stub
398
        Coordinate resp = new Coordinate();
399
        resp.x = p2d.getX();
400
        resp.y = p2d.getY();
401
402
        if (p2d instanceof FPoint3D) {
403
            resp.z = ((FPoint3D) p2d).getZs()[0];
404
        }
405
406
        return resp;
407
    }
408
409
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
410
        if (cc.size() == 2) {
411
            if (sameCoordinate((Coordinate) cc.get(0),
412
                        (Coordinate) cc.get(cc.size() - 1))) {
413
                ArrayList resp = new ArrayList();
414
                resp.add(cc.get(0));
415
416
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
417
                newc.x = newc.x + IRRELEVANT_DISTANCE;
418
                resp.add(newc);
419
420
                return resp;
421
            }
422
        }
423
424
        return cc;
425
    }
426
427
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
428
        if (c1.x != c2.x) {
429
            return false;
430
        }
431
432
        if (c1.y != c2.y) {
433
            return false;
434
        }
435
436
        return true;
437
    }
438
439
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
440
        if (cc.size() == 2) {
441
            return getMinClosedCoords((Coordinate) cc.get(0));
442
        }
443
444
        if (cc.size() == 3) {
445
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
446
                return getMinClosedCoords((Coordinate) cc.get(0));
447
            }
448
449
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
450
                return getMinClosedCoords((Coordinate) cc.get(0));
451
            }
452
453
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
454
                return getMinClosedCoords((Coordinate) cc.get(1));
455
            }
456
457
            cc.add(cc.get(0));
458
459
            return cc;
460
        }
461
462
        if (!sameCoordinate((Coordinate) cc.get(0),
463
                    (Coordinate) cc.get(cc.size() - 1))) {
464
            cc.add(cc.get(0));
465
        }
466
467
        return cc;
468
    }
469
470
    private static ArrayList getMinClosedCoords(Coordinate c) {
471
        ArrayList resp = new ArrayList();
472
        resp.add(c);
473
474
        Coordinate nc = new Coordinate(c);
475
        nc.x = nc.x + IRRELEVANT_DISTANCE;
476
        resp.add(nc);
477
478
        Coordinate nc2 = new Coordinate(nc);
479
        nc2.y = nc2.y + IRRELEVANT_DISTANCE;
480
        resp.add(nc2);
481
482
        resp.add(new Coordinate(c));
483
484
        return resp;
485
    }
486
487
    private static LinearRing getMinLinearRing(Coordinate c) {
488
        Coordinate[] p = new Coordinate[4];
489
        p[0] = c;
490
491
        Coordinate nc = new Coordinate(c);
492
        nc.x = nc.x + IRRELEVANT_DISTANCE;
493
494
        Coordinate nc2 = new Coordinate(nc);
495
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
496
        p[1] = nc;
497
        p[2] = nc2;
498
        p[3] = new Coordinate(c);
499
500
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
501
        LinearRing ls = new LinearRing(cs, geomFactory);
502
503
        return ls;
504
    }
505
506
    private static double[] getMinLinearRingZ() {
507
        double[] resp = new double[4];
508
509
        for (int i = 0; i < 4; i++)
510
            resp[i] = 0.0;
511
512
        return resp;
513
    }
514
515
    private static boolean pointInList(Coordinate testPoint,
516
        Coordinate[] pointList) {
517
        int t;
518
        int numpoints;
519
        Coordinate p;
520
521
        numpoints = Array.getLength(pointList);
522
523
        for (t = 0; t < numpoints; t++) {
524
            p = pointList[t];
525
526
            if ((testPoint.x == p.x) && (testPoint.y == p.y) &&
527
                    ((testPoint.z == p.z) || (!(testPoint.z == testPoint.z))) //nan test; x!=x iff x is nan
528
            ) {
529
                return true;
530
            }
531
        }
532
533
        return false;
534
    }
535
536
    private static ArrayList getPolygonsEasily(FShape mpolygon) {
537
        boolean threed = false;
538
539
        if (mpolygon instanceof FPolygon3D) {
540
            threed = true;
541
        }
542
543
        int start_ind = 0;
544
        int end_ind = 0;
545
        int ind = 0;
546
        int new_size;
547
        ArrayList arrayCoords = null;
548
        ArrayList resp = new ArrayList();
549
        Coordinate[] points = null;
550
        int theType = -99;
551
        double[] theData = new double[6];
552
        Coordinate onlyCoord = null;
553
        int numParts = 0;
554
555
        PathIterator theIterator = mpolygon.getPathIterator(null, FLATNESS);
556
557
        while (!theIterator.isDone()) {
558
            //while not done
559
            theType = theIterator.currentSegment(theData);
560
561
            if (onlyCoord == null) {
562
                onlyCoord = new Coordinate();
563
                onlyCoord.x = theData[0];
564
                onlyCoord.y = theData[1];
565
            }
566
567
            switch (theType) {
568
            case PathIterator.SEG_MOVETO:
569
570
                if (arrayCoords == null) {
571
                    arrayCoords = new ArrayList();
572
                }
573
                else {
574
                    end_ind = ind - 1;
575
576
                    arrayCoords = getClosedRelevantPolygon(arrayCoords);
577
                    new_size = arrayCoords.size();
578
579
                    if (arrayCoords != null) {
580
                        points = CoordinateArrays.toCoordinateArray(arrayCoords);
581
582
                        try {
583
                            LinearRing aux = geomFactory.createLinearRing(points);
584
                            double[] z = null;
585
586
                            if (threed) {
587
                                z = getZ((FPolygon3D) mpolygon, start_ind,
588
                                        end_ind, new_size);
589
                            }
590
591
                            LineString3D ring = new LineString3D(aux, z);
592
593
                            if (CGAlgorithms.isCCW(points)) {
594
                                resp.add(ring);
595
                            }
596
                            else {
597
                                resp.add(ring.createReverse());
598
                            }
599
                        }
600
                        catch (Exception e) {
601
                            System.err.println("Topology exception: " +
602
                                e.getMessage());
603
604
                            return null;
605
                        }
606
                    }
607
608
                    arrayCoords = new ArrayList();
609
610
                    start_ind = ind;
611
                }
612
613
                numParts++;
614
615
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
616
                ind++;
617
618
                break;
619
620
            case PathIterator.SEG_LINETO:
621
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
622
                ind++;
623
624
                break;
625
626
            case PathIterator.SEG_QUADTO:
627
                System.out.println("SEG_QUADTO Not supported here");
628
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
629
                arrayCoords.add(new Coordinate(theData[2], theData[3]));
630
                ind++;
631
                ind++;
632
633
                break;
634
635
            case PathIterator.SEG_CUBICTO:
636
                System.out.println("SEG_CUBICTO Not supported here");
637
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
638
                arrayCoords.add(new Coordinate(theData[2], theData[3]));
639
                arrayCoords.add(new Coordinate(theData[4], theData[5]));
640
                ind++;
641
                ind++;
642
                ind++;
643
644
                break;
645
646
            case PathIterator.SEG_CLOSE:
647
648
                // Coordinate firstCoord = (Coordinate) arrayCoords.get(0);
649
                // arrayCoords.add(new Coordinate(firstCoord.x, firstCoord.y));
650
                break;
651
            } //end switch
652
653
            theIterator.next();
654
        } //end while loop
655
656
        end_ind = ind - 1;
657
658
        // null shape:
659
        if (arrayCoords == null) {
660
            arrayCoords = new ArrayList();
661
662
            Coordinate _c = new Coordinate(0, 0, 0);
663
            arrayCoords.add(new Coordinate(_c));
664
            arrayCoords.add(new Coordinate(_c));
665
        }
666
667
        // --------------------------------------------
668
        arrayCoords = getClosedRelevantPolygon(arrayCoords);
669
        new_size = arrayCoords.size();
670
671
        if (arrayCoords != null) {
672
            points = CoordinateArrays.toCoordinateArray(arrayCoords);
673
674
            try {
675
                LinearRing aux = geomFactory.createLinearRing(points);
676
                double[] z = null;
677
678
                if (threed) {
679
                    z = getZ((FPolygon3D) mpolygon, start_ind, end_ind, new_size);
680
                }
681
682
                LineString3D ring = new LineString3D(aux, z);
683
684
                if (CGAlgorithms.isCCW(points)) {
685
                    resp.add(ring);
686
                }
687
                else {
688
                    resp.add(ring.createReverse());
689
                }
690
            }
691
            catch (Exception e) {
692
                System.err.println("Topology exception: " + e.getMessage());
693
694
                return null;
695
            }
696
        }
697
698
        if (resp.size() == 0) {
699
            resp.add(new LineString3D(getMinLinearRing(onlyCoord),
700
                    getMinLinearRingZ()));
701
        }
702
703
        return resp;
704
    }
705
706
    /**
707
     * Utility method to reverse an array of doubles.
708
     *
709
     * @param _z an array of doubles to be reversed.
710
     *
711
     * @return the reversed array of doubles
712
     */
713
    public static double[] reverseArray(double[] _z) {
714
        int size = _z.length;
715
        double[] resp = new double[size];
716
717
        for (int i = 0; i < size; i++) {
718
            resp[i] = _z[size - 1 - i];
719
        }
720
721
        return resp;
722
    }
723
724
    /**
725
     * Utility method to reverse an array of coordinates
726
     *
727
     * @param _z an array of coordinaes to be reversed.
728
     *
729
     * @return the reversed array of coordinates
730
     */
731
    public static Coordinate[] reverseCoordinateArray(Coordinate[] _z) {
732
        int size = _z.length;
733
        Coordinate[] resp = new Coordinate[size];
734
735
        for (int i = 0; i < size; i++) {
736
            resp[i] = _z[size - 1 - i];
737
        }
738
739
        return resp;
740
    }
741
742
    private static double[] getZ(FShape3D p3d, int _str, int _end, int size) {
743
        double[] resp = new double[size];
744
        double[] allz = p3d.getZs();
745
746
        for (int i = _str; ((i <= _end) && ((i - _str) < size)); i++) {
747
            resp[i - _str] = allz[i];
748
        }
749
750
        if ((_end - _str + 1) < size) {
751
            double repe = allz[_end];
752
753
            for (int i = (_end - _str + 1); i < size; i++) {
754
                resp[i] = repe;
755
            }
756
        }
757
758
        return resp;
759
    }
760
761
    private static ArrayList getLineStrings(FShape mlines) {
762
        boolean threed = false;
763
764
        if (mlines instanceof FPolyline3D) {
765
            threed = true;
766
        }
767
768
        int start_ind = 0;
769
        int end_ind = 0;
770
        int ind = 0;
771
        int new_size = 0;
772
773
        LineString3D lin;
774
775
        ArrayList arrayLines = new ArrayList();
776
        PathIterator theIterator = mlines.getPathIterator(null, FLATNESS);
777
        int theType = -99;
778
        double[] theData = new double[6];
779
        ArrayList arrayCoords = null;
780
        int numParts = 0;
781
782
        while (!theIterator.isDone()) {
783
            //while not done
784
            theType = theIterator.currentSegment(theData);
785
786
            switch (theType) {
787
            case PathIterator.SEG_MOVETO:
788
789
                // System.out.println("SEG_MOVETO");
790
                if (arrayCoords == null) {
791
                    arrayCoords = new ArrayList();
792
                }
793
                else {
794
                    end_ind = ind - 1;
795
                    arrayCoords = ensureSensibleLineString(arrayCoords);
796
                    new_size = arrayCoords.size();
797
798
                    LineString aux = geomFactory.createLineString(CoordinateArrays.toCoordinateArray(
799
                                arrayCoords));
800
                    double[] z = null;
801
802
                    if (threed) {
803
                        z = getZ((FPolyline3D) mlines, start_ind, end_ind,
804
                                new_size);
805
                    }
806
807
                    lin = new LineString3D(aux, z);
808
                    arrayLines.add(lin);
809
                    arrayCoords = new ArrayList();
810
811
                    start_ind = ind;
812
                }
813
814
                numParts++;
815
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
816
817
                break;
818
819
            case PathIterator.SEG_LINETO:
820
                arrayCoords.add(new Coordinate(theData[0], theData[1]));
821
822
                break;
823
824
            case PathIterator.SEG_QUADTO:
825
                System.out.println("Not supported here");
826
827
                break;
828
829
            case PathIterator.SEG_CUBICTO:
830
                System.out.println("Not supported here");
831
832
                break;
833
834
            case PathIterator.SEG_CLOSE:
835
836
                Coordinate firstCoord = (Coordinate) arrayCoords.get(0);
837
                arrayCoords.add(new Coordinate(firstCoord.x, firstCoord.y));
838
839
                break;
840
            } //end switch
841
842
            theIterator.next();
843
            ind++;
844
        } //end while loop
845
846
        arrayCoords = ensureSensibleLineString(arrayCoords);
847
        new_size = arrayCoords.size();
848
849
        LineString aux = geomFactory.createLineString(CoordinateArrays.toCoordinateArray(
850
                    arrayCoords));
851
        double[] z = null;
852
853
        if (threed) {
854
            z = getZ((FPolyline3D) mlines, start_ind, end_ind, new_size);
855
        }
856
857
        lin = new LineString3D(aux, z);
858
        arrayLines.add(lin);
859
860
        return arrayLines;
861
    }
862
863
    private static String lineStringToWKT(LineString3D ls, boolean threed) {
864
        String resp = "(";
865
        Coordinate[] cc = ls.getLs().getCoordinates();
866
        double[] z = ls.getZc();
867
        int size = cc.length;
868
869
        if (threed) {
870
            for (int i = 0; i < size; i++) {
871
                resp = resp + cc[i].x + " " + cc[i].y + " " + z[i] + ", ";
872
            }
873
874
            resp = resp.substring(0, resp.length() - 2);
875
            resp = resp + ")";
876
        }
877
        else {
878
            for (int i = 0; i < size; i++) {
879
                resp = resp + cc[i].x + " " + cc[i].y + ", ";
880
            }
881
882
            resp = resp.substring(0, resp.length() - 2);
883
            resp = resp + ")";
884
        }
885
886
        return resp;
887
    }
888
889
    private static String multiLineStringToWKT(ArrayList ml, boolean threed) {
890
        String resp = "MULTILINESTRING(";
891
892
        for (int i = 0; i < ml.size(); i++) {
893
            LineString3D ls = (LineString3D) ml.get(i);
894
            resp = resp + lineStringToWKT(ls, threed) + ", ";
895
        }
896
897
        resp = resp.substring(0, resp.length() - 2) + ")";
898
899
        return resp;
900
    }
901
902
    private static String polygonsToWKT(ArrayList pols, boolean threed) {
903
        String resp = "MULTIPOLYGON(";
904
        LineString3D ls = null;
905
906
        for (int i = 0; i < pols.size(); i++) {
907
            ls = (LineString3D) pols.get(i);
908
            resp = resp + "(" + lineStringToWKT(ls, threed) + "), ";
909
        }
910
911
        resp = resp.substring(0, resp.length() - 2) + ")";
912
913
        return resp;
914
    }
915
916
    private static String shellAndHolesToWKT(LineString3D shell,
917
        ArrayList holes, boolean threed) {
918
        String resp = "(";
919
        resp = resp + lineStringToWKT(shell, threed);
920
921
        if (holes.size() > 0) {
922
            for (int i = 0; i < holes.size(); i++) {
923
                LineString3D ls = (LineString3D) holes.get(i);
924
                resp = resp + ", " + lineStringToWKT(ls, threed);
925
            }
926
        }
927
928
        resp = resp + ")";
929
930
        return resp;
931
    }
932
933
    private static String multiPolygonToWKT(ArrayList shells, ArrayList hFs,
934
        boolean threed) {
935
        String resp = "MULTIPOLYGON(";
936
        LineString3D ls = null;
937
        ArrayList holes;
938
939
        for (int i = 0; i < shells.size(); i++) {
940
            ls = (LineString3D) shells.get(i);
941
            holes = (ArrayList) hFs.get(i);
942
            resp = resp + shellAndHolesToWKT(ls, holes, threed) + ", ";
943
        }
944
945
        resp = resp.substring(0, resp.length() - 2) + ")";
946
947
        return resp;
948
    }
949
950
    private static String pointToWKT(FPoint2D point, boolean threed) {
951
        String resp = "POINT(" + point.getX() + " " + point.getY();
952
953
        if ((threed) && (point instanceof FPoint3D)) {
954
            resp = resp + " " + ((FPoint3D) point).getZs()[0];
955
        }
956
957
        resp = resp + ")";
958
959
        return resp;
960
    }
961
962
    private static int twoDIndexToDimsIndex(int n, int d) {
963
        return ((d * (n - 1)) / 2) + 1;
964
    }
965
966
    private static ARRAY setSubelementsToDim(ARRAY old, int d)
967
        throws SQLException {
968
        Datum[] infos = (Datum[]) old.getOracleArray();
969
970
        for (int i = 3; i < infos.length; i = i + 3) {
971
            int oldind = infos[i].intValue();
972
            oldind = twoDIndexToDimsIndex(oldind, d);
973
            infos[i] = new NUMBER(oldind);
974
975
            //
976
            oldind = infos[i + 1].intValue();
977
            infos[i + 1] = new NUMBER(infos[1].intValue());
978
        }
979
980
        ARRAY resp = new ARRAY(old.getDescriptor(), old.getOracleConnection(),
981
                infos);
982
983
        return resp;
984
    }
985
986
    private static boolean isPointInsideLineString(Coordinate p, LineString ls) {
987
        Envelope env = ls.getEnvelopeInternal();
988
989
        if (!env.contains(p)) {
990
            return false;
991
        }
992
993
        return CGAlgorithms.isPointInRing(p, ls.getCoordinates());
994
    }
995
996
    private static boolean lineString3DIsContainedBy(LineString3D contained,
997
        LineString3D container) {
998
        int samples = 10;
999
        LineString _in = contained.getLs();
1000
        LineString _out = container.getLs();
1001
        Coordinate[] inc = _in.getCoordinates();
1002
        Coordinate aux;
1003
        int size = inc.length;
1004
1005
        if (size <= 10) {
1006
            for (int i = 0; i < size; i++) {
1007
                aux = inc[i];
1008
1009
                if (!isPointInsideLineString(aux, _out)) {
1010
                    return false;
1011
                }
1012
            }
1013
1014
            return true;
1015
        }
1016
        else {
1017
            for (int i = 0; i < samples; i++) {
1018
                aux = inc[rnd.nextInt(size)];
1019
1020
                if (!isPointInsideLineString(aux, _out)) {
1021
                    return false;
1022
                }
1023
            }
1024
1025
            return true;
1026
        }
1027
    }
1028
1029
    private static STRUCT getMultiPolygonAsStruct(ArrayList pols, int srid,
1030
        boolean threed, Connection _conn, boolean agu_bien, boolean hasSrid)
1031
        throws SQLException {
1032
        int size = pols.size();
1033
        int geotype = 2007;
1034
        int dim = 2;
1035
        int acum = 0;
1036
1037
        if (threed) {
1038
            geotype = 3007;
1039
            dim = 3;
1040
        }
1041
1042
        NUMBER[] indices = new NUMBER[3 * size];
1043
1044
        for (int i = 0; i < size; i++) {
1045
            indices[3 * i] = new NUMBER(acum + 1);
1046
            indices[(3 * i) + 1] = new NUMBER(1003);
1047
            indices[(3 * i) + 2] = new NUMBER(1);
1048
            acum = acum +
1049
                (dim * ((LineString3D) pols.get(i)).getLs().getNumPoints());
1050
        }
1051
1052
        int _ind = 0;
1053
        NUMBER[] ords = new NUMBER[acum];
1054
1055
        for (int i = 0; i < size; i++) {
1056
            LineString3D ls = (LineString3D) pols.get(i);
1057
            int num_p = ls.getLs().getNumPoints();
1058
1059
            for (int j = 0; j < num_p; j++) {
1060
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1061
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1062
1063
                if (threed) {
1064
                    ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1065
                }
1066
1067
                _ind = _ind + dim;
1068
            }
1069
        }
1070
1071
        STRUCT resp;
1072
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1073
                _conn);
1074
        Object[] obj = new Object[5];
1075
        obj[0] = new NUMBER(geotype);
1076
1077
        if (hasSrid) {
1078
            obj[1] = new NUMBER(srid);
1079
        }
1080
        else {
1081
            obj[1] = null;
1082
        }
1083
1084
        obj[2] = null;
1085
        obj[3] = indices;
1086
        obj[4] = ords;
1087
        resp = new STRUCT(dsc, _conn, obj);
1088
1089
        return resp;
1090
    }
1091
1092
    private static STRUCT getMultiLineAsStruct(ArrayList lines, int srid,
1093
        boolean threed, Connection _conn, boolean hasSrid)
1094
        throws SQLException {
1095
        /*
1096
        if (lines.size() == 1) {
1097
                return getOneLineStringAsStruct((LineString3D) lines.get(0), srid, threed, _conn);
1098
        }
1099
        */
1100
        int size = lines.size();
1101
        int geotype = 2006;
1102
        int dim = 2;
1103
        int acum = 0;
1104
1105
        if (threed) {
1106
            geotype = 3006;
1107
            dim = 3;
1108
        }
1109
1110
        NUMBER[] indices = new NUMBER[3 * size];
1111
1112
        for (int i = 0; i < size; i++) {
1113
            indices[3 * i] = new NUMBER(acum + 1);
1114
            indices[(3 * i) + 1] = new NUMBER(2);
1115
            indices[(3 * i) + 2] = new NUMBER(1);
1116
            acum = acum +
1117
                (dim * ((LineString3D) lines.get(i)).getLs().getNumPoints());
1118
        }
1119
1120
        int _ind = 0;
1121
        NUMBER[] ords = new NUMBER[acum];
1122
1123
        for (int i = 0; i < size; i++) {
1124
            LineString3D ls = (LineString3D) lines.get(i);
1125
            int num_p = ls.getLs().getNumPoints();
1126
1127
            for (int j = 0; j < num_p; j++) {
1128
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1129
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1130
1131
                if (threed) {
1132
                    ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1133
                }
1134
1135
                _ind = _ind + dim;
1136
            }
1137
        }
1138
1139
        STRUCT resp;
1140
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1141
                _conn);
1142
        Object[] obj = new Object[5];
1143
        obj[0] = new NUMBER(geotype);
1144
1145
        if (hasSrid) {
1146
            obj[1] = new NUMBER(srid);
1147
        }
1148
        else {
1149
            obj[1] = null;
1150
        }
1151
1152
        obj[2] = null;
1153
        obj[3] = indices;
1154
        obj[4] = ords;
1155
        resp = new STRUCT(dsc, _conn, obj);
1156
1157
        return resp;
1158
    }
1159
1160
    private static STRUCT getMultiPointAsStruct(Coordinate pnt, int srid,
1161
        boolean threed, Connection _conn, boolean hasSrid)
1162
        throws SQLException {
1163
        int geotype = 2001;
1164
        int dim = 2;
1165
1166
        if (threed) {
1167
            geotype = 3001;
1168
            dim = 3;
1169
        }
1170
1171
        Object[] ords = new Object[3];
1172
        ords[0] = new NUMBER(pnt.x);
1173
        ords[1] = new NUMBER(pnt.y);
1174
        ords[2] = (dim == 3) ? new NUMBER(pnt.z) : null; // ole ole y ole
1175
1176
        StructDescriptor ord_dsc = StructDescriptor.createDescriptor("MDSYS.SDO_POINT_TYPE",
1177
                _conn);
1178
        STRUCT ords_st = new STRUCT(ord_dsc, _conn, ords);
1179
1180
        STRUCT resp;
1181
1182
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1183
                _conn);
1184
        Object[] obj = new Object[5];
1185
1186
        obj[0] = new NUMBER(geotype);
1187
1188
        if (hasSrid) {
1189
            obj[1] = new NUMBER(srid);
1190
        }
1191
        else {
1192
            obj[1] = null;
1193
        }
1194
1195
        obj[2] = ords_st;
1196
        obj[3] = null;
1197
        obj[4] = null;
1198
        resp = new STRUCT(dsc, _conn, obj);
1199
1200
        return resp;
1201
    }
1202
1203
    /**
1204
     * Utility method to compute a circle's center and radius from three given points.
1205
     *
1206
     * @param points three points of a circumference
1207
     * @return a 2-item array with the circumference's center (Point2D) and radius (Double)
1208
     */
1209
    public static Object[] getCenterAndRadiousOfCirc(Point2D[] points) {
1210
        Object[] resp = new Object[2];
1211
        resp[0] = new Point2D.Double(0, 0);
1212
        resp[1] = new Double(0);
1213
1214
        double m11;
1215
        double m12;
1216
        double m13;
1217
        double m14;
1218
1219
        if (points.length != 3) {
1220
            logger.error("Needs 3 points (found " + points.length +
1221
                ") - circle cannot be computed.");
1222
1223
            // not a circle
1224
            return resp;
1225
        }
1226
1227
        double[][] a = new double[3][3];
1228
1229
        for (int i = 0; i < 3; i++) { // find minor 11
1230
            a[i][0] = points[i].getX();
1231
            a[i][1] = points[i].getY();
1232
            a[i][2] = 1;
1233
        }
1234
1235
        m11 = determinant(a, 3);
1236
1237
        for (int i = 0; i < 3; i++) { // find minor 12
1238
            a[i][0] = (points[i].getX() * points[i].getX()) +
1239
                (points[i].getY() * points[i].getY());
1240
            a[i][1] = points[i].getY();
1241
            a[i][2] = 1;
1242
        }
1243
1244
        m12 = determinant(a, 3);
1245
1246
        for (int i = 0; i < 3; i++) // find minor 13
1247
         {
1248
            a[i][0] = (points[i].getX() * points[i].getX()) +
1249
                (points[i].getY() * points[i].getY());
1250
            a[i][1] = points[i].getX();
1251
            a[i][2] = 1;
1252
        }
1253
1254
        m13 = determinant(a, 3);
1255
1256
        for (int i = 0; i < 3; i++) { // find minor 14
1257
            a[i][0] = (points[i].getX() * points[i].getX()) +
1258
                (points[i].getY() * points[i].getY());
1259
            a[i][1] = points[i].getX();
1260
            a[i][2] = points[i].getY();
1261
        }
1262
1263
        m14 = determinant(a, 3);
1264
1265
        Double resp_radius = new Double(0);
1266
        Point2D resp_center = new Point2D.Double(0, 0);
1267
1268
        if (m11 == 0) {
1269
            logger.error("Three points aligned - circle cannot be computed."); // not a circle
1270
        }
1271
        else {
1272
            double x = (0.5 * m12) / m11;
1273
            double y = (-0.5 * m13) / m11;
1274
            resp_center.setLocation(x, y);
1275
            resp_radius = new Double(Math.sqrt((x * x) + (y * y) + (m14 / m11)));
1276
            resp[0] = resp_center;
1277
            resp[1] = resp_radius;
1278
        }
1279
1280
        return resp;
1281
    }
1282
1283
    /**
1284
     * Utility method to compute a matrix determinant
1285
     * @param a the matrix
1286
     * @param n matrix size
1287
     * @return the matrix's determinant
1288
     */
1289
    public static double determinant(double[][] a, int n) {
1290
        double resp = 0;
1291
        double[][] m = new double[3][3];
1292
1293
        if (n == 2) { // terminate recursion
1294
            resp = (a[0][0] * a[1][1]) - (a[1][0] * a[0][1]);
1295
        }
1296
        else {
1297
            resp = 0;
1298
1299
            for (int j1 = 0; j1 < n; j1++) { // do each column
1300
1301
                for (int i = 1; i < n; i++) { // create minor
1302
1303
                    int j2 = 0;
1304
1305
                    for (int j = 0; j < n; j++) {
1306
                        if (j == j1) {
1307
                            continue;
1308
                        }
1309
1310
                        m[i - 1][j2] = a[i][j];
1311
                        j2++;
1312
                    }
1313
                }
1314
1315
                // sum (+/-)cofactor * minor
1316
                resp = resp +
1317
                    (Math.pow(-1.0, j1) * a[0][j1] * determinant(m, n - 1));
1318
            }
1319
        }
1320
1321
        return resp;
1322
    }
1323
1324
    private static int getSmallestContainerExcept(LineString3D ls,
1325
        ArrayList list, int self) {
1326
        int resp = -1;
1327
        ArrayList provList = new ArrayList();
1328
1329
        int size = list.size();
1330
1331
        for (int i = 0; i < self; i++) {
1332
            if (lineString3DIsContainedBy(ls, (LineString3D) list.get(i))) {
1333
                provList.add(new Integer(i));
1334
            }
1335
        }
1336
1337
        for (int i = (self + 1); i < size; i++) {
1338
            if (lineString3DIsContainedBy(ls, (LineString3D) list.get(i))) {
1339
                provList.add(new Integer(i));
1340
            }
1341
        }
1342
1343
        if (provList.size() == 0) {
1344
            // logger.debug("LineString is not contained by any other ls.");
1345
        }
1346
        else {
1347
            if (provList.size() == 1) {
1348
                resp = ((Integer) provList.get(0)).intValue();
1349
            }
1350
            else {
1351
                if (provList.size() == 2) {
1352
                    int ind_1 = ((Integer) provList.get(0)).intValue();
1353
                    int ind_2 = ((Integer) provList.get(1)).intValue();
1354
                    LineString3D ls1 = (LineString3D) list.get(ind_1);
1355
                    LineString3D ls2 = (LineString3D) list.get(ind_2);
1356
1357
                    if (lineString3DIsContainedBy(ls1, ls2)) {
1358
                        resp = ind_1;
1359
                    }
1360
                    else {
1361
                        resp = ind_2;
1362
                    }
1363
                }
1364
                else {
1365
                    // not so deep, sorry!
1366
                    // it's going to be a shell: resp = -1;
1367
                }
1368
            }
1369
        }
1370
1371
        return resp;
1372
    }
1373
1374
    private static int[] getIndicesOfShells(int[] containings) {
1375
        ArrayList resp = new ArrayList();
1376
1377
        for (int i = 0; i < containings.length; i++) {
1378
            if (containings[i] == -1) {
1379
                resp.add(new Integer(i));
1380
            }
1381
        }
1382
1383
        int size = resp.size();
1384
        int[] _resp = new int[size];
1385
1386
        for (int i = 0; i < size; i++) {
1387
            _resp[i] = ((Integer) resp.get(i)).intValue();
1388
        }
1389
1390
        return _resp;
1391
    }
1392
1393
    private static int[] getIndicesOfHoles(int[] containings, int[] shells) {
1394
        ArrayList resp = new ArrayList();
1395
1396
        for (int i = 0; i < containings.length; i++) {
1397
            int cont_by = containings[i];
1398
1399
            if ((cont_by != -1) && (isOneOf(cont_by, shells))) {
1400
                resp.add(new Integer(i));
1401
            }
1402
        }
1403
1404
        int size = resp.size();
1405
        int[] _resp = new int[size];
1406
1407
        for (int i = 0; i < size; i++) {
1408
            _resp[i] = ((Integer) resp.get(i)).intValue();
1409
        }
1410
1411
        return _resp;
1412
    }
1413
1414
    private static int[] getFinalContainings(int[] containings, int[] holes) {
1415
        ArrayList resp = new ArrayList();
1416
1417
        for (int i = 0; i < containings.length; i++) {
1418
            int cont_by = containings[i];
1419
1420
            if (isOneOf(cont_by, holes)) {
1421
                resp.add(new Integer(-1));
1422
            }
1423
            else {
1424
                resp.add(new Integer(cont_by));
1425
            }
1426
        }
1427
1428
        int size = resp.size();
1429
        int[] _resp = new int[size];
1430
1431
        for (int i = 0; i < size; i++) {
1432
            _resp[i] = ((Integer) resp.get(i)).intValue();
1433
        }
1434
1435
        return _resp;
1436
    }
1437
1438
    private static ArrayList getHolesOf(int ind, int[] final_contn,
1439
        ArrayList all) {
1440
        ArrayList resp_ind = new ArrayList();
1441
1442
        for (int i = 0; i < final_contn.length; i++) {
1443
            if (final_contn[i] == ind) {
1444
                resp_ind.add(new Integer(i));
1445
            }
1446
        }
1447
1448
        ArrayList resp = new ArrayList();
1449
1450
        for (int i = 0; i < resp_ind.size(); i++) {
1451
            Integer aux = (Integer) resp_ind.get(i);
1452
            resp.add(all.get(aux.intValue()));
1453
        }
1454
1455
        return resp;
1456
    }
1457
1458
    private static ArrayList getShellsIn(int[] final_contn, ArrayList all) {
1459
        ArrayList resp_ind = new ArrayList();
1460
1461
        for (int i = 0; i < final_contn.length; i++) {
1462
            if (final_contn[i] == -1) {
1463
                resp_ind.add(new Integer(i));
1464
            }
1465
        }
1466
1467
        ArrayList resp = new ArrayList();
1468
1469
        for (int i = 0; i < resp_ind.size(); i++) {
1470
            Integer aux = (Integer) resp_ind.get(i);
1471
            resp.add(all.get(aux.intValue()));
1472
        }
1473
1474
        return resp;
1475
    }
1476
1477
    /**
1478
     * This method tries to guess who is a shell and who is a hole from a set of
1479
     * linestrings.
1480
     *
1481
     * @param all_ls a set of linestrings to be checked.
1482
     *
1483
     * @return a 2-item array. the first is an arraylist of linestrings thought to be shells.
1484
     * the second is an array of arraylists containing the holes of each shell found in the
1485
     * first item
1486
     *
1487
     */
1488
    public static Object[] getHolesForShells(ArrayList all_ls) {
1489
        int no_of_ls = all_ls.size();
1490
        int[] containedby = new int[no_of_ls];
1491
        int[] shells;
1492
        int[] holes;
1493
        int[] final_cont;
1494
1495
        for (int i = 0; i < no_of_ls; i++) {
1496
            LineString3D ls_aux = (LineString3D) all_ls.get(i);
1497
            containedby[i] = getSmallestContainerExcept(ls_aux, all_ls, i);
1498
        }
1499
1500
        shells = getIndicesOfShells(containedby);
1501
        holes = getIndicesOfHoles(containedby, shells);
1502
        final_cont = getFinalContainings(containedby, holes);
1503
1504
        // true shells:
1505
        shells = getIndicesOfShells(final_cont);
1506
1507
        ArrayList resp_shells = new ArrayList();
1508
        ArrayList resp_holes_for_shells = new ArrayList();
1509
        ArrayList aux_holes;
1510
1511
        for (int i = 0; i < shells.length; i++) {
1512
            resp_shells.add(all_ls.get(shells[i]));
1513
            aux_holes = getHolesOf(i, final_cont, all_ls);
1514
            resp_holes_for_shells.add(aux_holes);
1515
        }
1516
1517
        Object[] _resp = new Object[2];
1518
        _resp[0] = resp_shells;
1519
        _resp[1] = resp_holes_for_shells;
1520
1521
        return _resp;
1522
    }
1523
1524
    private static int getTotalSize(ArrayList listOfLists) {
1525
        int resp = 0;
1526
1527
        for (int i = 0; i < listOfLists.size(); i++) {
1528
            resp = resp + ((ArrayList) listOfLists.get(i)).size();
1529
        }
1530
1531
        return resp;
1532
    }
1533
1534
    // private static STRUCT // private static ArrayList getPolygonsEasily(FShape mpolygon) {
1535
    private static STRUCT getMultiPolygonAsStruct(FShape mpol, int srid,
1536
        boolean threed, Connection _conn, boolean agu_bien, boolean hasSrid)
1537
        throws SQLException {
1538
        ArrayList all_ls = getPolygonsEasily(mpol);
1539
        Object[] hs = getHolesForShells(all_ls);
1540
        ArrayList sh = (ArrayList) hs[0];
1541
        ArrayList _ho = (ArrayList) hs[1];
1542
        ArrayList ho = reverseHoles(_ho);
1543
1544
        return getMultiPolygonAsStruct(sh, ho, srid, threed, _conn, agu_bien,
1545
            hasSrid);
1546
    }
1547
1548
    private static ArrayList reverseHoles(ArrayList hh) {
1549
        ArrayList resp = new ArrayList();
1550
1551
        for (int i = 0; i < hh.size(); i++) {
1552
            ArrayList item = (ArrayList) hh.get(i);
1553
            ArrayList newitem = new ArrayList();
1554
1555
            for (int j = 0; j < item.size(); j++) {
1556
                LineString3D ls = (LineString3D) item.get(j);
1557
                newitem.add(ls.createReverse());
1558
            }
1559
1560
            resp.add(newitem);
1561
        }
1562
1563
        return resp;
1564
    }
1565
1566
    private static STRUCT getMultiPolygonAsStruct(ArrayList shells,
1567
        ArrayList holes, int srid, boolean threed, Connection _conn,
1568
        boolean explicito, boolean hasSrid) throws SQLException {
1569
        int t = 1003;
1570
1571
        if (explicito) {
1572
            t = 2003;
1573
        }
1574
1575
        int size = shells.size() + getTotalSize(holes);
1576 13996 jldominguez@prodevelop.es
        int geotype = 2003;
1577
        if (size > 1) geotype = 2007;
1578
1579 13991 jldominguez@prodevelop.es
        int dim = 2;
1580
1581
        if (threed) {
1582 13996 jldominguez@prodevelop.es
            geotype = geotype + 1000;
1583 13991 jldominguez@prodevelop.es
            dim = 3;
1584
        }
1585
1586
        NUMBER[] indices = new NUMBER[3 * size];
1587
1588
        int acum = 0;
1589
        int start_ind = 0;
1590
1591
        for (int i = 0; i < shells.size(); i++) {
1592
            indices[start_ind] = new NUMBER(acum + 1);
1593
            indices[start_ind + 1] = new NUMBER(1003);
1594
            indices[start_ind + 2] = new NUMBER(1);
1595
            start_ind = start_ind + 3;
1596
            acum = acum +
1597
                (dim * ((LineString3D) shells.get(i)).getLs().getNumPoints());
1598
1599
            ArrayList item_holes = (ArrayList) holes.get(i);
1600
1601
            for (int j = 0; j < item_holes.size(); j++) {
1602
                indices[start_ind] = new NUMBER(acum + 1);
1603
                indices[start_ind + 1] = new NUMBER(t); // 1003
1604
                indices[start_ind + 2] = new NUMBER(1);
1605
                start_ind = start_ind + 3;
1606
                acum = acum +
1607
                    (dim * ((LineString3D) item_holes.get(j)).getLs()
1608
                            .getNumPoints());
1609
            }
1610
        }
1611
1612
        int _ind = 0;
1613
        NUMBER[] ords = new NUMBER[acum];
1614
1615
        for (int i = 0; i < shells.size(); i++) {
1616
            // --------------------------------
1617
            LineString3D ls = (LineString3D) shells.get(i);
1618
            int num_p = ls.getLs().getNumPoints();
1619
1620
            for (int j = 0; j < num_p; j++) {
1621
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1622
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1623
1624
                if (threed) {
1625
                    ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1626
                }
1627
1628
                _ind = _ind + dim;
1629
            }
1630
1631
            // -------------------------------
1632
            ArrayList item_holes = (ArrayList) holes.get(i);
1633
1634
            for (int j = 0; j < item_holes.size(); j++) {
1635
                ls = (LineString3D) item_holes.get(j);
1636
                num_p = ls.getLs().getNumPoints();
1637
1638
                for (int k = 0; k < num_p; k++) {
1639
                    ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(k).x);
1640
                    ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(k).y);
1641
1642
                    if (threed) {
1643
                        ords[_ind + 2] = new NUMBER(ls.getZc()[k]);
1644
                    }
1645
1646
                    _ind = _ind + dim;
1647
                }
1648
            }
1649
        }
1650
1651
        STRUCT resp;
1652
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
1653
                _conn);
1654
        Object[] obj = new Object[5];
1655
        obj[0] = new NUMBER(geotype);
1656
1657
        if (hasSrid) {
1658
            obj[1] = new NUMBER(srid);
1659
        }
1660
        else {
1661
            obj[1] = null;
1662
        }
1663
1664
        obj[2] = null;
1665
        obj[3] = indices;
1666
        obj[4] = ords;
1667
1668
        // String ind_str = printArray(indices);
1669
        // String ord_str = printArray(ords);
1670
        resp = new STRUCT(dsc, _conn, obj);
1671
1672
        return resp;
1673
    }
1674
1675
    public static String printArray(NUMBER[] array) {
1676
        String resp = "[ ";
1677
1678
        for (int i = 0; i < array.length; i++) {
1679
            resp = resp + " " + array[i].doubleValue() + " , ";
1680
        }
1681
1682
        resp = resp.substring(0, resp.length() - 2) + "]";
1683
1684
        return resp;
1685
    }
1686
1687
    private static boolean isOneOf(int ind, int[] list) {
1688
        for (int i = 0; i < list.length; i++) {
1689
            if (list[i] == ind) {
1690
                return true;
1691
            }
1692
        }
1693
1694
        return false;
1695
    }
1696
1697
    /**
1698
     * This method appends the geometries from a geometry collection in one STRUCT.
1699
     *
1700
     * @param co the geometry collection
1701
     * @param _forced_type a type that has to be used as the struct's main type
1702
     * @param _conn the connection
1703
     * @param _o_srid the geometry's SRS (oracle code)
1704
     * @param withSrid whether the SRS is non-NULL
1705
     * @param agu_bien whether to check holes' validity
1706
     * @param _isGeoCS whether the SRS is geodetic
1707
     * @return the STRUCT with the appended geometries
1708
     */
1709
    public static STRUCT appendGeometriesInStruct(FGeometryCollection co,
1710
        int _forced_type, Connection _conn, String _o_srid, boolean withSrid,
1711
        boolean agu_bien, boolean _isGeoCS) {
1712
        IGeometry[] geoms = co.getGeometries();
1713
        int size = geoms.length;
1714
        STRUCT[] sts = new STRUCT[size];
1715
1716
        for (int i = 0; i < size; i++) {
1717
            sts[i] = OracleSpatialDriver.iGeometryToSTRUCT(geoms[i],
1718
                    _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
1719
        }
1720
1721
        if (size == 1) {
1722
            return sts[0];
1723
        }
1724
1725
        STRUCT aux = sts[0];
1726
1727
        for (int i = 1; i < size; i++) {
1728
            aux = appendStructs(aux, sts[i], _conn);
1729
        }
1730
1731
        return aux;
1732
    }
1733
1734
    private static STRUCT appendStructs(STRUCT st1, STRUCT st2, Connection _conn) {
1735
        try {
1736
            ARRAY _ords = (ARRAY) st1.getOracleAttributes()[4];
1737
            int length_of_head_ords = _ords.getOracleArray().length;
1738
1739
            NUMBER gtype = new NUMBER(4 +
1740
                    (((NUMBER) st1.getOracleAttributes()[0]).intValue() / 1000));
1741
            NUMBER srid = (NUMBER) st1.getOracleAttributes()[1];
1742
            NUMBER middle = (NUMBER) st1.getOracleAttributes()[2];
1743
1744
            ARRAY info1 = (ARRAY) st1.getOracleAttributes()[3];
1745
            ARRAY info2 = (ARRAY) st2.getOracleAttributes()[3];
1746
            ARRAY ords1 = (ARRAY) st1.getOracleAttributes()[4];
1747
            ARRAY ords2 = (ARRAY) st2.getOracleAttributes()[4];
1748
1749
            Datum[] info = appendDatumArrays(info1.getOracleArray(),
1750
                    info2.getOracleArray(), length_of_head_ords);
1751
1752
            Datum[] ords = appendDatumArrays(ords1.getOracleArray(),
1753
                    ords2.getOracleArray(), 0);
1754
1755
            StructDescriptor dsc = st1.getDescriptor();
1756
1757
            Object[] atts = new Object[5];
1758
            atts[0] = gtype;
1759
            atts[1] = srid;
1760
            atts[2] = middle;
1761
            atts[3] = info;
1762
            atts[4] = ords;
1763
1764
            STRUCT resp = new STRUCT(dsc, _conn, atts);
1765
1766
            return resp;
1767
        }
1768
        catch (SQLException sqle) {
1769
            logger.error("While appending structs: " + sqle.getMessage(), sqle);
1770
        }
1771
1772
        return null;
1773
    }
1774
1775
    private static Datum[] appendDatumArrays(Datum[] head, Datum[] tail,
1776
        int offset) {
1777
        int head_l = head.length;
1778
        int tail_l = tail.length;
1779
        Datum[] resp = new Datum[head_l + tail_l];
1780
1781
        for (int i = 0; i < head_l; i++)
1782
            resp[i] = head[i];
1783
1784
        if (offset == 0) {
1785
            for (int i = 0; i < tail_l; i++)
1786
                resp[head_l + i] = tail[i];
1787
        }
1788
        else {
1789
            try {
1790
                for (int i = 0; i < tail_l; i++) {
1791
                    if ((i % 3) == 0) {
1792
                        resp[head_l + i] = new NUMBER(tail[i].intValue() +
1793
                                offset);
1794
                    }
1795
                    else {
1796
                        resp[head_l + i] = tail[i];
1797
                    }
1798
                }
1799
            }
1800
            catch (SQLException se) {
1801
                logger.error("Unexpected error: " + se.getMessage());
1802
            }
1803
        }
1804
1805
        return resp;
1806
    }
1807
1808
    /**
1809
     * Utility method to get an ineteger as a formatted string.
1810
     *
1811
     * @param n the integer
1812
     * @return the formatted string
1813
     */
1814
    public static String getFormattedInteger(int n) {
1815
        df.setGroupingUsed(true);
1816
        df.setGroupingSize(3);
1817
        dfs.setGroupingSeparator('.');
1818
        df.setDecimalFormatSymbols(dfs);
1819
1820
        return df.format(n);
1821
    }
1822
1823
    /**
1824
     * Tells whether these arrays belong to a rectangle polygon.
1825
     *
1826
     * @param info the struct's element info array
1827
     * @param ords the struct's coordinate array
1828
     * @return true if it is a rectangle polygon. false otherwise.
1829
     */
1830
    public static boolean polStructIsRectStruct(ARRAY info, ARRAY ords) {
1831
        try {
1832
            int[] infos = info.getIntArray();
1833
1834
            return ((infos[2] == 3) && (infos.length == 3));
1835
        }
1836
        catch (SQLException se) {
1837
            logger.error("While ckecking rectangle: " + se.getMessage(), se);
1838
        }
1839
1840
        return false;
1841
    }
1842
1843
    /**
1844
     * Utility method to deal with oracle info arrays.
1845
     */
1846
    public static ARRAY getDevelopedInfoArray(ARRAY info) {
1847
        ARRAY _resp = null;
1848
1849
        try {
1850
            Datum[] resp = new Datum[3];
1851
            Datum[] in = info.getOracleArray();
1852
            resp[0] = in[0];
1853
            resp[1] = in[1];
1854
            resp[2] = new NUMBER(1);
1855
            _resp = new ARRAY(info.getDescriptor(),
1856
                    info.getInternalConnection(), resp);
1857
        }
1858
        catch (SQLException se) {
1859
            logger.error("While creating ARRAY: " + se.getMessage(), se);
1860
        }
1861
1862
        return _resp;
1863
    }
1864
1865
    /**
1866
     * Utility method to deal with oracle coordinate arrays.
1867
     */
1868
    public static ARRAY getDevelopedOrdsArray(ARRAY ords) {
1869
        ARRAY _resp = null;
1870
1871
        try {
1872
            Datum[] resp = new Datum[10];
1873
            Datum[] corners = ords.getOracleArray();
1874
1875
            // x
1876
            resp[0] = corners[0];
1877
            resp[2] = corners[2];
1878
            resp[4] = corners[2];
1879
            resp[6] = corners[0];
1880
            resp[8] = corners[0];
1881
1882
            // y
1883
            resp[1] = corners[1];
1884
            resp[3] = corners[1];
1885
            resp[5] = corners[3];
1886
            resp[7] = corners[3];
1887
            resp[9] = corners[1];
1888
            _resp = new ARRAY(ords.getDescriptor(),
1889
                    ords.getInternalConnection(), resp);
1890
        }
1891
        catch (SQLException se) {
1892
            logger.error("While creating ARRAY: " + se.getMessage(), se);
1893
        }
1894
1895
        return _resp;
1896
    }
1897
1898
    /**
1899
     * utility method to convert a STRUCT into a GeneralPathX
1900
     * @param aux the struct's datum array
1901
     * @return the GeneralPathX instance created
1902
     */
1903
    public static GeneralPathX structToGPX(Datum[] aux) {
1904
        GeneralPathX resp = new GeneralPathX();
1905
        ARRAY infoARRAY = null;
1906
        ARRAY ordsARRAY = null;
1907
        Datum[] info_array = null;
1908
        Datum[] ords_array = null;
1909
        int info_array_size = 0;
1910
        int[] start_ind;
1911
        int[] end_ind;
1912
        int dims = 0;
1913
        boolean next_must_do_first = true;
1914
1915
        try {
1916
            infoARRAY = (ARRAY) aux[3];
1917
            ordsARRAY = (ARRAY) aux[4];
1918
1919
            if (polStructIsRectStruct(infoARRAY, ordsARRAY)) {
1920
                infoARRAY = getDevelopedInfoArray(infoARRAY);
1921
                ordsARRAY = getDevelopedOrdsArray(ordsARRAY);
1922
            }
1923
1924
            dims = ((NUMBER) aux[0]).intValue() / 1000;
1925
1926
            if (dims == 0) {
1927
                dims = 2;
1928
            }
1929
1930
            info_array = (Datum[]) infoARRAY.getOracleArray();
1931
            ords_array = (Datum[]) ordsARRAY.getOracleArray();
1932
            info_array_size = info_array.length / 3;
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
                    next_must_do_first = addOrdsToGPX(resp, start_ind[i] - 1,
1955
                            end_ind[i] - 1, ords_array, dims, lineType,
1956
                            (i == 1), next_must_do_first);
1957
                }
1958
            }
1959
            else {
1960
                // standard case, do the moveto always
1961
                for (int i = 0; i < info_array_size; i++) {
1962
                    lineType = getLineToType(info_array, i);
1963
                    addOrdsToGPX(resp, start_ind[i] - 1, end_ind[i] - 1,
1964
                        ords_array, dims, lineType, true, true);
1965
                }
1966
            }
1967
1968
            // boolean do_the_moves = true;
1969
        }
1970
        catch (SQLException se) {
1971
            logger.error("While creating GPX: " + se.getMessage(), se);
1972
        }
1973
1974
        return resp;
1975
    }
1976
1977
    private static int getLineToType(Datum[] infos, int i) {
1978
        int resp = PathIterator.SEG_LINETO;
1979
1980
        try {
1981
            if (((NUMBER) infos[(3 * i) + 2]).intValue() == 2) {
1982
                resp = PathIterator.SEG_QUADTO;
1983
            }
1984
        }
1985
        catch (SQLException e) {
1986
            logger.error("While getting line-to type: " + e.getMessage() +
1987
                " (returned SEG_LINETO)");
1988
        }
1989
1990
        return resp;
1991
    }
1992
1993
    private static boolean addOrdsToGPX(GeneralPathX gpx, int zero_based_start,
1994
        int zero_based_include_end, Datum[] ords, int d, int ltype,
1995
        boolean do_the_move, boolean must_do_first) {
1996
        int length = ords.length;
1997
        boolean return_following_must_do_first = true;
1998
1999
        double x = ((NUMBER) ords[zero_based_start]).doubleValue();
2000
        double y = ((NUMBER) ords[zero_based_start + 1]).doubleValue();
2001
2002
        if (must_do_first) {
2003
            if (do_the_move) {
2004
                gpx.moveTo(x, y);
2005
            }
2006
            else {
2007
                gpx.lineTo(x, y);
2008
            }
2009
        }
2010
2011
        int ind = 1;
2012
2013
        int size = ((zero_based_include_end - zero_based_start) / d) + 1;
2014
        int indx;
2015
        int indx2;
2016
2017
        if (ltype == PathIterator.SEG_QUADTO) { // (interpretation = 2)
2018
2019
            double x2;
2020
            double y2;
2021
2022
            while (ind < size) {
2023
                indx = zero_based_start + (ind * d);
2024
                x = ((NUMBER) ords[indx]).doubleValue();
2025
                y = ((NUMBER) ords[indx + 1]).doubleValue();
2026
2027
                indx2 = zero_based_start + ((ind + 1) * d);
2028
2029
                if (indx >= length) {
2030
                    indx2 = zero_based_start;
2031
                }
2032
2033
                x2 = ((NUMBER) ords[indx2]).doubleValue();
2034
                y2 = ((NUMBER) ords[indx2 + 1]).doubleValue();
2035
                gpx.quadTo(x, y, x2, y2);
2036
                ind++;
2037
                ind++;
2038
            }
2039
2040
            return_following_must_do_first = false;
2041
        }
2042
        else { // PathIterator.SEG_LINETO (interpretation = 1)
2043
2044
            while (ind < size) {
2045
                indx = zero_based_start + (ind * d);
2046
                x = ((NUMBER) ords[indx]).doubleValue();
2047
                y = ((NUMBER) ords[indx + 1]).doubleValue();
2048
                gpx.lineTo(x, y);
2049
                ind++;
2050
            }
2051
        }
2052
2053
        return return_following_must_do_first;
2054
    }
2055
2056
    /**
2057
     * Utility method. Gets FShape type from oracle geometry type.
2058
     * @param otype
2059
     * @return FShape type
2060
     */
2061
    public static int oracleGTypeToFShapeType(int otype) {
2062
        switch (otype) {
2063
        case ORACLE_GTYPE_UNKNOWN:
2064
            return FShape.NULL;
2065
2066
        case ORACLE_GTYPE_POINT:
2067
        case ORACLE_GTYPE_MULTIPOINT:
2068
            return FShape.POINT;
2069
2070
        case ORACLE_GTYPE_LINE:
2071
        case ORACLE_GTYPE_MULTILINE:
2072
            return FShape.LINE;
2073
2074
        case ORACLE_GTYPE_POLYGON:
2075
        case ORACLE_GTYPE_MULTIPOLYGON:
2076
            return FShape.POLYGON;
2077
2078
        case ORACLE_GTYPE_COLLECTION:
2079
            return FShape.MULTI;
2080
        }
2081
2082
        logger.warn("Unknown oracle geometry type: " + otype);
2083
2084
        return FShape.NULL;
2085
    }
2086
2087
    /**
2088
     * Utility method to get struct's type.
2089
     * @param the_data the struct's datum array
2090
     * @return the struct type
2091
     */
2092
    public static int getStructType(Datum[] the_data) {
2093
        int resp = -1;
2094
2095
        try {
2096
            resp = ((NUMBER) the_data[0]).intValue() % 1000;
2097
        }
2098
        catch (SQLException se) {
2099
            logger.error("Error: " + se.getMessage(), se);
2100
        }
2101
2102
        return resp;
2103
    }
2104
2105
    /**
2106
     * Utility method to get struct's SRID.
2107
     * @param the_data the struct's datum array
2108
     * @return the struct0's SRID
2109
     */
2110
    public static int getStructSRID(Datum[] the_data) {
2111
        int resp = -1;
2112
2113
        try {
2114
            resp = ((NUMBER) the_data[1]).intValue();
2115
        }
2116
        catch (SQLException se) {
2117
            logger.error("Error: " + se.getMessage(), se);
2118
        }
2119
2120
        return resp;
2121
    }
2122
2123
    /**
2124
     * Utility method to find out if  a struct is a circle.
2125
     *
2126
     * @param the_data the struct's datum array
2127
     * @return whether it is a circle
2128
     */
2129
    public static boolean isCircle(Datum[] the_data) {
2130
        int[] info = null;
2131
2132
        try {
2133
            info = ((ARRAY) the_data[3]).getIntArray();
2134
        }
2135
        catch (SQLException se) {
2136
            logger.error("While cheking circle: " + se.getMessage(), se);
2137
2138
            return false;
2139
        }
2140
2141
        if (info == null) {
2142
            return false;
2143
        }
2144
2145
        boolean resp = ((info.length == 3) && (info[2] == 4));
2146
2147
        return resp;
2148
    }
2149
2150
    /**
2151
     * Gets the struct's dimension size.
2152
     * @param st the struct
2153
     * @return the structs dimension
2154
     */
2155
    public static int getStructDimensions(STRUCT st) {
2156
        int resp = -1;
2157
2158
        try {
2159
            resp = ((NUMBER) st.getOracleAttributes()[0]).intValue() / 1000;
2160
        }
2161
        catch (SQLException se) {
2162
            logger.error("Error: " + se.getMessage(), se);
2163
        }
2164
2165
        if (resp < 2) {
2166
            resp = 2;
2167
        }
2168
2169
        return resp;
2170
    }
2171
2172
    /**
2173
     * Gets a struct's coordinates array.
2174
     * @param the_data the struct's datum array
2175
     * @return the coordinates array
2176
     */
2177
    public static double[] getOrds(Datum[] the_data) {
2178
        double[] resp = null;
2179
2180
        try {
2181
            ARRAY aux = (ARRAY) the_data[4];
2182
2183
            if (aux == null) {
2184
                return null;
2185
            }
2186
2187
            resp = aux.getDoubleArray();
2188
        }
2189
        catch (SQLException se) {
2190
            logger.error("While getting ordinates: " + se.getMessage(), se);
2191
        }
2192
2193
        return resp;
2194
    }
2195
2196
    /**
2197
     * Utility method to create a struct with the given data.
2198
     * @param type struct type
2199
     * @param srid coordinate system
2200
     * @param info element info array
2201
     * @param ords coordinates array
2202
     * @param conn connection
2203
     * @return the created struct
2204
     */
2205
    public static STRUCT createStruct(NUMBER type, NUMBER srid, Datum[] info,
2206
        Datum[] ords, Connection conn) {
2207
        try {
2208
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2209
                    conn);
2210
            Object[] obj = new Object[5];
2211
            obj[0] = type;
2212
            obj[1] = srid;
2213
            obj[2] = null;
2214
            obj[3] = info;
2215
            obj[4] = ords;
2216
2217
            return new STRUCT(dsc, conn, obj);
2218
        }
2219
        catch (SQLException se) {
2220
            logger.error("While creating STRUCT: " + se.getMessage(), se);
2221
        }
2222
2223
        return null;
2224
    }
2225
2226
    public static String getDimInfoAsString(ARRAY dim_info) {
2227
            String resp = "DIMENSIONS: ";
2228
2229
        if (dim_info == null) {
2230
            return "NULL" + "\n";
2231
        }
2232
        else {
2233
                try {
2234
                                Datum[] da = dim_info.getOracleArray();
2235
                                int size = da.length;
2236
                                resp = resp + size + "\n";
2237
                                for (int i = 0; i < size; i++) {
2238
                                        STRUCT dim_itemx = (STRUCT) da[i];
2239
                                        Object[] dim_desc = dim_itemx.getAttributes();
2240
                                        resp = resp + "DIMENSION " + i + ": " + ", NAME: "
2241
                                                        + dim_desc[0].toString() + ", MIN: "
2242
                                                        + dim_desc[1].toString() + ", MAX: "
2243
                                                        + dim_desc[2].toString() + ", TOL: "
2244
                                                        + dim_desc[3].toString();
2245
                                        if (i != (size -1)) {
2246
                                                resp = resp + "\n";
2247
                                        }
2248
                                }
2249
                        } catch (Exception ex) {
2250
                                return "ERROR: " + ex.getMessage() + "\n";
2251
                        }
2252
        }
2253
        return resp;
2254
    }
2255
2256
    public static STRUCT reprojectGeometry(Connection conn, STRUCT fromStruct, String toSrid) {
2257
2258
            String qry = "SELECT SDO_CS.TRANSFORM( ?, " + toSrid + ") FROM DUAL";
2259
            STRUCT resp = null;
2260
2261
            try {
2262
                        PreparedStatement _st = conn.prepareStatement(qry);
2263
                        _st.setObject(1, fromStruct);
2264
                        ResultSet _rs = _st.executeQuery();
2265
2266
                        if (_rs.next()) {
2267
                                resp = (STRUCT) _rs.getObject(1);
2268
                        } else {
2269
                                logger.error("While executing reprojection: empty resultset (?)");
2270
                                return fromStruct;
2271
                        }
2272
                } catch (Exception ex) {
2273
                        logger.error("While reprojecting: " + ex.getMessage());
2274
                        return fromStruct;
2275
                }
2276
2277
        if (resp == null) {
2278
                return fromStruct;
2279
        } else {
2280
                return resp;
2281
        }
2282
    }
2283
2284
}