Statistics
| Revision:

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

History | View | Annotate | Download (116 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
                GeometryType geometryType = geom.getGeometryType();
3735
                if (geometryType.isTypeOf(Geometry.TYPES.NULL)) {
3736
                        // null geometry
3737
            return null;
3738
        }
3739
                
3740
                
3741

    
3742
                boolean three = false;
3743

    
3744
                if (geom.getDimension() == 3) {
3745
                        three = true;
3746
                }
3747

    
3748
                STRUCT resp = null;
3749

    
3750
                if (geom instanceof MultiPoint2D) {
3751
                        resp = multiPoint2DToStruct((MultiPoint2D) geom, conn, osrid,
3752
                                        hasSrid);
3753
                        return resp;
3754
                }
3755

    
3756
                if (geom instanceof org.gvsig.fmap.geom.primitive.impl.Point2D) { // point 2/3d
3757
                        Coordinate p = getSingleCoordinate((Point) geom);
3758
                        resp = getMultiPointAsStruct(p, osrid, three, conn, hasSrid);
3759
                } else {
3760
                        if (geom instanceof Surface2D) { // polygon 2/3d
3761

    
3762
                                if (geom instanceof Circle2D) {
3763
                                        resp = getCircleAsStruct((Circle2D) geom, osrid, conn,
3764
                                                        hasSrid);
3765
                                } else {
3766
                                        // also FEllipse2D
3767
                                        resp = getMultiPolygonAsStruct(geom, osrid, three, conn,
3768
                                                        agu_b, hasSrid);
3769
                                }
3770
                        } else { // line 2/3d
3771

    
3772
                                List<LineString3D> _lines = getLineStrings(geom);
3773
                                resp = getMultiLineAsStruct(_lines, osrid, three, conn, hasSrid);
3774
                        }
3775
                }
3776

    
3777
                return resp;
3778
        }
3779
        
3780
        
3781
        
3782

    
3783

    
3784

    
3785
        public static int getShapeTypeFromArray(ArrayList arrlist) {
3786
                
3787
                int resp = ((Integer) arrlist.get(0)).intValue();
3788
                
3789
                int sz = arrlist.size();
3790
                int aux = 0;
3791
                for (int i=1; i<sz; i++) {
3792
                        aux = ((Integer) arrlist.get(i)).intValue();
3793
                        if (aux != resp) return TYPES.GEOMETRY;
3794
                }
3795
                return resp;
3796
        }
3797

    
3798
        // condition using ROWNUM with growing indexs to do a size-independent sample
3799
    public static String EXPONENTIAL_INDICES_CONDITION = null;
3800
    static {
3801
                EXPONENTIAL_INDICES_CONDITION = "(rownum < 40)";
3802
    }
3803
    
3804
    
3805
        public static void copyFeatureTypeToOracleStoreParams(
3806
                        EditableFeatureType efType, OracleStoreParameters params) {
3807
                
3808
                
3809
                // TODO Auto-generated method stub
3810
                
3811
        }
3812
        
3813

    
3814
    
3815
    /**
3816
     * Utility method to transform a struct into a IGeometry.
3817
     *
3818
     * @param st the struct to be converted
3819
     * @param complex comes from a complex sdo geometry
3820
     * @return the IGeometry
3821
     */
3822
    public static Geometry getGeometry(
3823
                    STRUCT st,
3824
                    boolean complex,
3825
                    boolean __tablehassrid,
3826
                    String __tablesrid,
3827
                    Connection _conn) {
3828

    
3829
            if (st == null) {
3830
                    Geometry aux = null;
3831
                    aux = createNullGeometry(SUBTYPES.GEOM2D);
3832
                    return aux;
3833
            }
3834

    
3835
        Datum[] the_data = null;
3836

    
3837
        try {
3838
            the_data = st.getOracleAttributes();
3839

    
3840
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
3841
            jgtype = oracleGTypeToFShapeType(jgtype, complex);
3842

    
3843
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
3844

    
3845
            if (dim < 2) {
3846
                dim = 2;
3847
            }
3848

    
3849
            int subty = getSubTypeFromDims(dim);
3850
            Geometry ig = createNullGeometry(subty);
3851

    
3852
            if (isActuallyACollection(the_data)) {
3853
                jgtype = TYPES.AGGREGATE;
3854
            }
3855

    
3856
            switch (jgtype) {
3857
            case TYPES.AGGREGATE:
3858
                ig = getFMapGeometryCollection(the_data, dim, __tablehassrid, __tablesrid, _conn);
3859
                break;
3860

    
3861
            case TYPES.POINT:
3862
                ig = getFMapGeometryPoint(the_data, dim);
3863
                break;
3864

    
3865
            case TYPES.CURVE:
3866
                ig = getFMapGeometryMultiLineString(the_data, dim);
3867
                break;
3868

    
3869
            case TYPES.SURFACE:
3870
                ig = getFMapGeometryMultipolygon(the_data, dim);
3871
                break;
3872
            }
3873

    
3874
            return ig;
3875
        } catch (Exception e) {
3876
            logger.error("While creating Geometry from STRUCT: " + e.getMessage());
3877
        }
3878
        return null;
3879
    }
3880
    
3881
    
3882
    /**
3883
     * Utility method to transform a struct into a IGeometry.
3884
     *
3885
     * @param st the struct to be converted
3886
     * @param complex comes from a complex sdo geometry
3887
     * @return the IGeometry
3888
     */
3889
    public static Primitive getPrimitive(STRUCT st, boolean complex) {
3890

    
3891
            GeometryManager gm = GeometryLocator.getGeometryManager();
3892
            Primitive resp = null;
3893
            
3894
            if (st == null) {
3895
                    try {
3896
                                resp = gm.createNullGeometry(SUBTYPES.GEOM2D);
3897
                        } catch (CreateGeometryException e) {
3898
                                logger.error("While creating null geometry: " + e.getMessage());
3899
                        }
3900
                        return resp;
3901
            }
3902

    
3903
        Datum[] the_data = null;
3904
        try {
3905
            the_data = st.getOracleAttributes();
3906

    
3907
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
3908
            jgtype = oracleGTypeToFShapeType(jgtype, complex);
3909

    
3910
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
3911

    
3912
            if (dim < 2) {
3913
                dim = 2;
3914
            }
3915

    
3916
                int subty = getSubTypeFromDims(dim);
3917
                Primitive ig = null;
3918
                try {
3919
                                ig = gm.createNullGeometry(subty);
3920
                        } catch (CreateGeometryException e) {
3921
                                logger.error("While creating null geometry: " + e.getMessage());
3922
                        }
3923

    
3924
            if (isActuallyACollection(the_data)) {
3925
                jgtype = TYPES.AGGREGATE;
3926
            }
3927

    
3928
            try {
3929
                switch (jgtype) {
3930
                case TYPES.POINT:
3931
                    ig = (Primitive) getFMapGeometryPoint(the_data, dim);
3932
                    break;
3933

    
3934
                case TYPES.CURVE:
3935
                    ig = (Primitive) getFMapGeometryMultiLineString(the_data, dim);
3936
                    break;
3937

    
3938
                case TYPES.SURFACE:
3939
                    ig = (Primitive) getFMapGeometryMultipolygon(the_data, dim);
3940
                    break;
3941
                default:
3942
                        logger.error("Aggregate of non primitives not supported.");
3943
                    break;
3944
                }
3945
            } catch (Exception ex) {
3946
                    logger.error("While creating primitive: " + ex.getMessage());
3947
            }
3948

    
3949
            return ig;
3950
        } catch (SQLException e) {
3951
            logger.error("While getting primitive: " + e.getMessage());
3952
        }
3953

    
3954
        return null;
3955
    }
3956
    
3957
    
3958
    private static int getSubTypeFromDims(int dim) {
3959
            
3960
            switch (dim) {
3961
            case 3:
3962
                    return SUBTYPES.GEOM3D;
3963
            case 4:
3964
                    return SUBTYPES.GEOM3DM;
3965
            default:
3966
                            return SUBTYPES.GEOM2D;
3967
            }
3968
        }
3969

    
3970
        public static Geometry getFMapGeometryCollection(
3971
                    Datum[] the_data,
3972
                    int dim,
3973
                    boolean tableHasSrid,
3974
                    String table_srid,
3975
                    Connection _conn) {
3976

    
3977
            NUMBER _srid = new NUMBER(0);
3978
        NUMBER main_type = new NUMBER((dim * 1000) + getStructType(the_data));
3979

    
3980

    
3981
        Datum[] all_info_array = null;
3982
        Object[] elems_info_aray = null;
3983
        Datum[] all_ords = null;
3984

    
3985
        Object[] ords_of_groups = null;
3986
        Object[] _elems_info_aray = null;
3987
        try {
3988
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
3989
            elems_info_aray = groupByElement(all_info_array);
3990
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
3991

    
3992
            ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
3993
            _elems_info_aray = new Object[elems_info_aray.length];
3994
        }
3995
        catch (SQLException e) {
3996
            logger.error("Unexpected error: " + e.getMessage());
3997
        }
3998

    
3999

    
4000
        for (int i = 0; i < elems_info_aray.length; i++) {
4001
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
4002
        }
4003

    
4004
        // _elems_info_aray, ords_of_groups
4005
        int no_of_elems = ords_of_groups.length;
4006
        Primitive[] geoms = new Primitive[no_of_elems];
4007

    
4008
        for (int i = 0; i < no_of_elems; i++) {
4009
            Datum[] item_info_array = null;
4010
            Datum[] item_ords = null;
4011
            NUMBER gtype = null;
4012

    
4013
            try {
4014
                item_info_array = (Datum[]) _elems_info_aray[i];
4015
                item_ords = (Datum[]) ords_of_groups[i];
4016

    
4017
                gtype = new NUMBER((dim * 1000) +
4018
                        (item_info_array[1].intValue() % 1000));
4019

    
4020
                if (tableHasSrid) {
4021
                        _srid = new NUMBER(Integer.parseInt(table_srid));
4022
                }
4023
            }
4024
            catch (SQLException se) {
4025
                logger.error("Unexpected error: " + se.getMessage());
4026
            }
4027

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

    
4031
            STRUCT itemst = null;
4032

    
4033
            if (tableHasSrid) {
4034

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

    
4075
                        FeatureSet set = null;
4076
                        try {
4077
                                FeatureQuery query = oraSrsStore.createFeatureQuery();
4078
                                query.setFilter(manager.createExpresion("EPSG = " + epsg));
4079
                                set = (FeatureSet) oraSrsStore.getDataSet(query);
4080
                                if (set.getSize() > 0) {
4081
                                        Iterator<Feature> it = set.iterator();
4082
                                        while (it.hasNext()) {
4083
                                                Feature feat = it.next();
4084
                                                Double ora = feat.getDouble("ORACLE");
4085
                                                int iora = ora.intValue();
4086
                                                double prefe = feat.getDouble("PRF_ORACLE");
4087
                                                if (prefe == 1) {
4088
                                                        isrs = iora;
4089
                                                        break;
4090
                                                }
4091
                                        }
4092
                                }
4093
                        } catch (DataException e) {
4094
                                e.printStackTrace();
4095
                        }
4096
                        if (isrs >= 0) {
4097
                                return Integer.toString(isrs);
4098
                        }
4099
                }
4100
                return null;
4101
        }
4102

    
4103
        /**
4104
         * Get EPSG SRS from Oracle SRS
4105
         * 
4106
         * @param oraSRID
4107
         * @return
4108
         */
4109
        public static Integer oracleSridToEpsg(String oraSRID) {
4110

    
4111
                DataManager manager = DALLocator.getDataManager();
4112
                Integer isrs = null;
4113
                
4114
                if (oraSRID != null) {
4115
                        FeatureStore oraSrsStore = (FeatureStore) OracleLibrary.getSRSDataStore();
4116

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

    
4141
        /**
4142
         * Get Oracle SRS from gvSIG projection
4143
         * 
4144
         * @param proj
4145
         * @return  
4146
         */
4147
        public static String projectionToOracleSrid(IProjection proj) {
4148
                if (proj != null) {
4149
                        String epsg = proj.getAbrev().trim();
4150
                        int ocu = epsg.indexOf(":");
4151
                        if (ocu != -1) {
4152
                                epsg = epsg.substring(ocu + 1);
4153
                        }
4154
                        return epsgToOracleSrid(epsg);
4155
                } else {
4156
                        return null;
4157
                }
4158
        }
4159

    
4160
        public static int dimensionsFromSubtype(int subtype) {
4161
                
4162
                switch (subtype) {
4163
                
4164
                case SUBTYPES.GEOM2D:
4165
                        return 2;
4166
                case SUBTYPES.GEOM3D:
4167
                case SUBTYPES.GEOM2DM:
4168
                        return 3;
4169
                case SUBTYPES.GEOM3DM:
4170
                        return 4;
4171
                default:
4172
                                logger.error("Unknown subtype: " + subtype + ". Returned 2 as number of dimensions.");
4173
                        return 2;
4174
                }
4175
        }
4176

    
4177
        public static Rectangle2D envelopeToRectangle2D(org.gvsig.fmap.geom.primitive.Envelope envelope) {
4178
                        
4179
                double x = envelope.getMinimum(0);
4180
                double y = envelope.getMinimum(1);
4181
                double w = envelope.getLength(0);
4182
                double h = envelope.getLength(1);
4183
                Rectangle2D resp = new Rectangle2D.Double(x,y,w,h);
4184
                return resp;
4185
        }
4186

    
4187
        public static Geometry createNullGeometry(int stype) {
4188
                
4189
        Geometry ig = null;
4190
        GeometryType nullgt = null;;
4191
                try {
4192
                        GeometryManager gm = GeometryLocator.getGeometryManager();
4193
                        nullgt = ((DefaultGeometryManager) gm).getGeometryType(DefaultNullGeometry.class.getName());
4194
                ig = new DefaultNullGeometry(nullgt);
4195
                } catch (GeometryTypeNotSupportedException e) {
4196
                        logger.error("While creating null geom: " + e.getMessage());
4197
                        return null;
4198
                }
4199
        return ig;
4200

    
4201
        }
4202
        
4203
        
4204
        
4205
    public static String getIntersectsEnvelopeSelect(
4206
                    String geo_col_name,
4207
                    Envelope enve,
4208
                    String ora_srid,
4209
                    boolean is_geo) {
4210
            
4211
        String resp = "";
4212
        String view_sdo = "";
4213
        
4214

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

    
4257
        } else {
4258
            
4259
            try {
4260
                                view_sdo = binaryUnionEnvs(envs, ora_srid, is_geo, GEOM_DEFAULT_TOL, conn, 0);
4261
                    resp = "(sdo_relate(" + geo_col_name + ", " + view_sdo +
4262
                            ", 'mask=anyinteract querytype=window') = 'TRUE')";
4263
                        } catch (Exception e) {
4264
                                logger.error("While getting union: " + e.getMessage(), e);
4265
                                resp = null;
4266
                        }
4267
        }
4268

    
4269
        return resp;
4270
    }
4271

    
4272
    /**
4273
     * @param envs
4274
     * @param ora_srid
4275
     * @param is_geo
4276
     * @param geomDefaultTol
4277
     * @return
4278
     */
4279
    public static String binaryUnionEnvs(
4280
        Envelope[] enves,
4281
        String ora_srid,
4282
        boolean is_geo,
4283
        String tol,
4284
        Connection conn,
4285
        int depth) throws Exception {
4286
        
4287
        if (enves == null || enves.length == 0) {
4288
            logger.error("Unexpected empty envelope array: " + enves);
4289
            return "";
4290
        }
4291
        
4292
        Envelope[] valid_enve = null;
4293
        if (depth == 0) {
4294
                valid_enve = getValidEnvelopes(enves, ora_srid, is_geo, tol, conn);
4295
        } else {
4296
                valid_enve = enves;
4297
        }
4298
        
4299
        if (valid_enve.length == 1) {
4300
            return getSdoConstructor(valid_enve[0], ora_srid, is_geo);
4301
        } else {
4302
            int s1 = valid_enve.length / 2;
4303
            int s2 = valid_enve.length - s1;
4304
            Envelope[] p1 = new Envelope[s1];
4305
            Envelope[] p2 = new Envelope[s2];
4306
            for (int i=0; i<s1; i++) {
4307
                p1[i] = valid_enve[i];
4308
            }
4309
            for (int i=0; i<s2; i++) {
4310
                p2[i] = valid_enve[s1 + i];
4311
            }
4312
            String resp = "sdo_geom.sdo_union(";
4313
            resp = resp + binaryUnionEnvs(p1, ora_srid, is_geo, tol, conn, depth+1) + ", ";
4314
            resp = resp + binaryUnionEnvs(p2, ora_srid, is_geo, tol, conn, depth+1) + ", " + tol + ")";
4315
            return resp;
4316
        }
4317
    }
4318

    
4319
    private static Envelope[] getValidEnvelopes(Envelope[] enves,
4320
                        String ora_srid, boolean is_geo, String tol, Connection conn) throws Exception {
4321
            
4322
            boolean valid = false;
4323
            Envelope[] resp = enves;
4324
            String union_str = null;
4325
            
4326
            while (!valid) {
4327
                    
4328
                    union_str = binaryUnionEnvs(
4329
                                    resp,
4330
                                    ora_srid,
4331
                                    is_geo,
4332
                                    tol,
4333
                                    conn,
4334
                                    1000);
4335
                    
4336
                    valid = testUnion(union_str, conn);
4337
                    if (!valid) {
4338
                            int[] mergeinds = getGoodMergeCoupe(resp);
4339
                            resp = mergeEnvelopes(resp, mergeinds);
4340
                    }
4341
            }
4342
                return resp;
4343
        }
4344

    
4345
        private static Envelope[] mergeEnvelopes(
4346
                        Envelope[] envs, int[] inds) throws Exception {
4347
                
4348
                if (envs == null || envs.length < 2) {
4349
                        logger.error("Unexpected envs (len must be >= 2): " + inds);
4350
                        return envs;
4351
                }
4352
                
4353
                if (inds == null || inds.length != 2) {
4354
                        logger.error("Unexpected inds (len must be 2): " + inds);
4355
                        return envs;
4356
                }
4357
                
4358
                GeometryManager gm = GeometryLocator.getGeometryManager();
4359
                
4360
                int len = envs.length;
4361
                Envelope[] resp = new Envelope[len-1];
4362
                
4363
                double minx = 0;
4364
                double miny = 0;
4365
                double maxx = 0;
4366
                double maxy = 0;
4367
        
4368
                Envelope e1 = envs[inds[0]];
4369
                Envelope e2 = envs[inds[1]];
4370
                
4371
                minx = Math.min(e1.getMinimum(0), e2.getMinimum(0));
4372
                miny = Math.min(e1.getMinimum(1), e2.getMinimum(1));
4373
                maxx = Math.max(e1.getMaximum(0), e2.getMaximum(0));
4374
                maxy = Math.max(e1.getMaximum(1), e2.getMaximum(1));
4375
                                
4376
                Envelope bigenv = gm.createEnvelope(
4377
                                minx, miny, maxx, maxy, SUBTYPES.GEOM2D);
4378
                
4379
                ArrayList<Envelope> accum = new ArrayList<Envelope>();
4380
                for (int i=0; i<len; i++) {
4381
                        if (i != inds[0] && i != inds[1]) {
4382
                                accum.add(envs[i]);
4383
                        }
4384
                }
4385
                
4386
                resp[0] = bigenv;
4387
                len = resp.length;
4388
                for (int i=1; i<len; i++) {
4389
                        if ((i-1) < accum.size() && accum.get(i-1) != null) {
4390
                                resp[i] = accum.get(i-1); 
4391
                        }
4392
                }
4393
                return resp;
4394
        }
4395

    
4396
        private static boolean testUnion(
4397
                        String union_str,
4398
                        Connection conn) {
4399
                
4400
                String qry = "SELECT " + union_str + " FROM DUAL";
4401

    
4402
                try {
4403
                        PreparedStatement _st = conn.prepareStatement(qry);
4404
                        _st.executeQuery();
4405
                        _st.close();
4406
                        return true;
4407
                } catch (Exception ex) {
4408
                        logger.warn("Oracle error. Envs will be simplified: " + ex.getMessage());
4409
                        return false;
4410
                }
4411
        }
4412

    
4413
        public static int[] getGoodMergeCoupe(Envelope[] envs) {
4414
            
4415
            int len = envs.length;
4416
            int[] resp = new int[2];
4417
            
4418
            for (int i=0; i<(len - 1); i++) {
4419
                    if (sameY(envs[i], envs[i+1])) {
4420
                            resp[0] = i;
4421
                            resp[1] = i+1;
4422
                            return resp;
4423
                    }
4424
            }
4425
            
4426
            // nothing found with same Y
4427
            double mindif = Double.MAX_VALUE;
4428
            double itemdif = 0;
4429
            int indi = 0;
4430
            for (int i=0; i<(len - 1); i++) {
4431
                    itemdif = difY(envs[i], envs[i+1]);
4432
                    if (itemdif < mindif) {
4433
                            mindif = itemdif; 
4434
                            indi = i;
4435
                    }
4436
            }
4437
            
4438
                resp[0] = indi;
4439
                resp[1] = indi+1;
4440
                return resp;
4441
    }
4442
    
4443
    
4444
    private static double difY(Envelope enva, Envelope envb) {
4445
            return Math.abs(enva.getMaximum(1) - envb.getMaximum(1));
4446
        }
4447

    
4448
        private static boolean sameY(Envelope enva, Envelope envb) {
4449
            
4450
            double tol = 0.1 * Math.min(enva.getLength(0), enva.getLength(1));
4451
            if (Math.abs(enva.getMaximum(1) - envb.getMaximum(1)) < tol) {
4452
                    return true;
4453
            } else {
4454
                    return false;
4455
            }
4456
        }
4457

    
4458
        /**
4459
     * @param geome
4460
     * @return
4461
     */
4462
    private static Envelope[] getEnvelopes(Geometry geome) {
4463
        
4464
        Envelope[] resp = null;
4465
        if (geome instanceof MultiSurface2D) {
4466
            
4467
            MultiSurface2D ms = (MultiSurface2D) geome;
4468
            int len = ms.getPrimitivesNumber();
4469
            resp = new Envelope[len];
4470
            for (int i=0; i<len; i++) {
4471
                resp[i] = ms.getPrimitiveAt(i).getEnvelope();
4472
            }
4473
            
4474
        } else {
4475
            resp = new Envelope[1];
4476
            resp[0] = geome.getEnvelope();
4477
        }
4478
        
4479
        return resp;
4480
    }
4481

    
4482
    public static String getSdoConstructor(Envelope enve, String ora_srid, boolean is_geo) {
4483
        String resp = "";
4484

    
4485
        try {
4486
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
4487
            String mdsys_sdo_ordinate_array = "";
4488

    
4489
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMinimum(0) + ", ";
4490
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMinimum(1) + ", ";
4491
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMaximum(0) + ", ";
4492
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array + enve.getMaximum(1);
4493

    
4494
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
4495
                mdsys_sdo_ordinate_array + ")";
4496

    
4497
            String aux = "";
4498

    
4499
            if (ora_srid != null) {
4500
                aux = ora_srid;
4501
            }
4502
            else {
4503
                aux = "null";
4504
            }
4505

    
4506
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
4507
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
4508
                ")";
4509
        }
4510
        catch (Exception ex) {
4511
                logger.error("While getting sdo contructor: " +
4512
                ex.getMessage());
4513
        }
4514

    
4515
        return resp;
4516
    }
4517
    
4518
    
4519
    public static String getSdoConstructor(
4520
                    Geometry geome, String ora_srid,
4521
                    boolean is_geo, Connection conn) {
4522
            
4523
            int ora_srid_int = 0;
4524
            STRUCT st = null;
4525
            ARRAY ora_arr = null;
4526

    
4527
            try {
4528
                    ora_srid_int = Integer.parseInt(ora_srid);
4529
                } catch (Exception e) { }
4530
            
4531
            try {
4532
                        st = geometryToSTRUCT(geome, conn, ora_srid_int, false, ora_srid != null);
4533
                        return structToString(st);
4534
                } catch (Exception e) {
4535
                        logger.error("While getting SDO geometry as String: " + e.getMessage());
4536
                        return null;
4537
                }
4538
            
4539
    }
4540

    
4541
        public static String structToString(STRUCT st) throws Exception {
4542
                
4543
                StringBuffer resp = new StringBuffer();
4544
                
4545
                resp.append("MDSYS.SDO_GEOMETRY(");
4546
                NUMBER ora_num = null;
4547
                STRUCT ora_struct = null;
4548
                ARRAY ora_arr = null;
4549
                
4550
                Datum[] dd = st.getOracleAttributes();
4551
                if (dd[0] instanceof NUMBER) {
4552
                        ora_num = (NUMBER) dd[0]; 
4553
                        resp.append(Integer.toString(ora_num.intValue()));
4554
                        resp.append(", ");
4555
                } else {
4556
                        throw new Exception("First component of SDO_GEOMETRY not a number; " + dd[0].getClass().getName());
4557
                }
4558
                
4559
                if (dd[1] instanceof NUMBER) {
4560
                        ora_num = (NUMBER) dd[1]; 
4561
                        resp.append(Integer.toString(ora_num.intValue()));
4562
                        resp.append(", ");
4563
                } else {
4564
                        resp.append("NULL, ");
4565
                }
4566
                
4567
                if (dd[2] instanceof STRUCT) {
4568
                        // special: point
4569
                        ora_struct = (STRUCT) dd[2];
4570
                        Datum[] aux = ora_struct.getOracleAttributes();
4571
                        double x = ((NUMBER) aux[0]).doubleValue();
4572
                        double y = ((NUMBER) aux[1]).doubleValue();
4573
                        resp.append(", SDO_POINT_TYPE(");
4574
                        resp.append(Double.toString(x));
4575
                        resp.append(", ");
4576
                        resp.append(Double.toString(y));
4577
                        resp.append(", NULL), NULL, NULL)");
4578
                        return resp.toString();
4579
                } else {
4580
                        resp.append("NULL, ");
4581
                }
4582
                
4583
                if (dd[3] instanceof ARRAY) {
4584
                        ora_arr = (ARRAY) dd[3];
4585
                        int[] aux = ora_arr.getIntArray();
4586
                        resp.append("MDSYS.SDO_ELEM_INFO_ARRAY(");
4587
                        resp.append(Integer.toString(aux[0]));
4588
                        for (int i=1; i<aux.length; i++) {
4589
                                resp.append(", ");
4590
                                resp.append(Integer.toString(aux[i]));
4591
                        }
4592
                        resp.append("), ");
4593

    
4594
                } else {
4595
                        throw new Exception("Component [3] is not an ARRAY: " + dd[3].getClass().getName());
4596
                }
4597
                
4598
                if (dd[4] instanceof ARRAY) {
4599
                        ora_arr = (ARRAY) dd[4];
4600
                        double[] aux = ora_arr.getDoubleArray();
4601
                        resp.append("MDSYS.SDO_ORDINATE_ARRAY(");
4602
                        resp.append(Double.toString(aux[0]));
4603
                        for (int i=1; i<aux.length; i++) {
4604
                                resp.append(", ");
4605
                                resp.append(Double.toString(aux[i]));
4606
                        }
4607
                        resp.append(")");
4608
                } else {
4609
                        throw new Exception("Component [4] is not an ARRAY: " + dd[4].getClass().getName());
4610
                }
4611

    
4612
                resp.append(")");;
4613
                return resp.toString();
4614
                
4615
        }
4616
        
4617
        
4618
        public static Object getId(FeatureReferenceProviderServices ref, FeatureType ft) {
4619
                
4620
                if (ft.hasOID()) {
4621
                        return ref.getOID();
4622
                } else {                        
4623
                        FeatureAttributeDescriptor[] fadd = ft.getPrimaryKey();
4624
                        Object resp = ref.getKeyValue(fadd[0].getName());
4625
                        if (resp == null) {
4626
                                logger.warn("Did not find PK in feat ref: " + fadd[0].getName());
4627
                        }
4628
                        return resp;
4629
                }
4630
        }
4631
        
4632
        
4633
        
4634
        
4635
        public static Geometry roughIntersection(Geometry geom, Envelope env) throws Exception {
4636
            
4637

    
4638
        if (geom instanceof MultiPrimitive) {
4639
            
4640
            MultiPrimitive mp = (MultiPrimitive) geom;
4641
            Envelope aux = null;
4642
            int n = mp.getPrimitivesNumber();
4643
            ArrayList acc = new ArrayList();
4644
            Envelope intenv = null;
4645
            
4646
            for (int i=0; i<n; i++) {
4647
                if (env.intersects(mp.getPrimitiveAt(i).getEnvelope())) {
4648
                    intenv = intersectEnvs(env, mp.getPrimitiveAt(i).getEnvelope());
4649
                    if (intenv != null) {
4650
                        acc.add(intenv);
4651
                    }
4652
                    
4653
                }
4654
            }
4655
            return envelopesToGeometry(acc);
4656
        } else {
4657
            if (geom instanceof Primitive) {
4658
                return geom.getEnvelope().getGeometry().intersection(env.getGeometry());
4659
            } else {
4660
                return geom.intersection(env.getGeometry());
4661
            }
4662
        }
4663

    
4664
            
4665
        }
4666
        
4667
        public static Envelope intersectEnvs(Envelope a, Envelope b) throws Exception {
4668
            
4669
        double min_x_a = a.getMinimum(0);
4670
        double min_y_a = a.getMinimum(1);
4671
        double max_x_a = a.getMaximum(0);
4672
        double max_y_a = a.getMaximum(1);
4673
        
4674
        double min_x_b = b.getMinimum(0);
4675
        double min_y_b = b.getMinimum(1);
4676
        double max_x_b = b.getMaximum(0);
4677
        double max_y_b = b.getMaximum(1);
4678
        
4679
        if (min_x_a > max_x_b
4680
            || min_x_b > max_x_a
4681
            || min_y_a > max_y_b
4682
            || min_y_b > max_y_a) {
4683
            return null;
4684
        } else {
4685
            
4686
            Rectangle2D ra = new Rectangle2D.Double(
4687
                min_x_a, min_y_a, max_x_a-min_x_a, max_y_a-min_y_a);
4688
            Rectangle2D rb = new Rectangle2D.Double(
4689
                min_x_b, min_y_b, max_x_b-min_x_b, max_y_b-min_y_b);
4690
            
4691
            Rectangle2D rc = new Rectangle2D.Double();
4692
            Rectangle2D.intersect(ra, rb, rc);
4693
            
4694
            return GeometryLocator.getGeometryManager().createEnvelope(
4695
                rc.getMinX(),
4696
                rc.getMinY(),
4697
                rc.getMaxX(),
4698
                rc.getMaxY(),
4699
                SUBTYPES.GEOM2D);
4700
            
4701
        }
4702
            
4703
            
4704
        }
4705
        
4706
        
4707
        
4708
    /**
4709
     * @param accum
4710
     * @return
4711
     */
4712
    public static Geometry envelopesToGeometry(ArrayList accum) throws Exception  {
4713

    
4714
        GeometryManager gm = GeometryLocator.getGeometryManager();
4715

    
4716
        if (accum.size() == 0) {
4717
            return gm.createNullGeometry(SUBTYPES.GEOM2D); 
4718
        }
4719
        
4720
        int len = accum.size();
4721
        GeneralPathX gpx = new GeneralPathX();
4722
        Envelope enve = null;
4723
        
4724
        for (int i=0; i<len; i++) {
4725
            enve = (Envelope) accum.get(i);
4726
            gpx.moveTo( enve.getMinimum(0), enve.getMinimum(1) );
4727
            gpx.lineTo( enve.getMinimum(0), enve.getMaximum(1) );
4728
            gpx.lineTo( enve.getMaximum(0), enve.getMaximum(1) );
4729
            gpx.lineTo( enve.getMaximum(0), enve.getMinimum(1) );
4730
            gpx.lineTo( enve.getMinimum(0), enve.getMinimum(1) );
4731
        }
4732
        
4733
        Geometry resp = null;
4734
        
4735
        try {
4736
            resp = gm.createMultiSurface(gpx, SUBTYPES.GEOM2D);
4737
        } catch (CreateGeometryException e) {
4738
            logger.error("While creating multi surface for aoi geom: " + e.getMessage());
4739
            return null;
4740
        }
4741
        return resp;
4742
    }
4743
    
4744
    
4745
    
4746
    /*
4747
    private static STRUCT getMultiLineAsStruct(ArrayList lines, int srid,
4748
        boolean threed, IConnection _conn, boolean hasSrid)
4749
        throws SQLException {
4750

4751
        int size = lines.size();
4752
        int geotype = 2006;
4753
        if (size == 1) {
4754
            geotype = 2002;
4755
        }
4756
        
4757
        int dim = 2;
4758
        int acum = 0;
4759
        double _z = 0; 
4760

4761
        if (threed) {
4762
            geotype = 3006;
4763
            if (size == 1) {
4764
                geotype = 3002;
4765
            }
4766
            dim = 3;
4767
        }
4768

4769
        NUMBER[] indices = new NUMBER[3 * size];
4770

4771
        for (int i = 0; i < size; i++) {
4772
            indices[3 * i] = new NUMBER(acum + 1);
4773
            indices[(3 * i) + 1] = new NUMBER(2);
4774
            indices[(3 * i) + 2] = new NUMBER(1);
4775
            acum = acum +
4776
                (dim * ((LineString3D) lines.get(i)).getLs().getNumPoints());
4777
        }
4778

4779
        int _ind = 0;
4780
        NUMBER[] ords = new NUMBER[acum];
4781

4782
        for (int i = 0; i < size; i++) {
4783
            LineString3D ls = (LineString3D) lines.get(i);
4784
            int num_p = ls.getLs().getNumPoints();
4785

4786
            for (int j = 0; j < num_p; j++) {
4787
                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
4788
                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
4789

4790
                if (threed) {
4791
                    _z = (ls.getZc() == null) ? 0 : ls.getZc()[j]; 
4792
                    ords[_ind + 2] = new NUMBER(_z);
4793
                }
4794

4795
                _ind = _ind + dim;
4796
            }
4797
        }
4798

4799
        STRUCT resp;
4800
        StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
4801
                ((ConnectionJDBC)_conn).getConnection());
4802
        Object[] obj = new Object[5];
4803
        obj[0] = new NUMBER(geotype);
4804

4805
        if (hasSrid) {
4806
            obj[1] = new NUMBER(srid);
4807
        }
4808
        else {
4809
            obj[1] = null;
4810
        }
4811

4812
        obj[2] = null;
4813
        obj[3] = indices;
4814
        obj[4] = ords;
4815
        resp = new STRUCT(dsc,((ConnectionJDBC)_conn).getConnection(), obj);
4816

4817
        return resp;
4818
    }
4819
    */
4820

    
4821

    
4822
}