Statistics
| Revision:

root / branches / v2_0_0_prep / extensions / org.gvsig.oracle / src / org / gvsig / fmap / dal / store / oracle / OracleUtils.java @ 38033

History | View | Annotate | Download (112 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2009 Prodevelop S.L. main development
26
 */
27

    
28
package org.gvsig.fmap.dal.store.oracle;
29

    
30
import java.awt.geom.PathIterator;
31
import java.awt.geom.Point2D;
32
import java.awt.geom.Rectangle2D;
33
import java.io.BufferedReader;
34
import java.io.File;
35
import java.io.FileReader;
36
import java.lang.reflect.Array;
37
import java.net.URL;
38
import java.sql.Connection;
39
import java.sql.PreparedStatement;
40
import java.sql.ResultSet;
41
import java.sql.SQLException;
42
import java.sql.Types;
43
import java.text.DecimalFormat;
44
import java.text.DecimalFormatSymbols;
45
import java.util.ArrayList;
46
import java.util.HashMap;
47
import java.util.Iterator;
48
import java.util.List;
49
import java.util.Random;
50

    
51
import oracle.sql.ARRAY;
52
import oracle.sql.Datum;
53
import oracle.sql.NUMBER;
54
import oracle.sql.STRUCT;
55
import oracle.sql.StructDescriptor;
56

    
57
import org.cresques.cts.IProjection;
58
import org.gvsig.fmap.dal.DALLocator;
59
import org.gvsig.fmap.dal.DataManager;
60
import org.gvsig.fmap.dal.exception.DataException;
61
import org.gvsig.fmap.dal.feature.EditableFeatureType;
62
import org.gvsig.fmap.dal.feature.Feature;
63
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
64
import org.gvsig.fmap.dal.feature.FeatureQuery;
65
import org.gvsig.fmap.dal.feature.FeatureSet;
66
import org.gvsig.fmap.dal.feature.FeatureStore;
67
import org.gvsig.fmap.dal.feature.FeatureType;
68
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
69
import org.gvsig.fmap.geom.Geometry;
70
import org.gvsig.fmap.geom.GeometryLocator;
71
import org.gvsig.fmap.geom.GeometryManager;
72
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
73
import org.gvsig.fmap.geom.Geometry.TYPES;
74
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
75
import org.gvsig.fmap.geom.aggregate.impl.MultiPoint2D;
76
import org.gvsig.fmap.geom.aggregate.impl.MultiPoint2DZ;
77
import org.gvsig.fmap.geom.aggregate.impl.MultiSurface2D;
78
import org.gvsig.fmap.geom.complex.Complex;
79
import org.gvsig.fmap.geom.exception.CreateGeometryException;
80
import org.gvsig.fmap.geom.impl.DefaultGeometryManager;
81
import org.gvsig.fmap.geom.primitive.Curve;
82
import org.gvsig.fmap.geom.primitive.Envelope;
83
import org.gvsig.fmap.geom.primitive.GeneralPathX;
84
import org.gvsig.fmap.geom.primitive.Point;
85
import org.gvsig.fmap.geom.primitive.Primitive;
86
import org.gvsig.fmap.geom.primitive.Surface;
87
import org.gvsig.fmap.geom.primitive.impl.Circle2D;
88
import org.gvsig.fmap.geom.primitive.impl.Curve2DZ;
89
import org.gvsig.fmap.geom.primitive.impl.DefaultNullGeometry;
90
import org.gvsig.fmap.geom.primitive.impl.Point2DZ;
91
import org.gvsig.fmap.geom.primitive.impl.Surface2D;
92
import org.gvsig.fmap.geom.primitive.impl.Surface2DZ;
93
import org.gvsig.fmap.geom.type.GeometryType;
94
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
95
import org.gvsig.oracle.extension.NewOracleTableExtension;
96
import org.gvsig.oracle.utils.LineString3D;
97
import org.slf4j.Logger;
98
import org.slf4j.LoggerFactory;
99

    
100
import com.vividsolutions.jts.algorithm.CGAlgorithms;
101
import com.vividsolutions.jts.geom.Coordinate;
102
import com.vividsolutions.jts.geom.CoordinateArrays;
103
import com.vividsolutions.jts.geom.GeometryFactory;
104
import com.vividsolutions.jts.geom.LineString;
105
import com.vividsolutions.jts.geom.LinearRing;
106
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
107

    
108
/**
109
 * Utility class with static methods.
110
 * 
111
 * @author jldominguez, vsanjaime
112
 * 
113
 */
114
public class OracleUtils {
115
        
116
        private static Logger logger = LoggerFactory.getLogger(OracleUtils.class);
117
        
118
        private static double FLATNESS = 0.8;
119
        private static GeometryFactory geomFactory = new GeometryFactory();
120
        private static final double IRRELEVANT_DISTANCE = 0.00000001;
121
        public static final Rectangle2D DEFAULT_BBOX = new Rectangle2D.Double(-180, -90, 360, 180);;
122
        private static Random rnd = new Random();
123
        private static DecimalFormat df = new DecimalFormat();
124
        private static DecimalFormatSymbols dfs = new DecimalFormatSymbols();
125
        
126
        public static final String ENVELOPE_ID = "Envelope_Key";
127
        public static final String DIMENSIONS_ID = "Dimensions_Key";
128

    
129
    private static final String GEOM_DEFAULT_TOL = "0.000005";
130

    
131

    
132
        /**
133
         * COnstructs a geometry from a file that contains a vertex per line:
134
         * 
135
         * x1 y1 z1 x2 y2 z2 ...
136
         * 
137
         * @param filepath
138
         *            vertices text file path
139
         * @param polygon
140
         *            whether it is a polygon or not
141
         * @return the created geometry
142
         * @throws CreateGeometryException
143
         */
144
        public static Geometry readGeometry3D(URL filepath, boolean polygon)
145
                        throws CreateGeometryException {
146

    
147
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
148

    
149
                GeneralPathX gpx = new GeneralPathX();
150
                File file = new File(filepath.getFile());
151
                List<Double> z = new ArrayList<Double>();
152

    
153
                try {
154
                        FileReader fr = new FileReader(file);
155
                        BufferedReader br = new BufferedReader(fr);
156
                        double[] coords = new double[3];
157

    
158
                        boolean move = true;
159

    
160
                        String line = br.readLine();
161

    
162
                        while (line != null) {
163
                                coords = parseLine(line);
164

    
165
                                if (line.length() == 0) {
166
                                        move = true;
167
                                } else {
168
                                        if (move) {
169
                                                gpx.moveTo(coords[0], coords[1]);
170
                                                z.add(new Double(coords[2]));
171
                                        } else {
172
                                                gpx.lineTo(coords[0], coords[1]);
173
                                                z.add(new Double(coords[2]));
174
                                        }
175

    
176
                                        move = false;
177
                                }
178

    
179
                                line = br.readLine();
180
                        }
181
                } catch (Exception ex) {
182
                        logger.error("While creating GeneralPathX: " + ex.getMessage());
183
                        return null;
184
                }
185

    
186
                if (polygon) {
187
                        Surface surface = (Surface) geomManager.create(
188
                                        Geometry.TYPES.SURFACE, Geometry.SUBTYPES.GEOM3D);
189
                        surface.setGeneralPath(gpx);
190
                        for (int i = 0; i < z.size(); i++) {
191
                                surface
192
                                                .setCoordinateAt(i, 2, ((Double) z.get(i))
193
                                                                .doubleValue());
194
                        }
195
                        return surface;
196
                } else {
197
                        Curve curve = (Curve) geomManager.create(Geometry.TYPES.CURVE,
198
                                        Geometry.SUBTYPES.GEOM3D);
199
                        curve.setGeneralPath(gpx);
200
                        for (int i = 0; i < z.size(); i++) {
201
                                curve.setCoordinateAt(i, 2, ((Double) z.get(i)).doubleValue());
202
                        }
203
                        return curve;
204
                }
205
        }
206

    
207
        /**
208
         * 
209
         * @param line
210
         * @return
211
         */
212
        private static double[] parseLine(String line) {
213
                String[] sep = line.split(" ");
214
                double[] resp = new double[3];
215

    
216
                for (int i = 0; i < 3; i++)
217
                        resp[i] = 0.0;
218

    
219
                try {
220
                        resp[0] = Double.parseDouble(sep[0]);
221
                } catch (Exception ex) {
222
                }
223

    
224
                if (sep.length > 1) {
225
                        try {
226
                                resp[1] = Double.parseDouble(sep[1]);
227
                        } catch (Exception ex) {
228
                        }
229

    
230
                        if (sep.length > 2) {
231
                                try {
232
                                        resp[2] = Double.parseDouble(sep[2]);
233
                                } catch (Exception ex) {
234
                                }
235
                        }
236
                }
237

    
238
                return resp;
239
        }
240

    
241
        /**
242
         * Transform multipoint2d or multipoint2dz to Oracle STRUCT
243
         * 
244
         * @param mp2d
245
         * @param conn
246
         * @param osrid
247
         * @param hasSrid
248
         * @return
249
         * @throws SQLException
250
         */
251
        private static STRUCT multiPoint2DToStruct(MultiPoint2D mp2d,
252
                        Connection conn, int osrid, boolean hasSrid) throws SQLException {
253
                int np = mp2d.getPrimitivesNumber();
254
                boolean threed = (mp2d instanceof MultiPoint2DZ);
255
                int gtype = 2005;
256
                int dim = 2;
257
                MultiPoint2DZ mp3d = null;
258

    
259
                if (threed) {
260
                        gtype = 3005;
261
                        dim = 3;
262
                        mp3d = (MultiPoint2DZ) mp2d;
263
                }
264

    
265
                NUMBER[] indices = new NUMBER[3];
266
                indices[0] = new NUMBER(1);
267
                indices[1] = new NUMBER(1);
268
                indices[2] = new NUMBER(np);
269

    
270
                NUMBER[] ords = new NUMBER[dim * np];
271

    
272
                for (int i = 0; i < np; i++) {
273
                        ords[dim * i] = new NUMBER(mp2d.getPoint(i).getX());
274
                        ords[(dim * i) + 1] = new NUMBER(mp2d.getPoint(i).getY());
275

    
276
                        if (threed) {
277
                                ords[(dim * i) + 2] = new NUMBER(mp3d.getZs()[i]);
278
                        }
279
                }
280

    
281
                STRUCT resp;
282
                StructDescriptor dsc = StructDescriptor.createDescriptor(
283
                                "MDSYS.SDO_GEOMETRY", conn);
284
                Object[] obj = new Object[5];
285
                obj[0] = new NUMBER(gtype);
286

    
287
                if (hasSrid) {
288
                        obj[1] = new NUMBER(osrid);
289
                } else { // , boolean hasSrid
290
                        obj[1] = null;
291
                }
292

    
293
                obj[2] = null;
294
                obj[3] = indices;
295
                obj[4] = ords;
296
                resp = new STRUCT(dsc, conn, obj);
297

    
298
                return resp;
299
        }
300

    
301
        /**
302
         * Transform circle2d to Oracle STRUCT
303
         * 
304
         * @param fcirc
305
         * @param osrid
306
         * @param _conn
307
         * @param hasSrid
308
         * @return
309
         * @throws SQLException
310
         */
311
        private static STRUCT getCircleAsStruct(Circle2D fcirc, int osrid,
312
                        Connection conn, boolean hasSrid) throws SQLException {
313
                int geotype = 2003;
314
                NUMBER[] indices = new NUMBER[3];
315
                indices[0] = new NUMBER(1);
316
                indices[1] = new NUMBER(1003);
317
                indices[2] = new NUMBER(4);
318

    
319
                NUMBER[] ords = new NUMBER[6];
320
                Coordinate[] three_points = getThreePointsOfCircumference(fcirc
321
                                .getCenter(), fcirc.getRadious());
322

    
323
                for (int i = 0; i < three_points.length; i++) {
324
                        ords[i * 2] = new NUMBER(three_points[i].x);
325
                        ords[(i * 2) + 1] = new NUMBER(three_points[i].y);
326
                }
327

    
328
                STRUCT resp;
329
                StructDescriptor dsc = StructDescriptor.createDescriptor(
330
                                "MDSYS.SDO_GEOMETRY", conn);
331
                Object[] obj = new Object[5];
332
                obj[0] = new NUMBER(geotype);
333

    
334
                if (hasSrid) {
335
                        obj[1] = new NUMBER(osrid);
336
                } else {
337
                        obj[1] = null;
338
                }
339

    
340
                obj[2] = null;
341
                obj[3] = indices;
342
                obj[4] = ords;
343
                resp = new STRUCT(dsc, conn, obj);
344

    
345
                return resp;
346
        }
347

    
348
        /**
349
         * 
350
         * @param center
351
         * @param radius
352
         * @return
353
         */
354
        private static Coordinate[] getThreePointsOfCircumference(Point center,
355
                        double radius) {
356
                Coordinate[] resp = new Coordinate[3];
357
                double x;
358
                double y;
359
                double alpha = 0;
360

    
361
                for (int i = 0; i < 3; i++) {
362
                        alpha = (i * 120.0 * Math.PI) / 180.0;
363
                        x = center.getX() + (radius * Math.cos(alpha));
364
                        y = center.getY() + (radius * Math.sin(alpha));
365
                        resp[i] = new Coordinate(x, y);
366
                }
367

    
368
                return resp;
369
        }
370

    
371
        /**
372
         * Get coordinates from a point
373
         * 
374
         * @param pto
375
         * @return
376
         */
377
        private static Coordinate getSingleCoordinate(Point pto) {
378
                Coordinate resp = new Coordinate();
379
                resp.x = pto.getX();
380
                resp.y = pto.getY();
381
                if (pto instanceof Point2DZ) {
382
                        resp.z = ((Point2DZ) pto).getCoordinateAt(3);
383
                }
384
                return resp;
385
        }
386

    
387
        /**
388
         * 
389
         * @param cc
390
         * @return
391
         */
392
        private static List<Coordinate> ensureSensibleLineString(List<Coordinate> cc) {
393
                if (cc.size() == 2) {
394
                        if (same2DCoordinate(cc.get(0), cc.get(cc.size() - 1))) {
395
                                List<Coordinate> resp = new ArrayList<Coordinate>();
396
                                resp.add(cc.get(0));
397

    
398
                                Coordinate newc = new Coordinate(cc.get(0));
399
                                newc.x = newc.x + IRRELEVANT_DISTANCE;
400
                                resp.add(newc);
401

    
402
                                return resp;
403
                        }
404
                }
405
                return cc;
406
        }
407

    
408
        /**
409
         * 
410
         * @param c1
411
         * @param c2
412
         * @return
413
         */
414
        private static boolean same2DCoordinate(Coordinate c1, Coordinate c2) {
415
                if (c1.x != c2.x) {
416
                        return false;
417
                }
418
                if (c1.y != c2.y) {
419
                        return false;
420
                }
421

    
422
                return true;
423
        }
424

    
425
        /**
426
         * 
427
         * @param cc
428
         * @return
429
         */
430
        private static List<Coordinate> getClosedRelevantPolygon(List<Coordinate> cc) {
431
                if (cc.size() == 2) {
432
                        return getMinClosedCoords(cc.get(0));
433
                }
434

    
435
                if (cc.size() == 3) {
436
                        if (same2DCoordinate(cc.get(0), cc.get(1))) {
437
                                return getMinClosedCoords(cc.get(0));
438
                        }
439

    
440
                        if (same2DCoordinate(cc.get(0), cc.get(2))) {
441
                                return getMinClosedCoords((Coordinate) cc.get(0));
442
                        }
443

    
444
                        if (same2DCoordinate(cc.get(1), cc.get(2))) {
445
                                return getMinClosedCoords(cc.get(1));
446
                        }
447

    
448
                        cc.add(cc.get(0));
449

    
450
                        return cc;
451
                }
452

    
453
                if (!same2DCoordinate(cc.get(0), cc.get(cc.size() - 1))) {
454
                        cc.add(cc.get(0));
455
                }
456

    
457
                return cc;
458
        }
459

    
460
        /**
461
         * 
462
         * @param c
463
         * @return
464
         */
465
        private static List<Coordinate> getMinClosedCoords(Coordinate c) {
466
                List<Coordinate> resp = new ArrayList<Coordinate>();
467
                resp.add(c);
468

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

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

    
477
                resp.add(new Coordinate(c));
478

    
479
                return resp;
480
        }
481

    
482
        /**
483
         * 
484
         * @param c
485
         * @return
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
        /**
507
         * 
508
         * @return
509
         */
510
        private static double[] getMinLinearRingZ() {
511
                double[] resp = new double[4];
512

    
513
                for (int i = 0; i < 4; i++)
514
                        resp[i] = 0.0;
515

    
516
                return resp;
517
        }
518

    
519
        /**
520
         * 
521
         * @param testPoint
522
         * @param pointList
523
         * @return
524
         */
525
        private static boolean pointInList(Coordinate testPoint,
526
                        Coordinate[] pointList) {
527
                int t;
528
                int numpoints;
529
                Coordinate p;
530

    
531
                numpoints = Array.getLength(pointList);
532

    
533
                for (t = 0; t < numpoints; t++) {
534
                        p = pointList[t];
535

    
536
                        if ((testPoint.x == p.x)
537
                                        && (testPoint.y == p.y)
538
                                        && ((testPoint.z == p.z) || (!(testPoint.z == testPoint.z)))) {
539
                                return true;
540
                        }
541
                }
542

    
543
                return false;
544
        }
545

    
546
        /***
547
         * 
548
         * @param mpolygon
549
         * @return
550
         */
551
        private static List<LineString3D> getPolygonsEasily(Geometry mpolygon) {
552
                boolean threed = false;
553

    
554
                if (mpolygon instanceof Surface2DZ) {
555
                        threed = true;
556
                }
557

    
558
                int start_ind = 0;
559
                int end_ind = 0;
560
                int ind = 0;
561
                int new_size;
562
                List<Coordinate> arrayCoords = null;
563
                List<LineString3D> resp = new ArrayList<LineString3D>();
564
                Coordinate[] points = null;
565
                int theType = -99;
566
                double[] theData = new double[6];
567
                Coordinate onlyCoord = null;
568
                int numParts = 0;
569

    
570
                PathIterator theIterator = mpolygon.getPathIterator(null, FLATNESS);
571

    
572
                while (!theIterator.isDone()) {
573
                        // while not done
574
                        theType = theIterator.currentSegment(theData);
575

    
576
                        if (onlyCoord == null) {
577
                                onlyCoord = new Coordinate();
578
                                onlyCoord.x = theData[0];
579
                                onlyCoord.y = theData[1];
580
                        }
581

    
582
                        switch (theType) {
583
                        case PathIterator.SEG_MOVETO:
584

    
585
                                if (arrayCoords == null) {
586
                                        arrayCoords = new ArrayList<Coordinate>();
587
                                } else {
588
                                        end_ind = ind - 1;
589

    
590
                                        arrayCoords = getClosedRelevantPolygon(arrayCoords);
591
                                        new_size = arrayCoords.size();
592

    
593
                                        if (arrayCoords != null) {
594
                                                points = CoordinateArrays
595
                                                                .toCoordinateArray(arrayCoords);
596

    
597
                                                try {
598
                                                        LinearRing aux = geomFactory
599
                                                                        .createLinearRing(points);
600
                                                        double[] z = null;
601

    
602
                                                        if (threed) {
603
                                                                z = getZ((Surface2DZ) mpolygon, start_ind,
604
                                                                                end_ind, new_size);
605
                                                        }
606

    
607
                                                        LineString3D ring = new LineString3D(aux, z);
608

    
609
                                                        if (CGAlgorithms.isCCW(points)) {
610
                                                                resp.add(ring);
611
                                                        } else {
612
                                                                resp.add(ring.createReverse());
613
                                                        }
614
                                                } catch (Exception e) {
615
                                                        logger.error("Topology exception: "
616
                                                                        + e.getMessage());
617

    
618
                                                        return null;
619
                                                }
620
                                        }
621

    
622
                                        arrayCoords = new ArrayList<Coordinate>();
623

    
624
                                        start_ind = ind;
625
                                }
626

    
627
                                numParts++;
628

    
629
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
630
                                ind++;
631

    
632
                                break;
633

    
634
                        case PathIterator.SEG_LINETO:
635
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
636
                                ind++;
637

    
638
                                break;
639

    
640
                        case PathIterator.SEG_QUADTO:
641
                                logger.info("SEG_QUADTO Not supported here");
642
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
643
                                arrayCoords.add(new Coordinate(theData[2], theData[3]));
644
                                ind++;
645
                                ind++;
646

    
647
                                break;
648

    
649
                        case PathIterator.SEG_CUBICTO:
650
                                logger.info("SEG_CUBICTO Not supported here");
651
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
652
                                arrayCoords.add(new Coordinate(theData[2], theData[3]));
653
                                arrayCoords.add(new Coordinate(theData[4], theData[5]));
654
                                ind++;
655
                                ind++;
656
                                ind++;
657

    
658
                                break;
659

    
660
                        case PathIterator.SEG_CLOSE:
661
                                break;
662
                        }
663

    
664
                        theIterator.next();
665
                }
666

    
667
                end_ind = ind - 1;
668

    
669
                // null shape:
670
                if (arrayCoords == null) {
671
                        arrayCoords = new ArrayList<Coordinate>();
672

    
673
                        Coordinate _c = new Coordinate(0, 0, 0);
674
                        arrayCoords.add(new Coordinate(_c));
675
                        arrayCoords.add(new Coordinate(_c));
676
                }
677

    
678
                // --------------------------------------------
679
                arrayCoords = getClosedRelevantPolygon(arrayCoords);
680
                new_size = arrayCoords.size();
681

    
682
                if (arrayCoords != null) {
683
                        points = CoordinateArrays.toCoordinateArray(arrayCoords);
684

    
685
                        try {
686
                                LinearRing aux = geomFactory.createLinearRing(points);
687
                                double[] z = null;
688

    
689
                                if (threed) {
690
                                        z = getZ((Surface2DZ) mpolygon, start_ind, end_ind,
691
                                                        new_size);
692
                                }
693

    
694
                                LineString3D ring = new LineString3D(aux, z);
695

    
696
                                if (CGAlgorithms.isCCW(points)) {
697
                                        resp.add(ring);
698
                                } else {
699
                                        resp.add(ring.createReverse());
700
                                }
701
                        } catch (Exception e) {
702
                                logger.error("Topology exception: " + e.getMessage());
703

    
704
                                return null;
705
                        }
706
                }
707

    
708
                if (resp.size() == 0) {
709
                        resp.add(new LineString3D(getMinLinearRing(onlyCoord),
710
                                        getMinLinearRingZ()));
711
                }
712

    
713
                return resp;
714
        }
715

    
716
        /**
717
         * Utility method to reverse an array of doubles.
718
         * 
719
         * @param _z
720
         *            an array of doubles to be reversed.
721
         * 
722
         * @return the reversed array of doubles
723
         */
724
        public static double[] reverseArray(double[] _z) {
725
                int size = _z.length;
726
                double[] resp = new double[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
        /**
736
         * Utility method to reverse an array of coordinates
737
         * 
738
         * @param _z
739
         *            an array of coordinaes to be reversed.
740
         * 
741
         * @return the reversed array of coordinates
742
         */
743
        public static Coordinate[] reverseCoordinateArray(Coordinate[] _z) {
744
                int size = _z.length;
745
                Coordinate[] resp = new Coordinate[size];
746

    
747
                for (int i = 0; i < size; i++) {
748
                        resp[i] = _z[size - 1 - i];
749
                }
750

    
751
                return resp;
752
        }
753

    
754
        /**
755
         * 
756
         * @param geom
757
         * @param _str
758
         * @param _end
759
         * @param size
760
         * @return
761
         */
762
        private static double[] getZ(Geometry geom, int _str, int _end, int size) {
763
                double[] resp = new double[size];
764

    
765
                double[] allz = new double[1];
766

    
767
                if (geom instanceof Point2DZ) {
768
                        allz[0] = ((Point2DZ) geom).getCoordinateAt(3);
769
                }
770
                if (geom instanceof Curve2DZ) {
771
                        Curve2DZ curve = (Curve2DZ) geom;
772
                        allz = new double[curve.getNumVertices()];
773
                        for (int i = 0; i < allz.length; i++) {
774
                                allz[i] = curve.getCoordinateAt(i, 3);
775
                        }
776
                }
777
                if (geom instanceof Surface2DZ) {
778
                        Surface2DZ surface = (Surface2DZ) geom;
779
                        allz = new double[surface.getNumVertices()];
780
                        for (int i = 0; i < allz.length; i++) {
781
                                allz[i] = surface.getCoordinateAt(i, 3);
782
                        }
783
                }
784

    
785
                for (int i = _str; ((i <= _end) && ((i - _str) < size)); i++) {
786
                        resp[i - _str] = allz[i];
787
                }
788

    
789
                if ((_end - _str + 1) < size) {
790
                        double repe = allz[_end];
791

    
792
                        for (int i = (_end - _str + 1); i < size; i++) {
793
                                resp[i] = repe;
794
                        }
795
                }
796
                return resp;
797
        }
798

    
799
        /**
800
         * 
801
         * @param mlines
802
         * @return
803
         */
804
        private static List<LineString3D> getLineStrings(Geometry mlines) {
805
                boolean threed = false;
806

    
807
                if (mlines instanceof Curve2DZ) {
808
                        threed = true;
809
                }
810

    
811
                int start_ind = 0;
812
                int end_ind = 0;
813
                int ind = 0;
814
                int new_size = 0;
815

    
816
                LineString3D lin;
817

    
818
                List<LineString3D> arrayLines = new ArrayList<LineString3D>();
819
                PathIterator theIterator = mlines.getPathIterator(null, FLATNESS);
820
                int theType = -99;
821
                double[] theData = new double[6];
822
                List<Coordinate> arrayCoords = null;
823
                int numParts = 0;
824

    
825
                while (!theIterator.isDone()) {
826
                        // while not done
827
                        theType = theIterator.currentSegment(theData);
828

    
829
                        switch (theType) {
830
                        case PathIterator.SEG_MOVETO:
831

    
832
                                if (arrayCoords == null) {
833
                                        arrayCoords = new ArrayList<Coordinate>();
834
                                } else {
835
                                        end_ind = ind - 1;
836
                                        arrayCoords = ensureSensibleLineString(arrayCoords);
837
                                        new_size = arrayCoords.size();
838

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

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

    
849
                                        lin = new LineString3D(aux, z);
850
                                        arrayLines.add(lin);
851
                                        arrayCoords = new ArrayList<Coordinate>();
852

    
853
                                        start_ind = ind;
854
                                }
855

    
856
                                numParts++;
857
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
858

    
859
                                break;
860

    
861
                        case PathIterator.SEG_LINETO:
862
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
863

    
864
                                break;
865

    
866
                        case PathIterator.SEG_QUADTO:
867
                                logger.info("Not supported here: SEG_QUADTO");
868

    
869
                                break;
870

    
871
                        case PathIterator.SEG_CUBICTO:
872
                                logger.info("Not supported here: SEG_CUBICTO");
873

    
874
                                break;
875

    
876
                        case PathIterator.SEG_CLOSE:
877

    
878
                                Coordinate firstCoord = (Coordinate) arrayCoords.get(0);
879
                                arrayCoords.add(new Coordinate(firstCoord.x, firstCoord.y));
880

    
881
                                break;
882
                        } // end switch
883

    
884
                        theIterator.next();
885
                        ind++;
886
                } // end while loop
887

    
888
                arrayCoords = ensureSensibleLineString(arrayCoords);
889
                new_size = arrayCoords.size();
890

    
891
                LineString aux = geomFactory.createLineString(CoordinateArrays
892
                                .toCoordinateArray(arrayCoords));
893
                double[] z = null;
894

    
895
                if (threed) {
896
                        z = getZ((Curve2DZ) mlines, start_ind, end_ind, new_size);
897
                }
898

    
899
                lin = new LineString3D(aux, z);
900
                arrayLines.add(lin);
901

    
902
                return arrayLines;
903
        }
904

    
905
        /**
906
         * 
907
         * @param ls
908
         * @param threed
909
         * @return
910
         */
911
        private static String lineStringToWKT(LineString3D ls, boolean threed) {
912
                String resp = "(";
913
                Coordinate[] cc = ls.getLs().getCoordinates();
914
                double[] z = ls.getZc();
915
                int size = cc.length;
916

    
917
                if (threed) {
918
                        for (int i = 0; i < size; i++) {
919
                                resp = resp + cc[i].x + " " + cc[i].y + " " + z[i] + ", ";
920
                        }
921

    
922
                        resp = resp.substring(0, resp.length() - 2);
923
                        resp = resp + ")";
924
                } else {
925
                        for (int i = 0; i < size; i++) {
926
                                resp = resp + cc[i].x + " " + cc[i].y + ", ";
927
                        }
928

    
929
                        resp = resp.substring(0, resp.length() - 2);
930
                        resp = resp + ")";
931
                }
932

    
933
                return resp;
934
        }
935

    
936
        /**
937
         * 
938
         * @param ml
939
         * @param threed
940
         * @return
941
         */
942
        private static String multiLineStringToWKT(List<LineString3D> ml,
943
                        boolean threed) {
944
                String resp = "MULTILINESTRING(";
945

    
946
                for (int i = 0; i < ml.size(); i++) {
947
                        LineString3D ls = ml.get(i);
948
                        resp = resp + lineStringToWKT(ls, threed) + ", ";
949
                }
950

    
951
                resp = resp.substring(0, resp.length() - 2) + ")";
952

    
953
                return resp;
954
        }
955

    
956
        /**
957
         * 
958
         * @param pols
959
         * @param threed
960
         * @return
961
         */
962
        private static String polygonsToWKT(List<LineString3D> pols, boolean threed) {
963
                String resp = "MULTIPOLYGON(";
964
                LineString3D ls = null;
965

    
966
                for (int i = 0; i < pols.size(); i++) {
967
                        ls = pols.get(i);
968
                        resp = resp + "(" + lineStringToWKT(ls, threed) + "), ";
969
                }
970

    
971
                resp = resp.substring(0, resp.length() - 2) + ")";
972

    
973
                return resp;
974
        }
975

    
976
        /**
977
         * 
978
         * @param shell
979
         * @param holes
980
         * @param threed
981
         * @return
982
         */
983
        private static String shellAndHolesToWKT(LineString3D shell,
984
                        List<LineString3D> holes, boolean threed) {
985
                String resp = "(";
986
                resp = resp + lineStringToWKT(shell, threed);
987

    
988
                if (holes.size() > 0) {
989
                        for (int i = 0; i < holes.size(); i++) {
990
                                LineString3D ls = holes.get(i);
991
                                resp = resp + ", " + lineStringToWKT(ls, threed);
992
                        }
993
                }
994

    
995
                resp = resp + ")";
996

    
997
                return resp;
998
        }
999

    
1000
        /**
1001
         * 
1002
         * @param shells
1003
         * @param hFs
1004
         * @param threed
1005
         * @return
1006
         */
1007
        private static String multiPolygonToWKT(List<LineString3D> shells,
1008
                        List<List<LineString3D>> hFs, boolean threed) {
1009
                String resp = "MULTIPOLYGON(";
1010
                LineString3D ls = null;
1011
                List<LineString3D> holes;
1012

    
1013
                for (int i = 0; i < shells.size(); i++) {
1014
                        ls = shells.get(i);
1015
                        holes = hFs.get(i);
1016
                        resp = resp + shellAndHolesToWKT(ls, holes, threed) + ", ";
1017
                }
1018

    
1019
                resp = resp.substring(0, resp.length() - 2) + ")";
1020

    
1021
                return resp;
1022
        }
1023

    
1024
        /**
1025
         * 
1026
         * @param point
1027
         * @param threed
1028
         * @return
1029
         */
1030
        private static String pointToWKT(Point point, boolean threed) {
1031
                String resp = "POINT(" + point.getX() + " " + point.getY();
1032

    
1033
                if ((threed) && (point instanceof Point2DZ)) {
1034
                        resp = resp + " " + ((Point2DZ) point).getCoordinateAt(3);
1035
                }
1036

    
1037
                resp = resp + ")";
1038

    
1039
                return resp;
1040
        }
1041

    
1042
        /**
1043
         * 
1044
         * @param n
1045
         * @param d
1046
         * @return
1047
         */
1048
        private static int twoDIndexToDimsIndex(int n, int d) {
1049
                return ((d * (n - 1)) / 2) + 1;
1050
        }
1051

    
1052
        /**
1053
         * 
1054
         * @param old
1055
         * @param d
1056
         * @return
1057
         * @throws SQLException
1058
         */
1059
        private static ARRAY setSubelementsToDim(ARRAY old, int d)
1060
                        throws SQLException {
1061
                Datum[] infos = (Datum[]) old.getOracleArray();
1062

    
1063
                for (int i = 3; i < infos.length; i = i + 3) {
1064
                        int oldind = infos[i].intValue();
1065
                        oldind = twoDIndexToDimsIndex(oldind, d);
1066
                        infos[i] = new NUMBER(oldind);
1067

    
1068
                        //
1069
                        oldind = infos[i + 1].intValue();
1070
                        infos[i + 1] = new NUMBER(infos[1].intValue());
1071
                }
1072

    
1073
                ARRAY resp = new ARRAY(old.getDescriptor(), old.getOracleConnection(),
1074
                                infos);
1075

    
1076
                return resp;
1077
        }
1078

    
1079
        /**
1080
         * 
1081
         * @param p
1082
         * @param ls
1083
         * @return
1084
         */
1085
        private static boolean isPointInsideLineString(Coordinate p, LineString ls) {
1086
                com.vividsolutions.jts.geom.Envelope env = ls.getEnvelopeInternal();
1087

    
1088
                if (!env.contains(p)) {
1089
                        return false;
1090
                }
1091

    
1092
                return CGAlgorithms.isPointInRing(p, ls.getCoordinates());
1093
        }
1094

    
1095
        /**
1096
         * 
1097
         * @param contained
1098
         * @param container
1099
         * @return
1100
         */
1101
        private static boolean lineString3DIsContainedBy(LineString3D contained,
1102
                        LineString3D container) {
1103
                int samples = 10;
1104
                LineString _in = contained.getLs();
1105
                LineString _out = container.getLs();
1106
                Coordinate[] inc = _in.getCoordinates();
1107
                Coordinate aux;
1108
                int size = inc.length;
1109

    
1110
                if (size <= 10) {
1111
                        for (int i = 0; i < size; i++) {
1112
                                aux = inc[i];
1113

    
1114
                                if (!isPointInsideLineString(aux, _out)) {
1115
                                        return false;
1116
                                }
1117
                        }
1118

    
1119
                        return true;
1120
                } else {
1121
                        for (int i = 0; i < samples; i++) {
1122
                                aux = inc[rnd.nextInt(size)];
1123

    
1124
                                if (!isPointInsideLineString(aux, _out)) {
1125
                                        return false;
1126
                                }
1127
                        }
1128

    
1129
                        return true;
1130
                }
1131
        }
1132

    
1133
        /**
1134
         * Transform multipolygons2d or 2dz to Oracle STRUCT
1135
         * 
1136
         * @param pols
1137
         * @param srid
1138
         * @param threed
1139
         * @param _conn
1140
         * @param agu_bien
1141
         * @param hasSrid
1142
         * @return
1143
         * @throws SQLException
1144
         */
1145
        private static STRUCT getMultiPolygonAsStruct(List<LineString3D> pols,
1146
                        int osrid, boolean threed, Connection conn, boolean agu_bien,
1147
                        boolean hasSrid) throws SQLException {
1148
                int size = pols.size();
1149
                int geotype = 2007;
1150
                int dim = 2;
1151
                int acum = 0;
1152

    
1153
                if (threed) {
1154
                        geotype = 3007;
1155
                        dim = 3;
1156
                }
1157

    
1158
                NUMBER[] indices = new NUMBER[3 * size];
1159

    
1160
                for (int i = 0; i < size; i++) {
1161
                        indices[3 * i] = new NUMBER(acum + 1);
1162
                        indices[(3 * i) + 1] = new NUMBER(1003);
1163
                        indices[(3 * i) + 2] = new NUMBER(1);
1164
                        acum = acum + (dim * (pols.get(i)).getLs().getNumPoints());
1165
                }
1166

    
1167
                int _ind = 0;
1168
                NUMBER[] ords = new NUMBER[acum];
1169

    
1170
                for (int i = 0; i < size; i++) {
1171
                        LineString3D ls = (LineString3D) pols.get(i);
1172
                        int num_p = ls.getLs().getNumPoints();
1173

    
1174
                        for (int j = 0; j < num_p; j++) {
1175
                                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1176
                                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1177

    
1178
                                if (threed) {
1179
                                        ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1180
                                }
1181

    
1182
                                _ind = _ind + dim;
1183
                        }
1184
                }
1185

    
1186
                STRUCT resp;
1187
                StructDescriptor dsc = StructDescriptor.createDescriptor(
1188
                                "MDSYS.SDO_GEOMETRY", conn);
1189
                Object[] obj = new Object[5];
1190
                obj[0] = new NUMBER(geotype);
1191

    
1192
                if (hasSrid) {
1193
                        obj[1] = new NUMBER(osrid);
1194
                } else {
1195
                        obj[1] = null;
1196
                }
1197

    
1198
                obj[2] = null;
1199
                obj[3] = indices;
1200
                obj[4] = ords;
1201
                resp = new STRUCT(dsc, conn, obj);
1202

    
1203
                return resp;
1204
        }
1205

    
1206
        /**
1207
         * 
1208
         * @param lines
1209
         * @param srid
1210
         * @param threed
1211
         * @param _conn
1212
         * @param hasSrid
1213
         * @return
1214
         * @throws SQLException
1215
         */
1216
        private static STRUCT getMultiLineAsStruct(List<LineString3D> lines,
1217
                        int osrid, boolean threed, Connection conn, boolean hasSrid)
1218
                        throws SQLException {
1219

    
1220
                int size = lines.size();
1221
                int geotype = 2006;
1222
                
1223
        if (size == 1) {
1224
            geotype = 2002;
1225
        }
1226

    
1227
        
1228
                int dim = 2;
1229
                int acum = 0;
1230

    
1231
                if (threed) {
1232
                        geotype = 3006;
1233
            if (size == 1) {
1234
                geotype = 3002;
1235
            }
1236
                        dim = 3;
1237
                }
1238

    
1239
                NUMBER[] indices = new NUMBER[3 * size];
1240

    
1241
                for (int i = 0; i < size; i++) {
1242
                        indices[3 * i] = new NUMBER(acum + 1);
1243
                        indices[(3 * i) + 1] = new NUMBER(2);
1244
                        indices[(3 * i) + 2] = new NUMBER(1);
1245
                        acum = acum + (dim * (lines.get(i)).getLs().getNumPoints());
1246
                }
1247

    
1248
                int _ind = 0;
1249
                NUMBER[] ords = new NUMBER[acum];
1250

    
1251
                for (int i = 0; i < size; i++) {
1252
                        LineString3D ls = lines.get(i);
1253
                        int num_p = ls.getLs().getNumPoints();
1254

    
1255
                        for (int j = 0; j < num_p; j++) {
1256
                                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1257
                                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1258

    
1259
                                if (threed) {
1260
                                        ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1261
                                }
1262

    
1263
                                _ind = _ind + dim;
1264
                        }
1265
                }
1266

    
1267
                STRUCT resp;
1268
                StructDescriptor dsc = StructDescriptor.createDescriptor(
1269
                                "MDSYS.SDO_GEOMETRY", conn);
1270
                Object[] obj = new Object[5];
1271
                obj[0] = new NUMBER(geotype);
1272

    
1273
                if (hasSrid) {
1274
                        obj[1] = new NUMBER(osrid);
1275
                } else {
1276
                        obj[1] = null;
1277
                }
1278

    
1279
                obj[2] = null;
1280
                obj[3] = indices;
1281
                obj[4] = ords;
1282
                resp = new STRUCT(dsc, conn, obj);
1283

    
1284
                return resp;
1285
        }
1286

    
1287
        /**
1288
         * 
1289
         * @param pnt
1290
         * @param srid
1291
         * @param threed
1292
         * @param _conn
1293
         * @param hasSrid
1294
         * @return
1295
         * @throws SQLException
1296
         */
1297
        private static STRUCT getMultiPointAsStruct(Coordinate pnt, int osrid,
1298
                        boolean threed, Connection conn, boolean hasSrid)
1299
                        throws SQLException {
1300
                int geotype = 2001;
1301
                int dim = 2;
1302

    
1303
                if (threed) {
1304
                        geotype = 3001;
1305
                        dim = 3;
1306
                }
1307

    
1308
                Object[] ords = new Object[3];
1309
                ords[0] = new NUMBER(pnt.x);
1310
                ords[1] = new NUMBER(pnt.y);
1311
                ords[2] = (dim == 3) ? new NUMBER(pnt.z) : null;
1312

    
1313
                StructDescriptor ord_dsc = StructDescriptor.createDescriptor(
1314
                                "MDSYS.SDO_POINT_TYPE", conn);
1315
                STRUCT ords_st = new STRUCT(ord_dsc, conn, ords);
1316

    
1317
                STRUCT resp;
1318

    
1319
                StructDescriptor dsc = StructDescriptor.createDescriptor(
1320
                                "MDSYS.SDO_GEOMETRY", conn);
1321
                Object[] obj = new Object[5];
1322

    
1323
                obj[0] = new NUMBER(geotype);
1324

    
1325
                if (hasSrid) {
1326
                        obj[1] = new NUMBER(osrid);
1327
                } else {
1328
                        obj[1] = null;
1329
                }
1330

    
1331
                obj[2] = ords_st;
1332
                obj[3] = null;
1333
                obj[4] = null;
1334
                resp = new STRUCT(dsc, conn, obj);
1335

    
1336
                return resp;
1337
        }
1338

    
1339
        /**
1340
         * Utility method to compute a circle's center and radius from three given
1341
         * points.
1342
         * 
1343
         * @param points
1344
         *            three points of a circumference
1345
         * @return a 2-item array with the circumference's center (Point2D) and
1346
         *         radius (Double)
1347
         */
1348
        public static Object[] getCenterAndRadiousOfCirc(Point2D[] points) {
1349
                Object[] resp = new Object[2];
1350
                resp[0] = new Point2D.Double(0, 0);
1351
                resp[1] = new Double(0);
1352

    
1353
                double m11;
1354
                double m12;
1355
                double m13;
1356
                double m14;
1357

    
1358
                if (points.length != 3) {
1359
                        logger.error("Needs 3 points (found " + points.length
1360
                                        + ") - circle cannot be computed.");
1361

    
1362
                        // not a circle
1363
                        return resp;
1364
                }
1365

    
1366
                double[][] a = new double[3][3];
1367

    
1368
                for (int i = 0; i < 3; i++) { // find minor 11
1369
                        a[i][0] = points[i].getX();
1370
                        a[i][1] = points[i].getY();
1371
                        a[i][2] = 1;
1372
                }
1373

    
1374
                m11 = determinant(a, 3);
1375

    
1376
                for (int i = 0; i < 3; i++) { // find minor 12
1377
                        a[i][0] = (points[i].getX() * points[i].getX())
1378
                                        + (points[i].getY() * points[i].getY());
1379
                        a[i][1] = points[i].getY();
1380
                        a[i][2] = 1;
1381
                }
1382

    
1383
                m12 = determinant(a, 3);
1384

    
1385
                for (int i = 0; i < 3; i++) // find minor 13
1386
                {
1387
                        a[i][0] = (points[i].getX() * points[i].getX())
1388
                                        + (points[i].getY() * points[i].getY());
1389
                        a[i][1] = points[i].getX();
1390
                        a[i][2] = 1;
1391
                }
1392

    
1393
                m13 = determinant(a, 3);
1394

    
1395
                for (int i = 0; i < 3; i++) { // find minor 14
1396
                        a[i][0] = (points[i].getX() * points[i].getX())
1397
                                        + (points[i].getY() * points[i].getY());
1398
                        a[i][1] = points[i].getX();
1399
                        a[i][2] = points[i].getY();
1400
                }
1401

    
1402
                m14 = determinant(a, 3);
1403

    
1404
                Double resp_radius = new Double(0);
1405
                Point2D resp_center = new Point2D.Double(0, 0);
1406

    
1407
                if (m11 == 0) {
1408
                        logger.error("Three points aligned - circle cannot be computed."); // not
1409
                        // a
1410
                        // circle
1411
                } else {
1412
                        double x = (0.5 * m12) / m11;
1413
                        double y = (-0.5 * m13) / m11;
1414
                        resp_center.setLocation(x, y);
1415
                        resp_radius = new Double(Math.sqrt((x * x) + (y * y) + (m14 / m11)));
1416
                        resp[0] = resp_center;
1417
                        resp[1] = resp_radius;
1418
                }
1419

    
1420
                return resp;
1421
        }
1422

    
1423
        /**
1424
         * Utility method to compute a matrix determinant
1425
         * 
1426
         * @param a
1427
         *            the matrix
1428
         * @param n
1429
         *            matrix size
1430
         * @return the matrix's determinant
1431
         */
1432
        public static double determinant(double[][] a, int n) {
1433
                double resp = 0;
1434
                double[][] m = new double[3][3];
1435

    
1436
                if (n == 2) { // terminate recursion
1437
                        resp = (a[0][0] * a[1][1]) - (a[1][0] * a[0][1]);
1438
                } else {
1439
                        resp = 0;
1440

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

    
1443
                                for (int i = 1; i < n; i++) { // create minor
1444

    
1445
                                        int j2 = 0;
1446

    
1447
                                        for (int j = 0; j < n; j++) {
1448
                                                if (j == j1) {
1449
                                                        continue;
1450
                                                }
1451

    
1452
                                                m[i - 1][j2] = a[i][j];
1453
                                                j2++;
1454
                                        }
1455
                                }
1456

    
1457
                                // sum (+/-)cofactor * minor
1458
                                resp = resp
1459
                                                + (Math.pow(-1.0, j1) * a[0][j1] * determinant(m, n - 1));
1460
                        }
1461
                }
1462

    
1463
                return resp;
1464
        }
1465

    
1466
        /**
1467
         * 
1468
         * @param ls
1469
         * @param list
1470
         * @param self
1471
         * @return
1472
         */
1473
        private static int getSmallestContainerExcept(LineString3D ls,
1474
                        List<LineString3D> list, int self) {
1475
                int resp = -1;
1476
                List<Integer> provList = new ArrayList<Integer>();
1477

    
1478
                int size = list.size();
1479

    
1480
                for (int i = 0; i < self; i++) {
1481
                        if (lineString3DIsContainedBy(ls, list.get(i))) {
1482
                                provList.add(new Integer(i));
1483
                        }
1484
                }
1485

    
1486
                for (int i = (self + 1); i < size; i++) {
1487
                        if (lineString3DIsContainedBy(ls, (LineString3D) list.get(i))) {
1488
                                provList.add(new Integer(i));
1489
                        }
1490
                }
1491

    
1492
                if (provList.size() == 0) {
1493
                        // logger.debug("LineString is not contained by any other ls.");
1494
                } else {
1495
                        if (provList.size() == 1) {
1496
                                resp = ((Integer) provList.get(0)).intValue();
1497
                        } else {
1498
                                if (provList.size() == 2) {
1499
                                        int ind_1 = ((Integer) provList.get(0)).intValue();
1500
                                        int ind_2 = ((Integer) provList.get(1)).intValue();
1501
                                        LineString3D ls1 = (LineString3D) list.get(ind_1);
1502
                                        LineString3D ls2 = (LineString3D) list.get(ind_2);
1503

    
1504
                                        if (lineString3DIsContainedBy(ls1, ls2)) {
1505
                                                resp = ind_1;
1506
                                        } else {
1507
                                                resp = ind_2;
1508
                                        }
1509
                                } else {
1510
                                        // not so deep, sorry!
1511
                                        // it's going to be a shell: resp = -1;
1512
                                }
1513
                        }
1514
                }
1515

    
1516
                return resp;
1517
        }
1518

    
1519
        /**
1520
         * 
1521
         * @param containings
1522
         * @return
1523
         */
1524
        private static int[] getIndicesOfShells(int[] containings) {
1525
                List<Integer> resp = new ArrayList<Integer>();
1526

    
1527
                for (int i = 0; i < containings.length; i++) {
1528
                        if (containings[i] == -1) {
1529
                                resp.add(new Integer(i));
1530
                        }
1531
                }
1532

    
1533
                int size = resp.size();
1534
                int[] _resp = new int[size];
1535

    
1536
                for (int i = 0; i < size; i++) {
1537
                        _resp[i] = (resp.get(i)).intValue();
1538
                }
1539

    
1540
                return _resp;
1541
        }
1542

    
1543
        /**
1544
         * 
1545
         * @param containings
1546
         * @param shells
1547
         * @return
1548
         */
1549
        private static int[] getIndicesOfHoles(int[] containings, int[] shells) {
1550
                List<Integer> resp = new ArrayList<Integer>();
1551

    
1552
                for (int i = 0; i < containings.length; i++) {
1553
                        int cont_by = containings[i];
1554

    
1555
                        if ((cont_by != -1) && (isOneOf(cont_by, shells))) {
1556
                                resp.add(new Integer(i));
1557
                        }
1558
                }
1559

    
1560
                int size = resp.size();
1561
                int[] _resp = new int[size];
1562

    
1563
                for (int i = 0; i < size; i++) {
1564
                        _resp[i] = (resp.get(i)).intValue();
1565
                }
1566

    
1567
                return _resp;
1568
        }
1569

    
1570
        /**
1571
         * 
1572
         * @param containings
1573
         * @param holes
1574
         * @return
1575
         */
1576
        private static int[] getFinalContainings(int[] containings, int[] holes) {
1577
                List<Integer> resp = new ArrayList<Integer>();
1578

    
1579
                for (int i = 0; i < containings.length; i++) {
1580
                        int cont_by = containings[i];
1581

    
1582
                        if (isOneOf(cont_by, holes)) {
1583
                                resp.add(new Integer(-1));
1584
                        } else {
1585
                                resp.add(new Integer(cont_by));
1586
                        }
1587
                }
1588

    
1589
                int size = resp.size();
1590
                int[] _resp = new int[size];
1591

    
1592
                for (int i = 0; i < size; i++) {
1593
                        _resp[i] = ((Integer) resp.get(i)).intValue();
1594
                }
1595

    
1596
                return _resp;
1597
        }
1598

    
1599
        /**
1600
         * 
1601
         * @param ind
1602
         * @param final_contn
1603
         * @param all
1604
         * @return
1605
         */
1606
        private static List<LineString3D> getHolesOf(int ind, int[] final_contn,
1607
                        List<LineString3D> all) {
1608

    
1609
                List<Integer> resp_ind = new ArrayList<Integer>();
1610

    
1611
                for (int i = 0; i < final_contn.length; i++) {
1612
                        if (final_contn[i] == ind) {
1613
                                resp_ind.add(new Integer(i));
1614
                        }
1615
                }
1616

    
1617
                List<LineString3D> resp = new ArrayList<LineString3D>();
1618

    
1619
                for (int i = 0; i < resp_ind.size(); i++) {
1620
                        Integer aux = (Integer) resp_ind.get(i);
1621
                        resp.add(all.get(aux.intValue()));
1622
                }
1623

    
1624
                return resp;
1625
        }
1626

    
1627
        /**
1628
         * 
1629
         * @param final_contn
1630
         * @param all
1631
         * @return
1632
         */
1633
        private static List<LineString3D> getShellsIn(int[] final_contn,
1634
                        List<LineString3D> all) {
1635
                List<Integer> resp_ind = new ArrayList<Integer>();
1636

    
1637
                for (int i = 0; i < final_contn.length; i++) {
1638
                        if (final_contn[i] == -1) {
1639
                                resp_ind.add(new Integer(i));
1640
                        }
1641
                }
1642

    
1643
                List<LineString3D> resp = new ArrayList<LineString3D>();
1644

    
1645
                for (int i = 0; i < resp_ind.size(); i++) {
1646
                        Integer aux = (Integer) resp_ind.get(i);
1647
                        resp.add(all.get(aux.intValue()));
1648
                }
1649

    
1650
                return resp;
1651
        }
1652

    
1653
        /**
1654
         * This method tries to guess who is a shell and who is a hole from a set of
1655
         * linestrings.
1656
         * 
1657
         * @param all_ls
1658
         *            a set of linestrings to be checked.
1659
         * 
1660
         * @return a 2-item array. the first is an arraylist of linestrings thought
1661
         *         to be shells. the second is an array of arraylists containing the
1662
         *         holes of each shell found in the first item
1663
         * 
1664
         */
1665
        public static Object[] getHolesForShells(List<LineString3D> all_ls) {
1666
                int no_of_ls = all_ls.size();
1667
                int[] containedby = new int[no_of_ls];
1668
                int[] shells;
1669
                int[] holes;
1670
                int[] final_cont;
1671

    
1672
                for (int i = 0; i < no_of_ls; i++) {
1673
                        LineString3D ls_aux = all_ls.get(i);
1674
                        containedby[i] = getSmallestContainerExcept(ls_aux, all_ls, i);
1675
                }
1676

    
1677
                shells = getIndicesOfShells(containedby);
1678
                holes = getIndicesOfHoles(containedby, shells);
1679
                final_cont = getFinalContainings(containedby, holes);
1680

    
1681
                // true shells:
1682
                shells = getIndicesOfShells(final_cont);
1683

    
1684
                List<LineString3D> resp_shells = new ArrayList<LineString3D>();
1685
                List resp_holes_for_shells = new ArrayList();
1686
                List<LineString3D> aux_holes;
1687

    
1688
                for (int i = 0; i < shells.length; i++) {
1689
                        resp_shells.add(all_ls.get(shells[i]));
1690
                        aux_holes = getHolesOf(i, final_cont, all_ls);
1691
                        resp_holes_for_shells.add(aux_holes);
1692
                }
1693

    
1694
                Object[] _resp = new Object[2];
1695
                _resp[0] = resp_shells;
1696
                _resp[1] = resp_holes_for_shells;
1697

    
1698
                return _resp;
1699
        }
1700

    
1701
        /**
1702
         * 
1703
         * @param listOfLists
1704
         * @return
1705
         */
1706
        private static int getTotalSize(List listOfLists) {
1707
                int resp = 0;
1708

    
1709
                for (int i = 0; i < listOfLists.size(); i++) {
1710
                        resp = resp + ((List) listOfLists.get(i)).size();
1711
                }
1712

    
1713
                return resp;
1714
        }
1715

    
1716
        /**
1717
         * 
1718
         * @param mpol
1719
         * @param srid
1720
         * @param threed
1721
         * @param _conn
1722
         * @param agu_bien
1723
         * @param hasSrid
1724
         * @return
1725
         * @throws SQLException
1726
         */
1727
        private static STRUCT getMultiPolygonAsStruct(Geometry mpol, int osrid,
1728
                        boolean threed, Connection conn, boolean agu_bien, boolean hasSrid)
1729
                        throws SQLException {
1730
                List<LineString3D> all_ls = getPolygonsEasily(mpol);
1731
                Object[] hs = getHolesForShells(all_ls);
1732
                List sh = (List) hs[0];
1733
                List _ho = (List) hs[1];
1734
                List ho = reverseHoles(_ho);
1735

    
1736
                STRUCT st = null;
1737
                
1738
                try {
1739
                        st = getMultiPolygonAsStruct(sh, ho, osrid, threed, conn, agu_bien, hasSrid);
1740
                } catch (Throwable th) {
1741
                        throw new SQLException(th.getMessage());
1742
                }
1743

    
1744
                return st; 
1745
        }
1746

    
1747
        /**
1748
         * 
1749
         * @param hh
1750
         * @return
1751
         */
1752
        private static List reverseHoles(List hh) {
1753
                List resp = new ArrayList();
1754

    
1755
                for (int i = 0; i < hh.size(); i++) {
1756
                        List item = (ArrayList) hh.get(i);
1757
                        List newitem = new ArrayList();
1758

    
1759
                        for (int j = 0; j < item.size(); j++) {
1760
                                LineString3D ls = (LineString3D) item.get(j);
1761
                                newitem.add(ls.createReverse());
1762
                        }
1763

    
1764
                        resp.add(newitem);
1765
                }
1766

    
1767
                return resp;
1768
        }
1769

    
1770
        /**
1771
         * 
1772
         * @param shells
1773
         * @param holes
1774
         * @param srid
1775
         * @param threed
1776
         * @param _conn
1777
         * @param explicito
1778
         * @param hasSrid
1779
         * @return
1780
         * @throws SQLException
1781
         */
1782
        private static STRUCT getMultiPolygonAsStruct(List shells, List holes,
1783
                        int osrid, boolean threed, Connection conn, boolean explicito,
1784
                        boolean hasSrid) throws SQLException {
1785
                int t = 1003;
1786

    
1787
                if (explicito) {
1788
                        t = 2003;
1789
                }
1790

    
1791
                int size = shells.size() + getTotalSize(holes);
1792
                int geotype = 2003;
1793
                if (size > 1)
1794
                        geotype = 2007;
1795

    
1796
                int dim = 2;
1797

    
1798
                if (threed) {
1799
                        geotype = geotype + 1000;
1800
                        dim = 3;
1801
                }
1802

    
1803
                NUMBER[] indices = new NUMBER[3 * size];
1804

    
1805
                int acum = 0;
1806
                int start_ind = 0;
1807

    
1808
                for (int i = 0; i < shells.size(); i++) {
1809
                        indices[start_ind] = new NUMBER(acum + 1);
1810
                        indices[start_ind + 1] = new NUMBER(1003);
1811
                        indices[start_ind + 2] = new NUMBER(1);
1812
                        start_ind = start_ind + 3;
1813
                        acum = acum + (dim * ((LineString3D) shells.get(i)).getLs().getNumPoints());
1814

    
1815
                        List item_holes = (List) holes.get(i);
1816

    
1817
                        for (int j = 0; j < item_holes.size(); j++) {
1818
                                indices[start_ind] = new NUMBER(acum + 1);
1819
                                indices[start_ind + 1] = new NUMBER(t); // 1003
1820
                                indices[start_ind + 2] = new NUMBER(1);
1821
                                start_ind = start_ind + 3;
1822
                                acum = acum
1823
                                                + (dim * ((LineString3D) item_holes.get(j)).getLs()
1824
                                                                .getNumPoints());
1825
                        }
1826
                }
1827

    
1828
                int _ind = 0;
1829
                NUMBER[] ords = new NUMBER[acum];
1830

    
1831
                for (int i = 0; i < shells.size(); i++) {
1832
                        // --------------------------------
1833
                        LineString3D ls = (LineString3D) shells.get(i);
1834
                        int num_p = ls.getLs().getNumPoints();
1835

    
1836
                        for (int j = 0; j < num_p; j++) {
1837
                                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1838
                                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1839

    
1840
                                if (threed) {
1841
                                        ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1842
                                }
1843

    
1844
                                _ind = _ind + dim;
1845
                        }
1846

    
1847
                        // -------------------------------
1848
                        List item_holes = (ArrayList) holes.get(i);
1849

    
1850
                        for (int j = 0; j < item_holes.size(); j++) {
1851
                                ls = (LineString3D) item_holes.get(j);
1852
                                num_p = ls.getLs().getNumPoints();
1853

    
1854
                                for (int k = 0; k < num_p; k++) {
1855
                                        ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(k).x);
1856
                                        ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(k).y);
1857

    
1858
                                        if (threed) {
1859
                                                ords[_ind + 2] = new NUMBER(ls.getZc()[k]);
1860
                                        }
1861

    
1862
                                        _ind = _ind + dim;
1863
                                }
1864
                        }
1865
                }
1866

    
1867
                STRUCT resp;
1868
                StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY", conn);
1869
                Object[] obj = new Object[5];
1870
                obj[0] = new NUMBER(geotype);
1871

    
1872
                if (hasSrid) {
1873
                        obj[1] = new NUMBER(osrid);
1874
                } else {
1875
                        obj[1] = null;
1876
                }
1877

    
1878
                obj[2] = null;
1879
                obj[3] = indices;
1880
                obj[4] = ords;
1881

    
1882
                resp = new STRUCT(dsc, conn, obj);
1883

    
1884
                return resp;
1885
        }
1886

    
1887
        /**
1888
         * 
1889
         * @param array
1890
         * @return
1891
         */
1892
        public static String printArray(NUMBER[] array) {
1893
                String resp = "[ ";
1894

    
1895
                for (int i = 0; i < array.length; i++) {
1896
                        resp = resp + " " + array[i].doubleValue() + " , ";
1897
                }
1898

    
1899
                resp = resp.substring(0, resp.length() - 2) + "]";
1900

    
1901
                return resp;
1902
        }
1903

    
1904
        /**
1905
         * 
1906
         * @param ind
1907
         * @param list
1908
         * @return
1909
         */
1910
        private static boolean isOneOf(int ind, int[] list) {
1911
                for (int i = 0; i < list.length; i++) {
1912
                        if (list[i] == ind) {
1913
                                return true;
1914
                        }
1915
                }
1916
                return false;
1917
        }
1918

    
1919
        /**
1920
         * This method appends the geometries from a geometries array in one STRUCT.
1921
         * 
1922
         * @param co
1923
         *            the geometry collection
1924
         * @param _forced_type
1925
         *            a type that has to be used as the struct's main type
1926
         * @param _conn
1927
         *            the connection
1928
         * @param _o_srid
1929
         *            the geometry's SRS (oracle code)
1930
         * @param withSrid
1931
         *            whether the SRS is non-NULL
1932
         * @param agu_bien
1933
         *            whether to check holes' validity
1934
         * @param _isGeoCS
1935
         *            whether the SRS is geodetic
1936
         * @return the STRUCT with the appended geometries
1937
         * @throws SQLException
1938
         */
1939
        public static STRUCT appendGeometriesInStruct(Geometry[] geoms,
1940
                        int _forced_type, Connection conn, String osrid, boolean withSrid,
1941
                        boolean agu_bien, boolean _isGeoCS) throws SQLException {
1942
                int osridd = Integer.parseInt(osrid);
1943
                int size = geoms.length;
1944
                STRUCT[] sts = new STRUCT[size];
1945

    
1946
                for (int i = 0; i < size; i++) {
1947
                        Geometry geom = geoms[i];
1948
                        sts[i] = geometryToSTRUCT(geom, conn, osridd, agu_bien, withSrid);
1949
                }
1950

    
1951
                if (size == 1) {
1952
                        return sts[0];
1953
                }
1954

    
1955
                STRUCT aux = sts[0];
1956

    
1957
                for (int i = 1; i < size; i++) {
1958
                        aux = appendStructs(aux, sts[i], conn);
1959
                }
1960

    
1961
                return aux;
1962
        }
1963

    
1964
        /**
1965
         * 
1966
         * @param st1
1967
         * @param st2
1968
         * @param _conn
1969
         * @return
1970
         */
1971
        private static STRUCT appendStructs(STRUCT st1, STRUCT st2, Connection conn) {
1972
                try {
1973
                        ARRAY _ords = (ARRAY) st1.getOracleAttributes()[4];
1974
                        int length_of_head_ords = _ords.getOracleArray().length;
1975

    
1976
                        NUMBER gtype = new NUMBER(
1977
                                        4 + (((NUMBER) st1.getOracleAttributes()[0]).intValue() / 1000));
1978
                        NUMBER srid = (NUMBER) st1.getOracleAttributes()[1];
1979
                        NUMBER middle = (NUMBER) st1.getOracleAttributes()[2];
1980

    
1981
                        ARRAY info1 = (ARRAY) st1.getOracleAttributes()[3];
1982
                        ARRAY info2 = (ARRAY) st2.getOracleAttributes()[3];
1983
                        ARRAY ords1 = (ARRAY) st1.getOracleAttributes()[4];
1984
                        ARRAY ords2 = (ARRAY) st2.getOracleAttributes()[4];
1985

    
1986
                        Datum[] info = appendDatumArrays(info1.getOracleArray(), info2
1987
                                        .getOracleArray(), length_of_head_ords);
1988

    
1989
                        Datum[] ords = appendDatumArrays(ords1.getOracleArray(), ords2
1990
                                        .getOracleArray(), 0);
1991

    
1992
                        StructDescriptor dsc = st1.getDescriptor();
1993

    
1994
                        Object[] atts = new Object[5];
1995
                        atts[0] = gtype;
1996
                        atts[1] = srid;
1997
                        atts[2] = middle;
1998
                        atts[3] = info;
1999
                        atts[4] = ords;
2000

    
2001
                        STRUCT resp = new STRUCT(dsc, conn, atts);
2002

    
2003
                        return resp;
2004
                } catch (SQLException sqle) {
2005
                        logger.error("While appending structs: " + sqle.getMessage(), sqle);
2006
                }
2007

    
2008
                return null;
2009
        }
2010

    
2011
        /**
2012
         * 
2013
         * @param head
2014
         * @param tail
2015
         * @param offset
2016
         * @return
2017
         */
2018
        private static Datum[] appendDatumArrays(Datum[] head, Datum[] tail,
2019
                        int offset) {
2020
                int head_l = head.length;
2021
                int tail_l = tail.length;
2022
                Datum[] resp = new Datum[head_l + tail_l];
2023

    
2024
                for (int i = 0; i < head_l; i++)
2025
                        resp[i] = head[i];
2026

    
2027
                if (offset == 0) {
2028
                        for (int i = 0; i < tail_l; i++)
2029
                                resp[head_l + i] = tail[i];
2030
                } else {
2031
                        try {
2032
                                for (int i = 0; i < tail_l; i++) {
2033
                                        if ((i % 3) == 0) {
2034
                                                resp[head_l + i] = new NUMBER(tail[i].intValue()
2035
                                                                + offset);
2036
                                        } else {
2037
                                                resp[head_l + i] = tail[i];
2038
                                        }
2039
                                }
2040
                        } catch (SQLException se) {
2041
                                logger.error("Unexpected error: " + se.getMessage());
2042
                        }
2043
                }
2044

    
2045
                return resp;
2046
        }
2047

    
2048
        /**
2049
         * Utility method to get an ineteger as a formatted string.
2050
         * 
2051
         * @param n
2052
         *            the integer
2053
         * @return the formatted string
2054
         */
2055
        public static String getFormattedInteger(int n) {
2056
                df.setGroupingUsed(true);
2057
                df.setGroupingSize(3);
2058
                dfs.setGroupingSeparator('.');
2059
                df.setDecimalFormatSymbols(dfs);
2060

    
2061
                return df.format(n);
2062
        }
2063

    
2064
        /**
2065
         * Tells whether these arrays belong to a rectangle polygon.
2066
         * 
2067
         * @param info
2068
         *            the struct's element info array
2069
         * @param ords
2070
         *            the struct's coordinate array
2071
         * @return true if it is a rectangle polygon. false otherwise.
2072
         */
2073
        public static boolean polStructIsRectStruct(ARRAY info, ARRAY ords) {
2074
                try {
2075
                        int[] infos = info.getIntArray();
2076

    
2077
                        return ((infos[2] == 3) && (infos.length == 3));
2078
                } catch (SQLException se) {
2079
                        logger.error("While ckecking rectangle: " + se.getMessage(), se);
2080
                }
2081

    
2082
                return false;
2083
        }
2084

    
2085
        /**
2086
         * Utility method to deal with oracle info arrays.
2087
         */
2088
        public static ARRAY getDevelopedInfoArray(ARRAY info) {
2089
                ARRAY _resp = null;
2090

    
2091
                try {
2092
                        Datum[] resp = new Datum[3];
2093
                        Datum[] in = info.getOracleArray();
2094
                        resp[0] = in[0];
2095
                        resp[1] = in[1];
2096
                        resp[2] = new NUMBER(1);
2097
                        _resp = new ARRAY(info.getDescriptor(), info
2098
                                        .getInternalConnection(), resp);
2099
                } catch (SQLException se) {
2100
                        logger.error("While creating ARRAY: " + se.getMessage(), se);
2101
                }
2102

    
2103
                return _resp;
2104
        }
2105

    
2106
        /**
2107
         * Utility method to deal with oracle coordinate arrays.
2108
         */
2109
        public static ARRAY getDevelopedOrdsArray(ARRAY ords, int dim) {
2110
                ARRAY _resp = null;
2111

    
2112
                try {
2113
                        int n = 5*2; // dim = 2, ignored parameter dim
2114
                        Datum[] resp = new Datum[n];
2115
                        Datum[] corners = ords.getOracleArray();
2116

    
2117
                        for (int i=0; i<5; i++) {
2118
                                resp[i*2] = ((i==2) || (i==3)) ? corners[dim] : corners[0];
2119
                        }
2120
                        for (int i=0; i<5; i++) {
2121
                                resp[1+i*2] = ((i==1) || (i==2)) ? corners[dim+1] : corners[1];
2122
                        }
2123
                        _resp = new ARRAY(ords.getDescriptor(), ords
2124
                                        .getInternalConnection(), resp);
2125
                } catch (SQLException se) {
2126
                        logger.error("While creating ARRAY: " + se.getMessage(), se);
2127
                }
2128

    
2129
                return _resp;
2130
        }
2131

    
2132
        /**
2133
         * utility method to convert a STRUCT into a GeneralPathX
2134
         * 
2135
         * @param aux
2136
         *            the struct's datum array
2137
         * @return the GeneralPathX instance created
2138
         */
2139
        public static GeneralPathX structToGPX(Datum[] aux) {
2140
                GeneralPathX resp = new GeneralPathX();
2141
                ARRAY infoARRAY = null;
2142
                ARRAY ordsARRAY = null;
2143
                Datum[] info_array = null;
2144
                Datum[] ords_array = null;
2145
                int info_array_size = 0;
2146
                int[] start_ind;
2147
                int[] end_ind;
2148
                int dims = 0;
2149
                boolean next_must_do_first = true;
2150

    
2151
                try {
2152
                        infoARRAY = (ARRAY) aux[3];
2153
                        ordsARRAY = (ARRAY) aux[4];
2154

    
2155
                        dims = ((NUMBER) aux[0]).intValue() / 1000;
2156

    
2157
                        if (dims == 0) {
2158
                                dims = 2;
2159
                        }
2160

    
2161
                        if (polStructIsRectStruct(infoARRAY, ordsARRAY)) {
2162
                                infoARRAY = getDevelopedInfoArray(infoARRAY);
2163
                                ordsARRAY = getDevelopedOrdsArray(ordsARRAY, dims);
2164
                                // rect is always 2d
2165
                                dims = 2;
2166
                        }
2167

    
2168
                        info_array = (Datum[]) infoARRAY.getOracleArray();
2169
                        ords_array = (Datum[]) ordsARRAY.getOracleArray();
2170
                        info_array_size = info_array.length / 3;
2171

    
2172
                        int last_index = ords_array.length - dims + 1;
2173

    
2174
                        // set indices:
2175
                        start_ind = new int[info_array_size];
2176
                        end_ind = new int[info_array_size];
2177

    
2178
                        for (int i = 0; i < info_array_size; i++)
2179
                                start_ind[i] = ((NUMBER) info_array[3 * i]).intValue();
2180

    
2181
                        for (int i = 0; i < (info_array_size - 1); i++)
2182
                                end_ind[i] = start_ind[i + 1] - 1;
2183

    
2184
                        end_ind[info_array_size - 1] = last_index;
2185

    
2186
                        int lineType = PathIterator.SEG_LINETO;
2187

    
2188
                        if (end_ind[0] == 0) { // collection of paths
2189

    
2190
                                for (int i = 1; i < info_array_size; i++) {
2191
                                        lineType = getLineToType(info_array, i);
2192

    
2193
                                        // -----------------------
2194
                                        if (end_ind[i] == (start_ind[i] - 1))
2195
                                                lineType = PathIterator.SEG_MOVETO;
2196
                                        // -----------------------
2197

    
2198
                                        next_must_do_first = addOrdsToGPX(resp, start_ind[i] - 1,
2199
                                                        end_ind[i] - 1, ords_array, dims, lineType,
2200
                                                        (i == 1) || (lineType == PathIterator.SEG_MOVETO),
2201
                                                        next_must_do_first);
2202
                                }
2203
                        } else {
2204
                                // standard case, do the moveto always
2205
                                for (int i = 0; i < info_array_size; i++) {
2206
                                        lineType = getLineToType(info_array, i);
2207
                                        addOrdsToGPX(resp, start_ind[i] - 1, end_ind[i] - 1,
2208
                                                        ords_array, dims, lineType, true, true);
2209
                                }
2210
                        }
2211

    
2212
                        // boolean do_the_moves = true;
2213
                } catch (SQLException se) {
2214
                        logger.error("While creating GPX: " + se.getMessage(), se);
2215
                }
2216

    
2217
                return resp;
2218
        }
2219

    
2220
        /**
2221
         * 
2222
         * @param infos
2223
         * @param i
2224
         * @return
2225
         */
2226
        private static int getLineToType(Datum[] infos, int i) {
2227
                int resp = PathIterator.SEG_LINETO;
2228

    
2229
                try {
2230
                        if (((NUMBER) infos[(3 * i) + 2]).intValue() == 2) {
2231
                                resp = PathIterator.SEG_QUADTO;
2232
                        }
2233
                } catch (SQLException e) {
2234
                        logger.error("While getting line-to type: " + e.getMessage()
2235
                                        + " (returned SEG_LINETO)");
2236
                }
2237

    
2238
                return resp;
2239
        }
2240

    
2241
        /**
2242
         * 
2243
         * @param gpx
2244
         * @param zero_based_start
2245
         * @param zero_based_include_end
2246
         * @param ords
2247
         * @param d
2248
         * @param ltype
2249
         * @param do_the_move
2250
         * @param must_do_first
2251
         * @return
2252
         */
2253
        private static boolean addOrdsToGPX(GeneralPathX gpx, int zero_based_start,
2254
                        int zero_based_include_end, Datum[] ords, int d, int ltype,
2255
                        boolean do_the_move, boolean must_do_first) {
2256
                int length = ords.length;
2257
                boolean return_following_must_do_first = true;
2258

    
2259
                double x = ((NUMBER) ords[zero_based_start]).doubleValue();
2260
                double y = ((NUMBER) ords[zero_based_start + 1]).doubleValue();
2261

    
2262
                if (must_do_first) {
2263
                        if (do_the_move) {
2264
                                gpx.moveTo(x, y);
2265
                        } else {
2266
                                gpx.lineTo(x, y);
2267
                        }
2268
                }
2269

    
2270
                int ind = 1;
2271

    
2272
                int size = ((zero_based_include_end - zero_based_start) / d) + 1;
2273
                int indx;
2274
                int indx2;
2275

    
2276
                if (ltype == PathIterator.SEG_QUADTO) { // (interpretation = 2)
2277

    
2278
                        double x2;
2279
                        double y2;
2280

    
2281
                        while (ind < size) {
2282
                                indx = zero_based_start + (ind * d);
2283
                                x = ((NUMBER) ords[indx]).doubleValue();
2284
                                y = ((NUMBER) ords[indx + 1]).doubleValue();
2285

    
2286
                                indx2 = zero_based_start + ((ind + 1) * d);
2287

    
2288
                                if (indx >= length) {
2289
                                        indx2 = zero_based_start;
2290
                                }
2291

    
2292
                                x2 = ((NUMBER) ords[indx2]).doubleValue();
2293
                                y2 = ((NUMBER) ords[indx2 + 1]).doubleValue();
2294
                                gpx.quadTo(x, y, x2, y2);
2295
                                ind++;
2296
                                ind++;
2297
                        }
2298

    
2299
                        return_following_must_do_first = false;
2300
                } else { // PathIterator.SEG_LINETO (interpretation = 1)
2301

    
2302
                        while (ind < size) {
2303
                                indx = zero_based_start + (ind * d);
2304
                                x = ((NUMBER) ords[indx]).doubleValue();
2305
                                y = ((NUMBER) ords[indx + 1]).doubleValue();
2306
                                gpx.lineTo(x, y);
2307
                                ind++;
2308
                        }
2309
                }
2310

    
2311
                return return_following_must_do_first;
2312
        }
2313

    
2314
        /**
2315
         * Utility method. Gets FShape type from oracle geometry type.
2316
         * 
2317
         * @param otype
2318
         * @return FShape type
2319
         */
2320
        public static int oracleGTypeToGvsigGeometryType(int otype) {
2321
                switch (otype) {
2322
                case OracleValues.ORACLE_GTYPE_UNKNOWN:
2323
                        return Geometry.TYPES.NULL;
2324

    
2325
                case OracleValues.ORACLE_GTYPE_POINT:
2326
                case OracleValues.ORACLE_GTYPE_MULTIPOINT:
2327
                        return Geometry.TYPES.POINT;
2328

    
2329
                case OracleValues.ORACLE_GTYPE_LINE:
2330
                case OracleValues.ORACLE_GTYPE_MULTILINE:
2331
                        return Geometry.TYPES.CURVE;
2332

    
2333
                case OracleValues.ORACLE_GTYPE_POLYGON:
2334
                case OracleValues.ORACLE_GTYPE_MULTIPOLYGON:
2335
                        return Geometry.TYPES.SURFACE;
2336

    
2337
                case OracleValues.ORACLE_GTYPE_COLLECTION:
2338
                        return Geometry.TYPES.AGGREGATE;
2339
                }
2340

    
2341
                logger.warn("Unknown oracle geometry type: " + otype);
2342

    
2343
                return Geometry.TYPES.NULL;
2344
        }
2345

    
2346
        /**
2347
         * Utility method to get struct's type.
2348
         * 
2349
         * @param the_data
2350
         *            the struct's datum array
2351
         * @return the struct type
2352
         */
2353
        public static int getStructType(Datum[] the_data) {
2354
                int resp = -1;
2355

    
2356
                try {
2357
                        resp = ((NUMBER) the_data[0]).intValue() % 1000;
2358
                } catch (SQLException se) {
2359
                        logger.error("Error: " + se.getMessage(), se);
2360
                }
2361

    
2362
                return resp;
2363
        }
2364

    
2365
        /**
2366
         * Utility method to get struct's SRID.
2367
         * 
2368
         * @param the_data
2369
         *            the struct's datum array
2370
         * @return the struct0's SRID
2371
         */
2372
        public static int getStructSRID(Datum[] the_data) {
2373
                int resp = -1;
2374

    
2375
                try {
2376
                        resp = ((NUMBER) the_data[1]).intValue();
2377
                } catch (SQLException se) {
2378
                        logger.error("Error: " + se.getMessage(), se);
2379
                }
2380

    
2381
                return resp;
2382
        }
2383

    
2384
        /**
2385
         * Utility method to find out if a struct is a circle.
2386
         * 
2387
         * @param the_data
2388
         *            the struct's datum array
2389
         * @return whether it is a circle
2390
         */
2391
        public static boolean isCircle(Datum[] the_data) {
2392
                int[] info = null;
2393

    
2394
                try {
2395
                        info = ((ARRAY) the_data[3]).getIntArray();
2396
                } catch (SQLException se) {
2397
                        logger.error("While cheking circle: " + se.getMessage(), se);
2398

    
2399
                        return false;
2400
                }
2401

    
2402
                if (info == null) {
2403
                        return false;
2404
                }
2405

    
2406
                boolean resp = ((info.length == 3) && (info[2] == 4));
2407

    
2408
                return resp;
2409
        }
2410

    
2411
        /**
2412
         * Gets the struct's dimension size.
2413
         * 
2414
         * @param st
2415
         *            the struct
2416
         * @return the structs dimension
2417
         */
2418
        public static int getStructDimensions(STRUCT st) {
2419
                int resp = -1;
2420

    
2421
                try {
2422
                        resp = ((NUMBER) st.getOracleAttributes()[0]).intValue() / 1000;
2423
                } catch (SQLException se) {
2424
                        logger.error("Error: " + se.getMessage(), se);
2425
                }
2426

    
2427
                if (resp < 2) {
2428
                        resp = 2;
2429
                }
2430

    
2431
                return resp;
2432
        }
2433
        
2434

    
2435

    
2436

    
2437
        /**
2438
         * Gets a struct's coordinates array.
2439
         * 
2440
         * @param the_data
2441
         *            the struct's datum array
2442
         * @return the coordinates array
2443
         */
2444
        public static double[] getOrds(Datum[] the_data) {
2445
                double[] resp = null;
2446

    
2447
                try {
2448
                        ARRAY aux = (ARRAY) the_data[4];
2449

    
2450
                        if (aux == null) {
2451
                                return null;
2452
                        }
2453

    
2454
                        resp = aux.getDoubleArray();
2455
                } catch (SQLException se) {
2456
                        logger.error("While getting ordinates: " + se.getMessage(), se);
2457
                }
2458

    
2459
                return resp;
2460
        }
2461

    
2462
        /**
2463
         * Utility method to create a struct with the given data.
2464
         * 
2465
         * @param type
2466
         *            struct type
2467
         * @param srid
2468
         *            coordinate system
2469
         * @param info
2470
         *            element info array
2471
         * @param ords
2472
         *            coordinates array
2473
         * @param conn
2474
         *            connection
2475
         * @return the created struct
2476
         */
2477
        public static STRUCT createStruct(NUMBER type, NUMBER srid, Datum[] info,
2478
                        Datum[] ords, Connection conn) {
2479
                try {
2480
                        StructDescriptor dsc = StructDescriptor.createDescriptor(
2481
                                        "MDSYS.SDO_GEOMETRY", conn);
2482
                        Object[] obj = new Object[5];
2483
                        obj[0] = type;
2484
                        obj[1] = srid;
2485
                        obj[2] = null;
2486
                        obj[3] = info;
2487
                        obj[4] = ords;
2488

    
2489
                        return new STRUCT(dsc, conn, obj);
2490
                } catch (SQLException se) {
2491
                        logger.error("While creating STRUCT: " + se.getMessage(), se);
2492
                }
2493

    
2494
                return null;
2495
        }
2496

    
2497
        /**
2498
         * 
2499
         * @param dim_info
2500
         * @return
2501
         */
2502
        public static String getDimInfoAsString(ARRAY dim_info) {
2503
                String resp = "DIMENSIONS: ";
2504

    
2505
                if (dim_info == null) {
2506
                        return "NULL" + "\n";
2507
                } else {
2508
                        try {
2509
                                Datum[] da = dim_info.getOracleArray();
2510
                                int size = da.length;
2511
                                resp = resp + size + "\n";
2512
                                for (int i = 0; i < size; i++) {
2513
                                        STRUCT dim_itemx = (STRUCT) da[i];
2514
                                        Object[] dim_desc = dim_itemx.getAttributes();
2515
                                        resp = resp + "DIMENSION " + i + ": " + ", NAME: "
2516
                                                        + dim_desc[0].toString() + ", MIN: "
2517
                                                        + dim_desc[1].toString() + ", MAX: "
2518
                                                        + dim_desc[2].toString() + ", TOL: "
2519
                                                        + dim_desc[3].toString();
2520
                                        if (i != (size - 1)) {
2521
                                                resp = resp + "\n";
2522
                                        }
2523
                                }
2524
                        } catch (Exception ex) {
2525
                                return "ERROR: " + ex.getMessage() + "\n";
2526
                        }
2527
                }
2528
                return resp;
2529
        }
2530

    
2531
        /**
2532
         * 
2533
         * @param conn
2534
         * @param fromStruct
2535
         * @param toSrid
2536
         * @return
2537
         */
2538
        public static STRUCT reprojectGeometry(Connection conn, STRUCT fromStruct,
2539
                        String toSrid) {
2540

    
2541
                String qry = "SELECT SDO_CS.TRANSFORM( ?, " + toSrid + ") FROM DUAL";
2542
                STRUCT resp = null;
2543

    
2544
                try {
2545
                        PreparedStatement _st = conn.prepareStatement(qry);
2546
                        _st.setObject(1, fromStruct);
2547
                        ResultSet _rs = _st.executeQuery();
2548

    
2549
                        if (_rs.next()) {
2550
                                resp = (STRUCT) _rs.getObject(1);
2551
                        } else {
2552
                                logger
2553
                                                .error("While executing reprojection: empty resultset (?)");
2554
                                return fromStruct;
2555
                        }
2556
                } catch (Exception ex) {
2557
                        logger.error("While reprojecting: " + ex.getMessage());
2558
                        return fromStruct;
2559
                }
2560

    
2561
                if (resp == null) {
2562
                        return fromStruct;
2563
                } else {
2564
                        return resp;
2565
                }
2566
        }
2567

    
2568
        /**
2569
         * 
2570
         * @param st
2571
         */
2572
        public static void printStruct(STRUCT st) {
2573

    
2574
                logger.debug("----------------------------------------------");
2575
                logger.debug("-- 16 FEBRERO 2009 ---------------------------");
2576
                logger.debug("----------------------------------------------");
2577

    
2578
                try {
2579
                        Object[] att = st.getAttributes();
2580
                        int l = att.length;
2581

    
2582
                        for (int i = 0; i < l; i++) {
2583
                                if (att[i] != null) {
2584
                                        if (att[i] instanceof ARRAY) {
2585
                                                ARRAY arr = (ARRAY) att[i];
2586
                                                logger.debug("ATT " + i + ": ");
2587
                                                printARRAY(arr);
2588
                                        } else {
2589
                                                logger.debug("ATT " + i + ": " + att[i].toString());
2590
                                        }
2591
                                        logger
2592
                                                        .debug("----------------------------------------------");
2593
                                }
2594
                        }
2595
                } catch (Exception ex) {
2596
                        logger.debug("-- Error: " + ex.getMessage());
2597
                }
2598

    
2599
        }
2600

    
2601
        /**
2602
         * 
2603
         * @param arr
2604
         * @throws Exception
2605
         */
2606
        private static void printARRAY(ARRAY arr) throws Exception {
2607

    
2608
                int[] intarr = arr.getIntArray();
2609
                if (intarr == null) {
2610
                        float[] floarr = arr.getFloatArray();
2611
                        if (floarr == null) {
2612
                                logger.debug("INT NULL y FLOAT NULL (?)");
2613
                        } else {
2614
                                int len = floarr.length;
2615
                                for (int i = 0; i < len; i++) {
2616
                                        if (Math.min(i, (len - i)) < 20) {
2617
                                                logger.debug("" + floarr[i]);
2618
                                        }
2619
                                }
2620
                        }
2621

    
2622
                } else {
2623
                        int len = intarr.length;
2624
                        for (int i = 0; i < len; i++) {
2625
                                if (Math.min(i, (len - i)) < 20) {
2626
                                        logger.debug("" + intarr[i]);
2627
                                }
2628
                        }
2629
                }
2630
        }
2631

    
2632
        /**
2633
         * Utility method. Gets FShape type from oracle geometry type.
2634
         * 
2635
         * @param otype
2636
         * @return FShape type
2637
         */
2638
        public static int oracleGTypeToFShapeType(int otype, boolean complex) {
2639

    
2640
                int resp = Geometry.TYPES.NULL;
2641

    
2642
                if (complex) {
2643

    
2644
                        switch (otype) {
2645
                        case OracleValues.ORACLE_GTYPE_COMPLEX_VOIDED_POLYON:
2646
                        case OracleValues.ORACLE_GTYPE_COMPLEX_COMPOUND_POLYON:
2647
                                resp = Geometry.TYPES.SURFACE;
2648
                                break;
2649
                        case OracleValues.ORACLE_GTYPE_COMPLEX_COMPOUND_LINE:
2650
                                resp = Geometry.TYPES.CURVE;
2651
                                break;
2652
                        }
2653

    
2654
                } else {
2655

    
2656
                        // =========== not complex =================
2657
                        switch (otype) {
2658
                        case OracleValues.ORACLE_GTYPE_UNKNOWN:
2659
                                resp = Geometry.TYPES.NULL;
2660
                                break;
2661

    
2662
                        case OracleValues.ORACLE_GTYPE_POINT:
2663
                        case OracleValues.ORACLE_GTYPE_MULTIPOINT:
2664
                                resp = Geometry.TYPES.POINT;
2665
                                break;
2666

    
2667
                        case OracleValues.ORACLE_GTYPE_LINE:
2668
                        case OracleValues.ORACLE_GTYPE_MULTILINE:
2669
                                resp = Geometry.TYPES.CURVE;
2670
                                break;
2671

    
2672
                        case OracleValues.ORACLE_GTYPE_POLYGON:
2673
                        case OracleValues.ORACLE_GTYPE_MULTIPOLYGON:
2674
                                resp = Geometry.TYPES.SURFACE;
2675
                                break;
2676

    
2677
                        case OracleValues.ORACLE_GTYPE_COLLECTION:
2678
                                resp = Geometry.TYPES.AGGREGATE;
2679
                                break;
2680
                        }
2681
                        // =========== not complex =================
2682
                }
2683

    
2684
                if (resp == Geometry.TYPES.NULL) {
2685
                        logger.error("Unknown oracle geometry type: " + otype);
2686
                }
2687
                return resp;
2688
        }
2689

    
2690
        /**
2691
         * 
2692
         * @param name
2693
         * @param arr
2694
         * @return
2695
         */
2696
        private static boolean isOneOfThese(String name, String[] arr) {
2697

    
2698
                for (int i = 0; i < arr.length; i++) {
2699
                        if (arr[i].compareToIgnoreCase(name) == 0)
2700
                                return true;
2701
                }
2702
                return false;
2703
        }
2704

    
2705
        /**
2706
         * 
2707
         * @param tt
2708
         * @param are_dims
2709
         * @return
2710
         */
2711
        public static boolean hasSeveralGeometryTypes(List tt, boolean are_dims) {
2712
                if (tt.size() == 0) {
2713
                        return false;
2714
                }
2715

    
2716
                HashMap m = new HashMap();
2717

    
2718
                for (int i = 0; i < tt.size(); i++) {
2719
                        Integer integ = (Integer) tt.get(i);
2720
                        int val = integ.intValue();
2721

    
2722
                        if ((val == 4) && (!are_dims)) {
2723
                                return true;
2724
                        }
2725

    
2726
                        m.put("" + (val % 4), "a type");
2727
                }
2728

    
2729
                Iterator iter = m.keySet().iterator();
2730
                iter.next();
2731

    
2732
                return iter.hasNext();
2733
        }
2734

    
2735
        /**
2736
         * 
2737
         */
2738
        public static void showMemory() {
2739
                Runtime r = Runtime.getRuntime();
2740
                long mem = r.totalMemory() - r.freeMemory();
2741
                logger.info("Total memory : " + mem);
2742
        }
2743

    
2744
        /**
2745
         * 
2746
         * @param input
2747
         * @param ind
2748
         * @param n
2749
         * @return
2750
         */
2751
        private static double[] getIndDoublesModule(double[] input, int ind, int n) {
2752
                int size = input.length / n;
2753
                double[] resp = new double[size];
2754

    
2755
                for (int i = 0; i < size; i++) {
2756
                        resp[i] = input[(i * n) + ind];
2757
                }
2758

    
2759
                return resp;
2760
        }
2761

    
2762
        /**
2763
         * 
2764
         * @param input
2765
         * @param ind
2766
         * @param n
2767
         * @return
2768
         */
2769
        private static double[] getIndBigDecimalModule(double[] input, int ind,
2770
                        int n) {
2771
                int size = input.length / n;
2772
                double[] resp = new double[size];
2773

    
2774
                for (int i = 0; i < size; i++) {
2775
                        resp[i] = input[(i * n) + ind];
2776
                }
2777

    
2778
                return resp;
2779
        }
2780

    
2781
        /**
2782
         * 
2783
         * @param the_data
2784
         * @param dim
2785
         * @return
2786
         * @throws CreateGeometryException
2787
         */
2788
        public static Geometry getFMapGeometryMultipolygon(Datum[] the_data, int dim)
2789
                        throws CreateGeometryException {
2790

    
2791
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2792

    
2793
                Geometry geom = null;
2794

    
2795
                if (OracleUtils.isCircle(the_data)) {
2796
                        geom = getCircleFromStruct(the_data);
2797
                } else {
2798
                        GeneralPathX gpx = OracleUtils.structToGPX(the_data);
2799

    
2800
                        if (dim == 2) {
2801
                                geom = geomManager.createSurface(gpx, Geometry.SUBTYPES.GEOM2D);
2802
                        } else {
2803
                                double[] ords = null;
2804

    
2805
                                try {
2806
                                        ords = ((ARRAY) the_data[4]).getDoubleArray();
2807
                                } catch (SQLException se) {
2808
                                        logger.error("While getting ordinates: " + se.getMessage(),
2809
                                                        se);
2810
                                }
2811

    
2812
                                double[] z = getIndBigDecimalModule(ords, 2, dim);
2813
                                geom = geomManager
2814
                                                .createSurface(gpx, Geometry.SUBTYPES.GEOM3D);
2815
                                for (int i = 0; i < z.length; i++) {
2816
                                        ((Surface2DZ) geom).setCoordinateAt(i, 2, z[i]);
2817
                                }
2818
                        }
2819
                }
2820

    
2821
                return geom;
2822
        }
2823

    
2824
        /**
2825
         * 
2826
         * @param the_data
2827
         * @return
2828
         * @throws CreateGeometryException
2829
         */
2830
        private static Geometry getCircleFromStruct(Datum[] the_data)
2831
                        throws CreateGeometryException {
2832

    
2833
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2834

    
2835
                double[] threep = null;
2836

    
2837
                try {
2838
                        threep = ((ARRAY) the_data[4]).getDoubleArray();
2839
                } catch (SQLException se) {
2840
                        logger.error("While getting ords from struct: " + se.getMessage(),
2841
                                        se);
2842

    
2843
                        return geomManager.createNullGeometry(Geometry.SUBTYPES.GEOM2D);
2844
                }
2845

    
2846
                Point2D[] three = new Point2D.Double[3];
2847
                three[0] = new Point2D.Double(threep[0], threep[1]);
2848
                three[1] = new Point2D.Double(threep[2], threep[3]);
2849
                three[2] = new Point2D.Double(threep[4], threep[5]);
2850

    
2851
                Object[] cent_rad = OracleUtils.getCenterAndRadiousOfCirc(three);
2852

    
2853
                Point2D cent = (Point2D) cent_rad[0];
2854
                double radious = ((Double) cent_rad[1]).doubleValue();
2855

    
2856
                Geometry circ = geomManager.create(Geometry.TYPES.CIRCLE,
2857
                                Geometry.SUBTYPES.GEOM2D);
2858
                ((Circle2D) circ).setPoints(cent, radious);
2859

    
2860
                return circ;
2861
        }
2862

    
2863
        /**
2864
         * 
2865
         * @param the_data
2866
         * @param dim
2867
         * @return
2868
         * @throws CreateGeometryException
2869
         */
2870
        public static Geometry getFMapGeometryMultiLineString(Datum[] the_data,
2871
                        int dim) throws CreateGeometryException {
2872

    
2873
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2874

    
2875
                GeneralPathX gpx = OracleUtils.structToGPX(the_data);
2876
                Geometry geom = null;
2877
                double[] ords = null;
2878

    
2879
                if (dim == 2) {
2880
                        geom = geomManager.createCurve(gpx, Geometry.SUBTYPES.GEOM2D);
2881
                } else {
2882
                        ords = OracleUtils.getOrds(the_data);
2883

    
2884
                        double[] z = getIndBigDecimalModule(ords, 2, dim);
2885
                        geom = geomManager.createCurve(gpx, Geometry.SUBTYPES.GEOM3D);
2886
                        for (int i = 0; i < z.length; i++) {
2887
                                ((Curve2DZ) geom).setCoordinateAt(i, 2, z[i]);
2888
                        }
2889
                }
2890

    
2891
                return geom;
2892
        }
2893

    
2894
        /**
2895
         * 
2896
         * @param the_data
2897
         * @param dim
2898
         * @return
2899
         * @throws CreateGeometryException
2900
         */
2901
        public static Geometry getFMapGeometryPoint(Datum[] the_data, int dim)
2902
                        throws CreateGeometryException {
2903

    
2904
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2905

    
2906
                double[] ords = OracleUtils.getOrds(the_data);
2907

    
2908
                if (ords == null) { // sdo_point
2909

    
2910
                        return getFMapGeometrySdoPoint(the_data, dim);
2911
                }
2912

    
2913
                Geometry geom = null;
2914
                int total_size = ords.length;
2915
                int no_po = total_size / dim;
2916
                double[] x = new double[no_po];
2917
                double[] y = new double[no_po];
2918
                double[] z = new double[no_po];
2919

    
2920
                for (int i = 0; i < no_po; i++) {
2921
                        x[i] = ords[i * dim]; // pp[i].getX();
2922
                        y[i] = ords[(i * dim) + 1];
2923

    
2924
                        if (dim >= 3) {
2925
                                z[i] = ords[(i * dim) + 2];
2926
                        }
2927
                }
2928

    
2929
                if (dim == 2) {
2930
                        if (no_po == 1) {
2931
                                geom = geomManager.createPoint(x[0], y[0],
2932
                                                Geometry.SUBTYPES.GEOM2D);
2933
                        } else {
2934
                                geom = geomManager.create(Geometry.TYPES.MULTIPOINT,
2935
                                                Geometry.SUBTYPES.GEOM2D);
2936

    
2937
                                ((MultiPoint2D) geom).setPoints(x, y);
2938
                        }
2939
                } else {
2940
                        if (no_po == 1) {
2941
                                geom = geomManager.createPoint(x[0], y[0],
2942
                                                Geometry.SUBTYPES.GEOM3D);
2943
                                ((Point2DZ) geom).setCoordinateAt(2, z[0]);
2944
                        } else {
2945
                                geom = geomManager.create(Geometry.TYPES.MULTIPOINT,
2946
                                                Geometry.SUBTYPES.GEOM3D);
2947
                                ((MultiPoint2DZ) geom).setPoints(x, y);
2948
                                Point2DZ pto = null;
2949
                                for (int i = 0; i < x.length; i++) {
2950
                                        pto = (Point2DZ) geomManager.create(Geometry.TYPES.POINT,
2951
                                                        Geometry.SUBTYPES.GEOM3D);
2952
                                        pto.setX(x[i]);
2953
                                        pto.setY(y[i]);
2954
                                        pto.setCoordinateAt(2, z[i]);
2955
                                        ((MultiPoint2DZ) geom).addPoint(pto);
2956
                                }
2957
                        }
2958
                }
2959

    
2960
                return geom;
2961
        }
2962

    
2963
        /**
2964
         * 
2965
         * @param the_data
2966
         * @param d
2967
         * @return
2968
         * @throws CreateGeometryException
2969
         */
2970
        public static Geometry getFMapGeometrySdoPoint(Datum[] the_data, int d)
2971
                        throws CreateGeometryException {
2972

    
2973
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2974

    
2975
                double x = 0;
2976
                double y = 0;
2977
                double z = 0;
2978

    
2979
                try {
2980
                        Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
2981
                        x = ((NUMBER) aux[0]).doubleValue();
2982
                        y = ((NUMBER) aux[1]).doubleValue();
2983

    
2984
                        if (d > 2) {
2985
                                z = ((NUMBER) aux[2]).doubleValue();
2986
                        }
2987
                } catch (SQLException se) {
2988
                        logger.error("While getting sdo point ordinates: "
2989
                                        + se.getMessage(), se);
2990
                }
2991

    
2992
                Geometry geom = null;
2993

    
2994
                if (d == 2) {
2995
                        geom = geomManager.createPoint(x, y, Geometry.SUBTYPES.GEOM2D);
2996
                } else {
2997

    
2998
                        Point2DZ point = (Point2DZ) geomManager.create(
2999
                                        Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D);
3000
                        point.setX(x);
3001
                        point.setY(y);
3002
                        point.setCoordinateAt(2, z);
3003
                        geom = point;
3004
                }
3005

    
3006
                return geom;
3007
        }
3008

    
3009
        /**
3010
         * 
3011
         * @param the_data
3012
         * @return
3013
         */
3014
        public static boolean isActuallyACollection(Datum[] the_data) {
3015
                int[] info = null;
3016

    
3017
                try {
3018
                        ARRAY aux = (ARRAY) the_data[3];
3019

    
3020
                        if (aux == null) {
3021
                                return false;
3022
                        }
3023

    
3024
                        info = aux.getIntArray();
3025
                } catch (SQLException se) {
3026
                        logger.error("While checking collection: " + se.getMessage());
3027
                        return false;
3028
                }
3029

    
3030
                if (info == null) {
3031
                        return false; // sdo_point
3032
                }
3033

    
3034
                int size = info.length / 3;
3035

    
3036
                if (size == 1) {
3037
                        return false;
3038
                }
3039

    
3040
                if (size == 2) {
3041
                        return ((info[1] % 1000) != (info[4] % 1000))
3042
                                        && (!((info[1] == 1005) && (info[4] == 2)));
3043
                }
3044

    
3045
                int second = info[4] % 1000;
3046
                int item = 0;
3047

    
3048
                for (int i = 2; i < size; i++) {
3049
                        item = info[(i * 3) + 1] % 1000;
3050
                        if ((item != second) && (!((item == 5) && (second == 2)))) {
3051
                                return true;
3052
                        }
3053
                }
3054

    
3055
                return false;
3056
        }
3057

    
3058
        /**
3059
         * 
3060
         * @param info
3061
         * @return
3062
         */
3063
        public static Datum[] updateIndexes(Datum[] info) {
3064
                int size = info.length / 3;
3065
                NUMBER[] resp = new NUMBER[3 * size];
3066

    
3067
                try {
3068
                        int rest = info[0].intValue() - 1;
3069

    
3070
                        for (int i = 0; i < size; i++) {
3071
                                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
3072
                                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
3073
                                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
3074
                        }
3075
                } catch (SQLException se) {
3076
                        logger.error("Unexpected error: " + se.getMessage());
3077
                }
3078

    
3079
                return resp;
3080
        }
3081

    
3082
        /**
3083
         * 
3084
         * @param all
3085
         * @param first_inc
3086
         * @param last_inc
3087
         * @return
3088
         */
3089
        public static double[] getSubSet(double[] all, int first_inc, int last_inc) {
3090
                double[] resp = new double[last_inc - first_inc + 1];
3091

    
3092
                for (int i = first_inc; i <= last_inc; i++) {
3093
                        resp[i - first_inc] = all[i];
3094
                }
3095

    
3096
                return resp;
3097
        }
3098

    
3099
        /**
3100
         * 
3101
         * @param all
3102
         * @param groups
3103
         * @return
3104
         * @throws SQLException
3105
         */
3106
        public static Object[] getOrdOfGroups(Datum[] all, Object[] groups)
3107
                        throws SQLException {
3108
                Object[] resp = new Object[groups.length];
3109

    
3110
                if (resp.length == 1) {
3111
                        resp[0] = all;
3112

    
3113
                        return resp;
3114
                }
3115

    
3116
                int ind = 0;
3117
                Datum[] aux = (Datum[]) groups[1];
3118
                int _end = aux[0].intValue() - 2;
3119
                Datum[] ord_aux = getSubSet(all, 0, _end);
3120

    
3121
                int _start = _end + 1;
3122
                resp[ind] = ord_aux;
3123
                ind++;
3124

    
3125
                for (int i = 2; i < groups.length; i++) {
3126
                        aux = (Datum[]) groups[i];
3127
                        _end = aux[0].intValue() - 2;
3128
                        ord_aux = getSubSet(all, _start, _end);
3129
                        resp[ind] = ord_aux;
3130
                        ind++;
3131
                        _start = _end + 1;
3132
                }
3133

    
3134
                // last
3135
                _end = all.length - 1;
3136
                ord_aux = getSubSet(all, _start, _end);
3137
                resp[groups.length - 1] = ord_aux;
3138

    
3139
                return resp;
3140
        }
3141

    
3142
        /**
3143
         * 
3144
         * @param all
3145
         * @param groups
3146
         * @return
3147
         */
3148
        public static Object[] getOrdOfGroups(double[] all, Object[] groups) {
3149
                Object[] resp = new Object[groups.length];
3150

    
3151
                if (resp.length == 1) {
3152
                        resp[0] = all;
3153

    
3154
                        return resp;
3155
                }
3156

    
3157
                int ind = 0;
3158
                int[] aux = (int[]) groups[1];
3159
                int _end = aux[0] - 2;
3160
                double[] ord_aux = getSubSet(all, 0, _end);
3161

    
3162
                int _start = _end + 1;
3163
                resp[ind] = ord_aux;
3164
                ind++;
3165

    
3166
                for (int i = 2; i < groups.length; i++) {
3167
                        aux = (int[]) groups[i];
3168
                        _end = aux[0] - 2;
3169
                        ord_aux = getSubSet(all, _start, _end);
3170
                        resp[ind] = ord_aux;
3171
                        ind++;
3172
                        _start = _end + 1;
3173
                }
3174

    
3175
                // last
3176
                _end = all.length - 1;
3177
                ord_aux = getSubSet(all, _start, _end);
3178
                resp[groups.length - 1] = ord_aux;
3179

    
3180
                return resp;
3181
        }
3182

    
3183
        /**
3184
         * 
3185
         * @param all_elem
3186
         * @return
3187
         */
3188
        public static Object[] groupByElement(int[] all_elem) {
3189
                List resp = new ArrayList();
3190

    
3191
                int size = all_elem.length / 3;
3192

    
3193
                int[] aux = getNthGroupOfThree(all_elem, 0);
3194

    
3195
                int[] newaux;
3196
                int i = 1;
3197

    
3198
                while (i < size) {
3199
                        newaux = getNthGroupOfThree(all_elem, i);
3200

    
3201
                        if (newaux[0] == aux[0]) {
3202
                                // aux[2] says how many components
3203
                                for (int j = 0; j < aux[2]; j++) {
3204
                                        aux = appendIntArrays(aux, getNthGroupOfThree(all_elem, j
3205
                                                        + i));
3206
                                }
3207

    
3208
                                resp.add(aux);
3209
                                i = i + aux[2];
3210
                                aux = getNthGroupOfThree(all_elem, i);
3211
                        } else {
3212
                                if (newaux[1] == 2003) {
3213
                                        aux = appendIntArrays(aux, newaux);
3214
                                } else {
3215
                                        resp.add(aux);
3216
                                        aux = getNthGroupOfThree(all_elem, i);
3217
                                }
3218
                        }
3219

    
3220
                        i++;
3221
                }
3222

    
3223
                resp.add(aux);
3224

    
3225
                return resp.toArray();
3226
        }
3227

    
3228
        /**
3229
         * 
3230
         * @param all_elem
3231
         * @return
3232
         */
3233
        public static boolean isSimpleCollectionOfLines(Datum[] all_elem) {
3234

    
3235
                try {
3236
                        int size = all_elem.length;
3237
                        if (all_elem[1].intValue() != 4)
3238
                                return false;
3239
                        int size3 = size / 3;
3240

    
3241
                        for (int i = 1; i < size3; i++) {
3242
                                if (all_elem[3 * i + 1].intValue() != 2)
3243
                                        return false;
3244
                        }
3245
                        return true;
3246

    
3247
                } catch (SQLException ex) {
3248
                        logger.error("While is simple line collection: " + ex.getMessage());
3249
                }
3250

    
3251
                return false;
3252
        }
3253

    
3254
        /**
3255
         * 
3256
         * @param elem
3257
         * @return
3258
         */
3259
        public static Datum[] removeThreeFirst(Datum[] elem) {
3260
                int sz = elem.length;
3261
                Datum[] resp = new Datum[sz - 3];
3262
                for (int i = 3; i < sz; i++)
3263
                        resp[i - 3] = elem[i];
3264
                return resp;
3265
        }
3266

    
3267
        /**
3268
         * 
3269
         * @param all_elem
3270
         * @return
3271
         */
3272
        public static Object[] groupByElement(Datum[] all_elem) {
3273

    
3274
                if (isSimpleCollectionOfLines(all_elem)) {
3275
                        Object[] r = new Object[1];
3276
                        r[0] = removeThreeFirst(all_elem);
3277
                        return r;
3278
                }
3279

    
3280
                List resp = new ArrayList();
3281

    
3282
                int size = all_elem.length / 3;
3283

    
3284
                Datum[] aux = getNthGroupOfThree(all_elem, 0);
3285

    
3286
                Datum[] newaux;
3287
                int i = 1;
3288
                boolean add_last_time = true;
3289

    
3290
                try {
3291
                        while (i < size) {
3292
                                newaux = getNthGroupOfThree(all_elem, i);
3293

    
3294
                                if (newaux[0].intValue() == aux[0].intValue()) {
3295
                                        // aux[2] says how many components
3296
                                        for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
3297
                                                aux = appendDatArrays(aux, getNthGroupOfThree(all_elem,
3298
                                                                j + i));
3299
                                        }
3300

    
3301
                                        resp.add(aux);
3302
                                        i = i + ((NUMBER) aux[2]).intValue();
3303
                                        if (i < size) { // in some cases (line collection, 4)
3304
                                                aux = getNthGroupOfThree(all_elem, i);
3305
                                        } else {
3306
                                                add_last_time = false;
3307
                                        }
3308
                                } else {
3309
                                        if (((NUMBER) newaux[1]).intValue() == 2003) {
3310
                                                aux = appendDatArrays(aux, newaux);
3311
                                        } else {
3312
                                                resp.add(aux);
3313
                                                aux = getNthGroupOfThree(all_elem, i);
3314
                                        }
3315
                                }
3316

    
3317
                                i++;
3318
                        }
3319
                } catch (SQLException se) {
3320
                        logger.error("Unexpected error: " + se.getMessage());
3321
                }
3322

    
3323
                if (add_last_time) {
3324
                        resp.add(aux);
3325
                }
3326

    
3327
                return resp.toArray();
3328
        }
3329

    
3330
        /**
3331
         * 
3332
         * @param r
3333
         * @param hasSrid
3334
         * @param isView
3335
         * @param _isGeogCS
3336
         * @param _oracleSRID
3337
         * @param __conn
3338
         * @return
3339
         */
3340
        public static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
3341
                        boolean isView, boolean _isGeogCS, String osrid, Connection __conn) {
3342
                Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
3343
                Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
3344

    
3345
                if ((_isGeogCS) && (isView)) {
3346
                        c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
3347
                        c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
3348
                }
3349

    
3350
                STRUCT resp = null;
3351

    
3352
                try {
3353

    
3354
                        int size = 5;
3355
                        Object[] new_obj = new Object[size];
3356

    
3357
                        new_obj[0] = new NUMBER(2003);
3358

    
3359
                        if (hasSrid) {
3360
                                new_obj[1] = new NUMBER(osrid);
3361
                        } else {
3362
                                new_obj[1] = null;
3363
                        }
3364

    
3365
                        new_obj[2] = null;
3366

    
3367
                        NUMBER[] elem_info = new NUMBER[3];
3368
                        elem_info[0] = new NUMBER(1);
3369
                        elem_info[1] = new NUMBER(1003);
3370
                        elem_info[2] = new NUMBER(3);
3371
                        new_obj[3] = elem_info;
3372

    
3373
                        NUMBER[] ords = null;
3374
                        ords = new NUMBER[4];
3375
                        ords[0] = new NUMBER(c1.getX());
3376
                        ords[1] = new NUMBER(c1.getY());
3377
                        ords[2] = new NUMBER(c2.getX());
3378
                        ords[3] = new NUMBER(c2.getY());
3379
                        new_obj[4] = ords;
3380

    
3381
                        StructDescriptor dsc = StructDescriptor.createDescriptor(
3382
                                        "MDSYS.SDO_GEOMETRY", __conn);
3383

    
3384
                        resp = new STRUCT(dsc, __conn, new_obj);
3385
                } catch (Exception ex) {
3386
                        logger.error(
3387
                                        "Error while creating rect struct: " + ex.getMessage(), ex);
3388
                }
3389

    
3390
                return resp;
3391
        }
3392

    
3393
        /**
3394
         * 
3395
         * @param r1
3396
         * @param r2
3397
         * @return
3398
         */
3399
        public static Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
3400
                if (r1.getMaxX() <= r2.getMinX()) {
3401
                        return null;
3402
                }
3403

    
3404
                if (r2.getMaxX() <= r1.getMinX()) {
3405
                        return null;
3406
                }
3407

    
3408
                if (r1.getMaxY() <= r2.getMinY()) {
3409
                        return null;
3410
                }
3411

    
3412
                if (r2.getMaxY() <= r1.getMinY()) {
3413
                        return null;
3414
                }
3415

    
3416
                double minx = Math.max(r1.getMinX(), r2.getMinX());
3417
                double miny = Math.max(r1.getMinY(), r2.getMinY());
3418
                double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
3419
                double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
3420

    
3421
                double w = maxx - minx;
3422
                double h = maxy - miny;
3423

    
3424
                return new Rectangle2D.Double(minx, miny, w, h);
3425
        }
3426

    
3427
        /**
3428
         * Utility method to find out if a coordinate system is geodetic or not.
3429
         * 
3430
         * @param oracleSRID2
3431
         *            the coordinate system's oracle code
3432
         * @param thas
3433
         *            whether the table has a coordinate system set. if not, the
3434
         *            method returns false.
3435
         * @return whether the coordinate system is geodetic or not.
3436
         */
3437
        public static boolean getIsGCS(String oracleSRID2, boolean thas) {
3438

    
3439
                if (!thas)
3440
                        return false;
3441
                if (oracleSRID2 == null)
3442
                        return false;
3443

    
3444
                int ora_cs = 0;
3445

    
3446
                try {
3447
                        ora_cs = Integer.parseInt(oracleSRID2);
3448
                } catch (Exception ex) {
3449
                        return false;
3450
                }
3451

    
3452
                if (
3453
                                ((ora_cs >= 8000) && (ora_cs <= 8999))
3454
                                ||
3455
                                (ora_cs == 524288)
3456
                                ||
3457
                                ((ora_cs >= 4000) && (ora_cs <= 4999))
3458
                                ) {
3459
                        return true;
3460
                } else {
3461
                        return false;
3462
                }
3463
        }
3464

    
3465
        /**
3466
         * 
3467
         * @param sample input STRUCT
3468
         * @return type and subtype of geometry
3469
         * @throws SQLException
3470
         */
3471
        public static int[] getGeoTypeSubTypeOfStruct(STRUCT sample) throws SQLException {
3472

    
3473
                int _code = ((NUMBER) sample.getOracleAttributes()[0]).intValue();
3474
                return getGeoTypeSubTypeOfOracleCode(_code);
3475
        }
3476

    
3477
        
3478
        public static int[] getGeoTypeSubTypeOfOracleCode(int code) {
3479

    
3480
                // [TYPES.?, SUBTYPES.?]
3481
                int[] resp = new int[2];
3482
                
3483
                int type_part = code % 10;
3484
                int dim_part = code / 1000;
3485

    
3486
                resp[1] = SUBTYPES.GEOM2D;
3487
                if (dim_part == 3) {
3488
                        resp[1] = SUBTYPES.GEOM3D;
3489
                } else {
3490
                        if (dim_part == 4) {
3491
                                resp[1] = SUBTYPES.GEOM3DM;
3492
                        }
3493
                }
3494

    
3495
                resp[0] = TYPES.GEOMETRY;
3496
                
3497
                switch (type_part) {
3498
                case 1:
3499
                        resp[0] = Geometry.TYPES.POINT;
3500
                        break;
3501
                case 2:
3502
                        resp[0] = Geometry.TYPES.CURVE;
3503
                        break;
3504
                case 3:
3505
                        resp[0] = Geometry.TYPES.SURFACE;
3506
                        break;
3507
                case 4:
3508
                        resp[0] = Geometry.TYPES.AGGREGATE;
3509
                        break;
3510
                case 5:
3511
                        resp[0] = Geometry.TYPES.MULTIPOINT;
3512
                        break;
3513
                case 6:
3514
                        resp[0] = Geometry.TYPES.CURVE;
3515
                        break;
3516
                case 7:
3517
                        resp[0] = Geometry.TYPES.SURFACE;
3518
                        break;
3519
                default:
3520
                        logger.error("Unknown geometry type: " + code);
3521
                break;
3522
                }
3523

    
3524
                return resp;
3525
        }
3526
        /**
3527
         * 
3528
         * @param info
3529
         * @return
3530
         */
3531
        public static int[] updateIndexes(int[] info) {
3532
                int size = info.length / 3;
3533
                int[] resp = new int[3 * size];
3534
                int rest = info[0] - 1;
3535

    
3536
                for (int i = 0; i < size; i++) {
3537
                        resp[3 * i] = info[3 * i] - rest;
3538
                        resp[(3 * i) + 1] = info[(3 * i) + 1];
3539
                        resp[(3 * i) + 2] = info[(3 * i) + 2];
3540
                }
3541

    
3542
                return resp;
3543
        }
3544

    
3545
        /**
3546
         * 
3547
         * @param head
3548
         * @param tail
3549
         * @return
3550
         */
3551
        public static int[] appendIntArrays(int[] head, int[] tail) {
3552
                int[] resp = new int[head.length + tail.length];
3553
                int hsize = head.length;
3554

    
3555
                for (int i = 0; i < hsize; i++) {
3556
                        resp[i] = head[i];
3557
                }
3558

    
3559
                for (int i = 0; i < tail.length; i++) {
3560
                        resp[hsize + i] = tail[i];
3561
                }
3562

    
3563
                return resp;
3564
        }
3565

    
3566
        /**
3567
         * 
3568
         * @param head
3569
         * @param tail
3570
         * @return
3571
         */
3572
        public static Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
3573
                Datum[] resp = new Datum[head.length + tail.length];
3574
                int hsize = head.length;
3575

    
3576
                for (int i = 0; i < hsize; i++) {
3577
                        resp[i] = head[i];
3578
                }
3579

    
3580
                for (int i = 0; i < tail.length; i++) {
3581
                        resp[hsize + i] = tail[i];
3582
                }
3583

    
3584
                return resp;
3585
        }
3586

    
3587
        /**
3588
         * 
3589
         * @param list
3590
         * @param n
3591
         * @return
3592
         */
3593
        public static int[] getNthGroupOfThree(int[] list, int n) {
3594
                int[] resp = new int[3];
3595
                resp[0] = list[3 * n];
3596
                resp[1] = list[(3 * n) + 1];
3597
                resp[2] = list[(3 * n) + 2];
3598

    
3599
                return resp;
3600
        }
3601

    
3602
        /**
3603
         * 
3604
         * @param list
3605
         * @param n
3606
         * @return
3607
         */
3608
        public static Datum[] getNthGroupOfThree(Datum[] list, int n) {
3609
                Datum[] resp = new Datum[3];
3610
                resp[0] = list[3 * n];
3611
                resp[1] = list[(3 * n) + 1];
3612
                resp[2] = list[(3 * n) + 2];
3613

    
3614
                return resp;
3615
        }
3616

    
3617
        /**
3618
         * 
3619
         * @param all
3620
         * @param first_inc
3621
         * @param last_inc
3622
         * @return
3623
         */
3624
        public static Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
3625
                Datum[] resp = new Datum[last_inc - first_inc + 1];
3626

    
3627
                for (int i = first_inc; i <= last_inc; i++) {
3628
                        resp[i - first_inc] = all[i];
3629
                }
3630

    
3631
                return resp;
3632
        }
3633

    
3634
        /**
3635
         * 
3636
         * @param _type
3637
         * @return
3638
         */
3639
        public static int maxSizeForFieldType(int _type) {
3640
                switch (_type) {
3641
                case Types.VARCHAR:
3642
                        return OracleValues.VARCHAR2_STANDARD_SIZE;
3643

    
3644
                case Types.LONGVARCHAR:
3645
                        return OracleValues.VARCHAR2_LONG_SIZE;
3646
                }
3647

    
3648
                return -1;
3649
        }
3650

    
3651
        /**
3652
         * 
3653
         * @param tname
3654
         * @param suffix
3655
         * @return
3656
         */
3657
        public static String getDerivedName(String tname, String suffix) {
3658
                int ind = tname.lastIndexOf(".");
3659
                if (ind == -1) {
3660
                        int l = Math.min(28, tname.length());
3661
                        return tname.substring(0, l) + "_" + suffix;
3662
                } else {
3663
                        String pre = tname.substring(0, ind);
3664
                        String post = tname.substring(ind + 1, tname.length());
3665
                        int lpost = Math.min(24, post.length());
3666
                        int lpre = Math.min(3, pre.length());
3667
                        return pre.substring(0, lpre) + "_" + post.substring(0, lpost)
3668
                                        + "_" + suffix;
3669
                }
3670
        }
3671

    
3672
        /**
3673
         * Converts Geometry to STRUCT
3674
         * 
3675
         * @param geom
3676
         *            the geometry to convert
3677
         * @param _forced_type
3678
         *            forced type to use
3679
         * @param _conn
3680
         *            connection
3681
         * @param _o_srid
3682
         *            SRS (oracle code)
3683
         * @param withSrid
3684
         *            whether this STRUCT has a non-NULL SRS
3685
         * @param agu_bien
3686
         *            whether or not to check the correctness of the holes
3687
         * @param _isGeoCS
3688
         *            whether the SRS is geodetic or not
3689
         * @return the generated STRUCT
3690
         * @throws SQLException
3691
         */
3692
        public static STRUCT buildSTRUCT(Geometry geom, int _forced_type,
3693
                        Connection conn, String osrid, boolean withSrid, boolean agu_bien,
3694
                        boolean _isGeoCS) { // throws SQLException {
3695
                if (geom instanceof Complex) {
3696
                        // Complex coll = (Complex) geom;
3697
                        //
3698
                        // return appendGeometriesInStruct(coll, _forced_type, conn, osrid,
3699
                        // withSrid, agu_bien, _isGeoCS);
3700
                        return null;
3701
                } else {
3702
                        // Shape shp = geom.getInternalShape();
3703
                        int osridd = withSrid ? Integer.parseInt(osrid) : 0;
3704
                        STRUCT resp = null;
3705
                        try {
3706
                                resp = geometryToSTRUCT(geom, conn, osridd, agu_bien, withSrid);
3707
                        } catch (SQLException e) {
3708
                                logger.error("While converting to STRUCT: " + e.getMessage());
3709
                        }
3710
                        return resp;
3711
                }
3712
        }
3713

    
3714
        /**
3715
         * Utility method to convert a gvSIG Geometry into a oracle STRUCT
3716
         * 
3717
         * @param geom
3718
         *            the FShape object
3719
         * @param c
3720
         *            the connection
3721
         * @param srid
3722
         *            the SRS (oracle code)
3723
         * @param agu_b
3724
         *            whether to check holes validity
3725
         * @param hasSrid
3726
         *            whether the SRS is non-NULL
3727
         * @return a oracle struct representing the geometry
3728
         * 
3729
         * @throws SQLException
3730
         */
3731
        public static STRUCT geometryToSTRUCT(Geometry geom, Connection conn,
3732
                        int osrid, boolean agu_b, boolean hasSrid) throws SQLException {
3733

    
3734
                boolean three = false;
3735

    
3736
                if (geom.getDimension() == 3) {
3737
                        three = true;
3738
                }
3739

    
3740
                STRUCT resp = null;
3741

    
3742
                GeometryType geometryType = geom.getGeometryType();
3743
                
3744
                if (geometryType.isTypeOf(Geometry.TYPES.MULTIPOINT)) {
3745
                        resp = multiPoint2DToStruct((MultiPoint2D) geom, conn, osrid,
3746
                                        hasSrid);
3747
                        return resp;
3748
                } else if (geometryType.isTypeOf(Geometry.TYPES.POINT)) { // point 2/3d
3749
                        Coordinate p = getSingleCoordinate((Point) geom);
3750
                        resp = getMultiPointAsStruct(p, osrid, three, conn, hasSrid);
3751
                } else if (geometryType.isTypeOf(Geometry.TYPES.CURVE)) { // curve 2/3d
3752
            List<LineString3D> _lines = getLineStrings(geom);
3753
            resp = getMultiLineAsStruct(_lines, osrid, three, conn, hasSrid);
3754
        } else if (geometryType.isTypeOf(Geometry.TYPES.SURFACE)) { // surface 2/3d
3755
                        if (geometryType.getType() ==  Geometry.TYPES.CIRCLE) {
3756
                                resp = getCircleAsStruct((Circle2D) geom, osrid, conn,
3757
                                                hasSrid);
3758
                        } else {
3759
                                // also FEllipse2D
3760
                                resp = getMultiPolygonAsStruct(geom, osrid, three, conn,
3761
                                                agu_b, hasSrid);
3762
                        }
3763
        } else if (geometryType.isTypeOf(Geometry.TYPES.NULL)) { // null geometry
3764
            return null;
3765
        }
3766

    
3767
                return resp;
3768
        }
3769
        
3770
        
3771
        
3772

    
3773

    
3774

    
3775
        public static int getShapeTypeFromArray(ArrayList arrlist) {
3776
                
3777
                int resp = ((Integer) arrlist.get(0)).intValue();
3778
                
3779
                int sz = arrlist.size();
3780
                int aux = 0;
3781
                for (int i=1; i<sz; i++) {
3782
                        aux = ((Integer) arrlist.get(i)).intValue();
3783
                        if (aux != resp) return TYPES.GEOMETRY;
3784
                }
3785
                return resp;
3786
        }
3787

    
3788
        // condition using ROWNUM with growing indexs to do a size-independent sample
3789
    public static String EXPONENTIAL_INDICES_CONDITION = null;
3790
    static {
3791
                EXPONENTIAL_INDICES_CONDITION = "(rownum < 40)";
3792
    }
3793
    
3794
    
3795
        public static void copyFeatureTypeToOracleStoreParams(
3796
                        EditableFeatureType efType, OracleStoreParameters params) {
3797
                
3798
                
3799
                // TODO Auto-generated method stub
3800
                
3801
        }
3802
        
3803

    
3804
    
3805
    /**
3806
     * Utility method to transform a struct into a IGeometry.
3807
     *
3808
     * @param st the struct to be converted
3809
     * @param complex comes from a complex sdo geometry
3810
     * @return the IGeometry
3811
     */
3812
    public static Geometry getGeometry(
3813
                    STRUCT st,
3814
                    boolean complex,
3815
                    boolean __tablehassrid,
3816
                    String __tablesrid,
3817
                    Connection _conn) {
3818

    
3819
            if (st == null) {
3820
                    Geometry aux = null;
3821
                    aux = createNullGeometry(SUBTYPES.GEOM2D);
3822
                    return aux;
3823
            }
3824

    
3825
        Datum[] the_data = null;
3826

    
3827
        try {
3828
            the_data = st.getOracleAttributes();
3829

    
3830
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
3831
            jgtype = oracleGTypeToFShapeType(jgtype, complex);
3832

    
3833
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
3834

    
3835
            if (dim < 2) {
3836
                dim = 2;
3837
            }
3838

    
3839
            int subty = getSubTypeFromDims(dim);
3840
            Geometry ig = createNullGeometry(subty);
3841

    
3842
            if (isActuallyACollection(the_data)) {
3843
                jgtype = TYPES.AGGREGATE;
3844
            }
3845

    
3846
            switch (jgtype) {
3847
            case TYPES.AGGREGATE:
3848
                ig = getFMapGeometryCollection(the_data, dim, __tablehassrid, __tablesrid, _conn);
3849
                break;
3850

    
3851
            case TYPES.POINT:
3852
                ig = getFMapGeometryPoint(the_data, dim);
3853
                break;
3854

    
3855
            case TYPES.CURVE:
3856
                ig = getFMapGeometryMultiLineString(the_data, dim);
3857
                break;
3858

    
3859
            case TYPES.SURFACE:
3860
                ig = getFMapGeometryMultipolygon(the_data, dim);
3861
                break;
3862
            }
3863

    
3864
            return ig;
3865
        } catch (Exception e) {
3866
            logger.error("While creating Geometry from STRUCT: " + e.getMessage());
3867
        }
3868
        return null;
3869
    }
3870
    
3871
    
3872
    /**
3873
     * Utility method to transform a struct into a IGeometry.
3874
     *
3875
     * @param st the struct to be converted
3876
     * @param complex comes from a complex sdo geometry
3877
     * @return the IGeometry
3878
     */
3879
    public static Primitive getPrimitive(STRUCT st, boolean complex) {
3880

    
3881
            GeometryManager gm = GeometryLocator.getGeometryManager();
3882
            Primitive resp = null;
3883
            
3884
            if (st == null) {
3885
                    try {
3886
                                resp = gm.createNullGeometry(SUBTYPES.GEOM2D);
3887
                        } catch (CreateGeometryException e) {
3888
                                logger.error("While creating null geometry: " + e.getMessage());
3889
                        }
3890
                        return resp;
3891
            }
3892

    
3893
        Datum[] the_data = null;
3894
        try {
3895
            the_data = st.getOracleAttributes();
3896

    
3897
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
3898
            jgtype = oracleGTypeToFShapeType(jgtype, complex);
3899

    
3900
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
3901

    
3902
            if (dim < 2) {
3903
                dim = 2;
3904
            }
3905

    
3906
                int subty = getSubTypeFromDims(dim);
3907
                Primitive ig = null;
3908
                try {
3909
                                ig = gm.createNullGeometry(subty);
3910
                        } catch (CreateGeometryException e) {
3911
                                logger.error("While creating null geometry: " + e.getMessage());
3912
                        }
3913

    
3914
            if (isActuallyACollection(the_data)) {
3915
                jgtype = TYPES.AGGREGATE;
3916
            }
3917

    
3918
            try {
3919
                switch (jgtype) {
3920
                case TYPES.POINT:
3921
                    ig = (Primitive) getFMapGeometryPoint(the_data, dim);
3922
                    break;
3923

    
3924
                case TYPES.CURVE:
3925
                    ig = (Primitive) getFMapGeometryMultiLineString(the_data, dim);
3926
                    break;
3927

    
3928
                case TYPES.SURFACE:
3929
                    ig = (Primitive) getFMapGeometryMultipolygon(the_data, dim);
3930
                    break;
3931
                default:
3932
                        logger.error("Aggregate of non primitives not supported.");
3933
                    break;
3934
                }
3935
            } catch (Exception ex) {
3936
                    logger.error("While creating primitive: " + ex.getMessage());
3937
            }
3938

    
3939
            return ig;
3940
        } catch (SQLException e) {
3941
            logger.error("While getting primitive: " + e.getMessage());
3942
        }
3943

    
3944
        return null;
3945
    }
3946
    
3947
    
3948
    private static int getSubTypeFromDims(int dim) {
3949
            
3950
            switch (dim) {
3951
            case 3:
3952
                    return SUBTYPES.GEOM3D;
3953
            case 4:
3954
                    return SUBTYPES.GEOM3DM;
3955
            default:
3956
                            return SUBTYPES.GEOM2D;
3957
            }
3958
        }
3959

    
3960
        public static Geometry getFMapGeometryCollection(
3961
                    Datum[] the_data,
3962
                    int dim,
3963
                    boolean tableHasSrid,
3964
                    String table_srid,
3965
                    Connection _conn) {
3966

    
3967
            NUMBER _srid = new NUMBER(0);
3968
        NUMBER main_type = new NUMBER((dim * 1000) + getStructType(the_data));
3969

    
3970

    
3971
        Datum[] all_info_array = null;
3972
        Object[] elems_info_aray = null;
3973
        Datum[] all_ords = null;
3974

    
3975
        Object[] ords_of_groups = null;
3976
        Object[] _elems_info_aray = null;
3977
        try {
3978
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
3979
            elems_info_aray = groupByElement(all_info_array);
3980
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
3981

    
3982
            ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
3983
            _elems_info_aray = new Object[elems_info_aray.length];
3984
        }
3985
        catch (SQLException e) {
3986
            logger.error("Unexpected error: " + e.getMessage());
3987
        }
3988

    
3989

    
3990
        for (int i = 0; i < elems_info_aray.length; i++) {
3991
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
3992
        }
3993

    
3994
        // _elems_info_aray, ords_of_groups
3995
        int no_of_elems = ords_of_groups.length;
3996
        Primitive[] geoms = new Primitive[no_of_elems];
3997

    
3998
        for (int i = 0; i < no_of_elems; i++) {
3999
            Datum[] item_info_array = null;
4000
            Datum[] item_ords = null;
4001
            NUMBER gtype = null;
4002

    
4003
            try {
4004
                item_info_array = (Datum[]) _elems_info_aray[i];
4005
                item_ords = (Datum[]) ords_of_groups[i];
4006

    
4007
                gtype = new NUMBER((dim * 1000) +
4008
                        (item_info_array[1].intValue() % 1000));
4009

    
4010
                if (tableHasSrid) {
4011
                        _srid = new NUMBER(Integer.parseInt(table_srid));
4012
                }
4013
            }
4014
            catch (SQLException se) {
4015
                logger.error("Unexpected error: " + se.getMessage());
4016
            }
4017

    
4018
            // if it's the first geometry, the type is the collection's main type (no?) - no
4019
            // if (i == 0) gtype = main_type;
4020

    
4021
            STRUCT itemst = null;
4022

    
4023
            if (tableHasSrid) {
4024

    
4025
                itemst = createStruct(gtype, _srid,
4026
                        item_info_array, item_ords, _conn);
4027
            }
4028
            else {
4029
                itemst = createStruct(gtype, null,
4030
                        item_info_array, item_ords, _conn);
4031
            }
4032
            geoms[i] = getPrimitive(itemst, true);
4033
        }
4034
        
4035
            GeometryManager gm = GeometryLocator.getGeometryManager();
4036
            int subt = getSubTypeFromDims(dim);
4037
        MultiPrimitive resp = null;
4038
        
4039
        try {
4040
                        resp = (MultiPrimitive) gm.create(TYPES.AGGREGATE, subt);
4041
                for (int i = 0; i < no_of_elems; i++) {
4042
                        resp.addPrimitive(geoms[i]);
4043
                }
4044
                } catch (Exception e) {
4045
                        logger.error("While creating multi primitive: " + e.getMessage());
4046
                }
4047
        return resp;
4048
    }
4049
        
4050
        // ===========================================================
4051
        
4052
        /**
4053
         * Get oracle srid from srs code(EPSG code)
4054
         * 
4055
         * @param epsg
4056
         * @return oraSRID
4057
         */
4058
        public static String epsgToOracleSrid(String epsg) {
4059
                
4060
                DataManager manager = DALLocator.getDataManager();
4061
                int isrs = -1;
4062
                if (epsg != null) {
4063
                        FeatureStore oraSrsStore = (FeatureStore) OracleLibrary.getSRSDataStore();
4064

    
4065
                        FeatureSet set = null;
4066
                        try {
4067
                                FeatureQuery query = oraSrsStore.createFeatureQuery();
4068
                                query.setFilter(manager.createExpresion("EPSG = " + epsg));
4069
                                set = (FeatureSet) oraSrsStore.getDataSet(query);
4070
                                if (set.getSize() > 0) {
4071
                                        Iterator<Feature> it = set.iterator();
4072
                                        while (it.hasNext()) {
4073
                                                Feature feat = it.next();
4074
                                                Double ora = feat.getDouble("ORACLE");
4075
                                                int iora = ora.intValue();
4076
                                                double prefe = feat.getDouble("PRF_ORACLE");
4077
                                                if (prefe == 1) {
4078
                                                        isrs = iora;
4079
                                                        break;
4080
                                                }
4081
                                        }
4082
                                }
4083
                        } catch (DataException e) {
4084
                                e.printStackTrace();
4085
                        }
4086
                        if (isrs >= 0) {
4087
                                return Integer.toString(isrs);
4088
                        }
4089
                }
4090
                return null;
4091
        }
4092

    
4093
        /**
4094
         * Get EPSG SRS from Oracle SRS
4095
         * 
4096
         * @param oraSRID
4097
         * @return
4098
         */
4099
        public static Integer oracleSridToEpsg(String oraSRID) {
4100

    
4101
                DataManager manager = DALLocator.getDataManager();
4102
                Integer isrs = null;
4103
                
4104
                if (oraSRID != null) {
4105
                        FeatureStore oraSrsStore = (FeatureStore) OracleLibrary.getSRSDataStore();
4106

    
4107
                        FeatureSet set = null;
4108
                        try {
4109
                                FeatureQuery query = oraSrsStore.createFeatureQuery();
4110
                                query.setFilter(manager.createExpresion("ORACLE = " + oraSRID));
4111
                                set = (FeatureSet) oraSrsStore.getDataSet(query);
4112
                                if (set.getSize() > 0) {
4113
                                        Iterator<Feature> it = set.iterator();
4114
                                        while (it.hasNext()) {
4115
                                                Feature feat = it.next();
4116
                                                isrs = new Integer(Math.round((float) feat.getDouble("EPSG")));
4117
                                        }
4118
                                } else {
4119
                                        logger.warn("Did not find Oracle SRID code: " + oraSRID + ". We'll assume it's an EPSG code.");
4120
                                        isrs = new Integer(Integer.parseInt(oraSRID));
4121
                                }
4122
                        } catch (Exception e) {
4123
                                logger.error("While getting EPSG from oracle srid: " + e.getMessage());
4124
                        }
4125
                        return isrs;
4126
                } else {
4127
                        return null;
4128
                }
4129
        }
4130

    
4131
        /**
4132
         * Get Oracle SRS from gvSIG projection
4133
         * 
4134
         * @param proj
4135
         * @return  
4136
         */
4137
        public static String projectionToOracleSrid(IProjection proj) {
4138
                if (proj != null) {
4139
                        String epsg = proj.getAbrev().trim();
4140
                        int ocu = epsg.indexOf(":");
4141
                        if (ocu != -1) {
4142
                                epsg = epsg.substring(ocu + 1);
4143
                        }
4144
                        return epsgToOracleSrid(epsg);
4145
                } else {
4146
                        return null;
4147
                }
4148
        }
4149

    
4150
        public static int dimensionsFromSubtype(int subtype) {
4151
                
4152
                switch (subtype) {
4153
                
4154
                case SUBTYPES.GEOM2D:
4155
                        return 2;
4156
                case SUBTYPES.GEOM3D:
4157
                case SUBTYPES.GEOM2DM:
4158
                        return 3;
4159
                case SUBTYPES.GEOM3DM:
4160
                        return 4;
4161
                default:
4162
                                logger.error("Unknown subtype: " + subtype + ". Returned 2 as number of dimensions.");
4163
                        return 2;
4164
                }
4165
        }
4166

    
4167
        public static Rectangle2D envelopeToRectangle2D(org.gvsig.fmap.geom.primitive.Envelope envelope) {
4168
                        
4169
                double x = envelope.getMinimum(0);
4170
                double y = envelope.getMinimum(1);
4171
                double w = envelope.getLength(0);
4172
                double h = envelope.getLength(1);
4173
                Rectangle2D resp = new Rectangle2D.Double(x,y,w,h);
4174
                return resp;
4175
        }
4176

    
4177
        public static Geometry createNullGeometry(int stype) {
4178
                
4179
        Geometry ig = null;
4180
        GeometryType nullgt = null;;
4181
                try {
4182
                        GeometryManager gm = GeometryLocator.getGeometryManager();
4183
                        nullgt = ((DefaultGeometryManager) gm).getGeometryType(DefaultNullGeometry.class.getName());
4184
                ig = new DefaultNullGeometry(nullgt);
4185
                } catch (GeometryTypeNotSupportedException e) {
4186
                        logger.error("While creating null geom: " + e.getMessage());
4187
                        return null;
4188
                }
4189
        return ig;
4190

    
4191
        }
4192
        
4193
        
4194
        
4195
    public static String getIntersectsEnvelopeSelect(
4196
                    String geo_col_name,
4197
                    Envelope enve,
4198
                    String ora_srid,
4199
                    boolean is_geo) {
4200
            
4201
        String resp = "";
4202
        String view_sdo = "";
4203
        
4204

    
4205
        if (is_geo) {
4206
            
4207
            view_sdo = getSdoConstructor(enve, "0", is_geo);;
4208
            resp = "(sdo_relate(" + geo_col_name +
4209
                ", SDO_CS.VIEWPORT_TRANSFORM(" + view_sdo + ", " + ora_srid +
4210
                "), 'mask=anyinteract querytype=window') = 'TRUE')";
4211
        } else {
4212
            view_sdo = getSdoConstructor(enve, ora_srid, is_geo);;
4213
            resp = "(sdo_relate(" + geo_col_name + ", " + view_sdo +
4214
            ", 'mask=anyinteract querytype=window') = 'TRUE')";
4215
        }
4216
        return resp;
4217
    }
4218
    
4219
    
4220
    public static String getIntersectsMultiRectSelect(
4221
                    String geo_col_name,
4222
                    Geometry geome,
4223
                    String ora_srid,
4224
                    boolean is_geo,
4225
                    Connection conn) {
4226
            
4227
        String resp = "";
4228
        String view_sdo = ""; 
4229
        
4230
        Envelope[] envs = getEnvelopes(geome);
4231
        int len = envs.length;
4232
        
4233
        if (len == 1) {
4234
            if (is_geo) {
4235
                
4236
                view_sdo = getSdoConstructor(envs[0], "0", is_geo);
4237
                resp = "(sdo_relate(" + geo_col_name +
4238
                ", SDO_CS.VIEWPORT_TRANSFORM(" + view_sdo + ", " + ora_srid +
4239
                "), 'mask=anyinteract querytype=window') = 'TRUE')";
4240
                
4241
            } else {
4242
                view_sdo = getSdoConstructor(envs[0], ora_srid, is_geo);
4243
                resp = "(sdo_relate(" + geo_col_name + ", " + view_sdo +
4244
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
4245
            }
4246

    
4247
        } else {
4248
            
4249
            view_sdo = binaryUnionEnvs(envs, ora_srid, is_geo, GEOM_DEFAULT_TOL);
4250
            resp = "(sdo_relate(" + geo_col_name + ", " + view_sdo +
4251
            ", 'mask=anyinteract querytype=window') = 'TRUE')";
4252
        }
4253

    
4254
        return resp;
4255
    }
4256

    
4257
    /**
4258
     * @param envs
4259
     * @param ora_srid
4260
     * @param is_geo
4261
     * @param geomDefaultTol
4262
     * @return
4263
     */
4264
    public static String binaryUnionEnvs(
4265
        Envelope[] envs,
4266
        String ora_srid,
4267
        boolean is_geo,
4268
        String tol) {
4269
        
4270
        if (envs == null || envs.length == 0) {
4271
            logger.error("Unexpected empty envelope array: " + envs);
4272
            return "";
4273
        }
4274
        
4275
        if (envs.length == 1) {
4276
            return getSdoConstructor(envs[0], ora_srid, is_geo);
4277
        } else {
4278
            int s1 = envs.length / 2;
4279
            int s2 = envs.length - s1;
4280
            Envelope[] p1 = new Envelope[s1];
4281
            Envelope[] p2 = new Envelope[s2];
4282
            for (int i=0; i<s1; i++) {
4283
                p1[i] = envs[i];
4284
            }
4285
            for (int i=0; i<s2; i++) {
4286
                p2[i] = envs[s1 + i];
4287
            }
4288
            String resp = "sdo_geom.sdo_union(";
4289
            resp = resp + binaryUnionEnvs(p1, ora_srid, is_geo, tol) + ", ";
4290
            resp = resp + binaryUnionEnvs(p2, ora_srid, is_geo, tol) + ", " + tol + ")";
4291
            return resp;
4292
        }
4293
    }
4294

    
4295
    /**
4296
     * @param geome
4297
     * @return
4298
     */
4299
    private static Envelope[] getEnvelopes(Geometry geome) {
4300
        
4301
        Envelope[] resp = null;
4302
        if (geome instanceof MultiSurface2D) {
4303
            
4304
            MultiSurface2D ms = (MultiSurface2D) geome;
4305
            int len = ms.getPrimitivesNumber();
4306
            resp = new Envelope[len];
4307
            for (int i=0; i<len; i++) {
4308
                resp[i] = ms.getPrimitiveAt(i).getEnvelope();
4309
            }
4310
            
4311
        } else {
4312
            resp = new Envelope[1];
4313
            resp[0] = geome.getEnvelope();
4314
        }
4315
        
4316
        return resp;
4317
    }
4318

    
4319
    public static String getSdoConstructor(Envelope enve, String ora_srid, boolean is_geo) {
4320
        String resp = "";
4321

    
4322
        try {
4323
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
4324
            String mdsys_sdo_ordinate_array = "";
4325

    
4326
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMinimum(0) + ", ";
4327
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMinimum(1) + ", ";
4328
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMaximum(0) + ", ";
4329
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMaximum(1);
4330

    
4331
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
4332
                mdsys_sdo_ordinate_array + ")";
4333

    
4334
            String aux = "";
4335

    
4336
            if (ora_srid != null) {
4337
                aux = ora_srid;
4338
            }
4339
            else {
4340
                aux = "null";
4341
            }
4342

    
4343
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
4344
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
4345
                ")";
4346
        }
4347
        catch (Exception ex) {
4348
                logger.error("While getting sdo contructor: " +
4349
                ex.getMessage());
4350
        }
4351

    
4352
        return resp;
4353
    }
4354
    
4355
    
4356
    public static String getSdoConstructor(
4357
                    Geometry geome, String ora_srid,
4358
                    boolean is_geo, Connection conn) {
4359
            
4360
            int ora_srid_int = 0;
4361
            STRUCT st = null;
4362
            ARRAY ora_arr = null;
4363

    
4364
            try {
4365
                    ora_srid_int = Integer.parseInt(ora_srid);
4366
                } catch (Exception e) { }
4367
            
4368
            try {
4369
                        st = geometryToSTRUCT(geome, conn, ora_srid_int, false, ora_srid != null);
4370
                        return structToString(st);
4371
                } catch (Exception e) {
4372
                        logger.error("While getting SDO geometry as String: " + e.getMessage());
4373
                        return null;
4374
                }
4375
            
4376
    }
4377

    
4378
        public static String structToString(STRUCT st) throws Exception {
4379
                
4380
                StringBuffer resp = new StringBuffer();
4381
                
4382
                resp.append("MDSYS.SDO_GEOMETRY(");
4383
                NUMBER ora_num = null;
4384
                STRUCT ora_struct = null;
4385
                ARRAY ora_arr = null;
4386
                
4387
                Datum[] dd = st.getOracleAttributes();
4388
                if (dd[0] instanceof NUMBER) {
4389
                        ora_num = (NUMBER) dd[0]; 
4390
                        resp.append(Integer.toString(ora_num.intValue()));
4391
                        resp.append(", ");
4392
                } else {
4393
                        throw new Exception("First component of SDO_GEOMETRY not a number; " + dd[0].getClass().getName());
4394
                }
4395
                
4396
                if (dd[1] instanceof NUMBER) {
4397
                        ora_num = (NUMBER) dd[1]; 
4398
                        resp.append(Integer.toString(ora_num.intValue()));
4399
                        resp.append(", ");
4400
                } else {
4401
                        resp.append("NULL, ");
4402
                }
4403
                
4404
                if (dd[2] instanceof STRUCT) {
4405
                        // special: point
4406
                        ora_struct = (STRUCT) dd[2];
4407
                        Datum[] aux = ora_struct.getOracleAttributes();
4408
                        double x = ((NUMBER) aux[0]).doubleValue();
4409
                        double y = ((NUMBER) aux[1]).doubleValue();
4410
                        resp.append(", SDO_POINT_TYPE(");
4411
                        resp.append(Double.toString(x));
4412
                        resp.append(", ");
4413
                        resp.append(Double.toString(y));
4414
                        resp.append(", NULL), NULL, NULL)");
4415
                        return resp.toString();
4416
                } else {
4417
                        resp.append("NULL, ");
4418
                }
4419
                
4420
                if (dd[3] instanceof ARRAY) {
4421
                        ora_arr = (ARRAY) dd[3];
4422
                        int[] aux = ora_arr.getIntArray();
4423
                        resp.append("MDSYS.SDO_ELEM_INFO_ARRAY(");
4424
                        resp.append(Integer.toString(aux[0]));
4425
                        for (int i=1; i<aux.length; i++) {
4426
                                resp.append(", ");
4427
                                resp.append(Integer.toString(aux[i]));
4428
                        }
4429
                        resp.append("), ");
4430

    
4431
                } else {
4432
                        throw new Exception("Component [3] is not an ARRAY: " + dd[3].getClass().getName());
4433
                }
4434
                
4435
                if (dd[4] instanceof ARRAY) {
4436
                        ora_arr = (ARRAY) dd[4];
4437
                        double[] aux = ora_arr.getDoubleArray();
4438
                        resp.append("MDSYS.SDO_ORDINATE_ARRAY(");
4439
                        resp.append(Double.toString(aux[0]));
4440
                        for (int i=1; i<aux.length; i++) {
4441
                                resp.append(", ");
4442
                                resp.append(Double.toString(aux[i]));
4443
                        }
4444
                        resp.append(")");
4445
                } else {
4446
                        throw new Exception("Component [4] is not an ARRAY: " + dd[4].getClass().getName());
4447
                }
4448

    
4449
                resp.append(")");;
4450
                return resp.toString();
4451
                
4452
        }
4453
        
4454
        
4455
        public static Object getId(FeatureReferenceProviderServices ref, FeatureType ft) {
4456
                
4457
                if (ft.hasOID()) {
4458
                        return ref.getOID();
4459
                } else {                        
4460
                        FeatureAttributeDescriptor[] fadd = ft.getPrimaryKey();
4461
                        Object resp = ref.getKeyValue(fadd[0].getName());
4462
                        if (resp == null) {
4463
                                logger.warn("Did not find PK in feat ref: " + fadd[0].getName());
4464
                        }
4465
                        return resp;
4466
                }
4467
        }
4468
        
4469
        
4470
        
4471
        
4472
        public static Geometry roughIntersection(Geometry geom, Envelope env) throws Exception {
4473
            
4474

    
4475
        if (geom instanceof MultiPrimitive) {
4476
            
4477
            MultiPrimitive mp = (MultiPrimitive) geom;
4478
            Envelope aux = null;
4479
            int n = mp.getPrimitivesNumber();
4480
            ArrayList acc = new ArrayList();
4481
            Envelope intenv = null;
4482
            
4483
            for (int i=0; i<n; i++) {
4484
                if (env.intersects(mp.getPrimitiveAt(i).getEnvelope())) {
4485
                    intenv = intersectEnvs(env, mp.getPrimitiveAt(i).getEnvelope());
4486
                    if (intenv != null) {
4487
                        acc.add(intenv);
4488
                    }
4489
                    
4490
                }
4491
            }
4492
            return envelopesToGeometry(acc);
4493
        } else {
4494
            if (geom instanceof Primitive) {
4495
                return geom.getEnvelope().getGeometry().intersection(env.getGeometry());
4496
            } else {
4497
                return geom.intersection(env.getGeometry());
4498
            }
4499
        }
4500

    
4501
            
4502
        }
4503
        
4504
        public static Envelope intersectEnvs(Envelope a, Envelope b) throws Exception {
4505
            
4506
        double min_x_a = a.getMinimum(0);
4507
        double min_y_a = a.getMinimum(1);
4508
        double max_x_a = a.getMaximum(0);
4509
        double max_y_a = a.getMaximum(1);
4510
        
4511
        double min_x_b = b.getMinimum(0);
4512
        double min_y_b = b.getMinimum(1);
4513
        double max_x_b = b.getMaximum(0);
4514
        double max_y_b = b.getMaximum(1);
4515
        
4516
        if (min_x_a > max_x_b
4517
            || min_x_b > max_x_a
4518
            || min_y_a > max_y_b
4519
            || min_y_b > max_y_a) {
4520
            return null;
4521
        } else {
4522
            
4523
            Rectangle2D ra = new Rectangle2D.Double(
4524
                min_x_a, min_y_a, max_x_a-min_x_a, max_y_a-min_y_a);
4525
            Rectangle2D rb = new Rectangle2D.Double(
4526
                min_x_b, min_y_b, max_x_b-min_x_b, max_y_b-min_y_b);
4527
            
4528
            Rectangle2D rc = new Rectangle2D.Double();
4529
            Rectangle2D.intersect(ra, rb, rc);
4530
            
4531
            return GeometryLocator.getGeometryManager().createEnvelope(
4532
                rc.getMinX(),
4533
                rc.getMinY(),
4534
                rc.getMaxX(),
4535
                rc.getMaxY(),
4536
                SUBTYPES.GEOM2D);
4537
            
4538
        }
4539
            
4540
            
4541
        }
4542
        
4543
        
4544
        
4545
    /**
4546
     * @param accum
4547
     * @return
4548
     */
4549
    public static Geometry envelopesToGeometry(ArrayList accum) throws Exception  {
4550

    
4551
        GeometryManager gm = GeometryLocator.getGeometryManager();
4552

    
4553
        if (accum.size() == 0) {
4554
            return gm.createNullGeometry(SUBTYPES.GEOM2D); 
4555
        }
4556
        
4557
        int len = accum.size();
4558
        GeneralPathX gpx = new GeneralPathX();
4559
        Envelope enve = null;
4560
        
4561
        for (int i=0; i<len; i++) {
4562
            enve = (Envelope) accum.get(i);
4563
            gpx.moveTo( enve.getMinimum(0), enve.getMinimum(1) );
4564
            gpx.lineTo( enve.getMinimum(0), enve.getMaximum(1) );
4565
            gpx.lineTo( enve.getMaximum(0), enve.getMaximum(1) );
4566
            gpx.lineTo( enve.getMaximum(0), enve.getMinimum(1) );
4567
            gpx.lineTo( enve.getMinimum(0), enve.getMinimum(1) );
4568
        }
4569
        
4570
        Geometry resp = null;
4571
        
4572
        try {
4573
            resp = gm.createMultiSurface(gpx, SUBTYPES.GEOM2D);
4574
        } catch (CreateGeometryException e) {
4575
            logger.error("While creating multi surface for aoi geom: " + e.getMessage());
4576
            return null;
4577
        }
4578
        return resp;
4579
    }
4580
    
4581
    
4582
    
4583
    /*
4584
    private static STRUCT getMultiLineAsStruct(ArrayList lines, int srid,
4585
        boolean threed, IConnection _conn, boolean hasSrid)
4586
        throws SQLException {
4587

4588
        int size = lines.size();
4589
        int geotype = 2006;
4590
        if (size == 1) {
4591
            geotype = 2002;
4592
        }
4593
        
4594
        int dim = 2;
4595
        int acum = 0;
4596
        double _z = 0; 
4597

4598
        if (threed) {
4599
            geotype = 3006;
4600
            if (size == 1) {
4601
                geotype = 3002;
4602
            }
4603
            dim = 3;
4604
        }
4605

4606
        NUMBER[] indices = new NUMBER[3 * size];
4607

4608
        for (int i = 0; i < size; i++) {
4609
            indices[3 * i] = new NUMBER(acum + 1);
4610
            indices[(3 * i) + 1] = new NUMBER(2);
4611
            indices[(3 * i) + 2] = new NUMBER(1);
4612
            acum = acum +
4613
                (dim * ((LineString3D) lines.get(i)).getLs().getNumPoints());
4614
        }
4615

4616
        int _ind = 0;
4617
        NUMBER[] ords = new NUMBER[acum];
4618

4619
        for (int i = 0; i < size; i++) {
4620
            LineString3D ls = (LineString3D) lines.get(i);
4621
            int num_p = ls.getLs().getNumPoints();
4622

4623
            for (int j = 0; j < num_p; j++) {
4624
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
4625
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
4626

4627
                if (threed) {
4628
                    _z = (ls.getZc() == null) ? 0 : ls.getZc()[j]; 
4629
                    ords[_ind + 2] = new NUMBER(_z);
4630
                }
4631

4632
                _ind = _ind + dim;
4633
            }
4634
        }
4635

4636
        STRUCT resp;
4637
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
4638
                ((ConnectionJDBC)_conn).getConnection());
4639
        Object[] obj = new Object[5];
4640
        obj[0] = new NUMBER(geotype);
4641

4642
        if (hasSrid) {
4643
            obj[1] = new NUMBER(srid);
4644
        }
4645
        else {
4646
            obj[1] = null;
4647
        }
4648

4649
        obj[2] = null;
4650
        obj[3] = indices;
4651
        obj[4] = ords;
4652
        resp = new STRUCT(dsc,((ConnectionJDBC)_conn).getConnection(), obj);
4653

4654
        return resp;
4655
    }
4656
    */
4657

    
4658

    
4659
}