Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / extensions / org.gvsig.oracle / src / org / gvsig / fmap / dal / store / oracle / OracleUtils.java @ 30300

History | View | Annotate | Download (81.4 KB)

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

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

    
66
import oracle.sql.ARRAY;
67
import oracle.sql.Datum;
68
import oracle.sql.NUMBER;
69
import oracle.sql.STRUCT;
70
import oracle.sql.StructDescriptor;
71

    
72
import org.apache.log4j.Logger;
73
import org.gvsig.fmap.geom.Geometry;
74
import org.gvsig.fmap.geom.GeometryLocator;
75
import org.gvsig.fmap.geom.GeometryManager;
76
import org.gvsig.fmap.geom.aggregate.impl.MultiCurve2DZ;
77
import org.gvsig.fmap.geom.aggregate.impl.MultiPoint2D;
78
import org.gvsig.fmap.geom.aggregate.impl.MultiPoint2DZ;
79
import org.gvsig.fmap.geom.exception.CreateGeometryException;
80
import org.gvsig.fmap.geom.primitive.Curve;
81
import org.gvsig.fmap.geom.primitive.GeneralPathX;
82
import org.gvsig.fmap.geom.primitive.Point;
83
import org.gvsig.fmap.geom.primitive.Surface;
84
import org.gvsig.fmap.geom.primitive.impl.Circle2D;
85
import org.gvsig.fmap.geom.primitive.impl.Curve2DZ;
86
import org.gvsig.fmap.geom.primitive.impl.Point2DZ;
87
import org.gvsig.fmap.geom.primitive.impl.Surface2DZ;
88
import org.gvsig.oracle.utils.LineString3D;
89

    
90
import com.vividsolutions.jts.algorithm.CGAlgorithms;
91
import com.vividsolutions.jts.geom.Coordinate;
92
import com.vividsolutions.jts.geom.CoordinateArrays;
93
import com.vividsolutions.jts.geom.Envelope;
94
import com.vividsolutions.jts.geom.GeometryFactory;
95
import com.vividsolutions.jts.geom.LineString;
96
import com.vividsolutions.jts.geom.LinearRing;
97
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
98

    
99
/**
100
 * Utility class with static methods.
101
 * 
102
 * @author jldominguez
103
 * 
104
 */
105
public class OracleUtils {
106
        private static Logger logger = Logger
107
                        .getLogger(OracleUtils.class.getName());
108
        private static double FLATNESS = 0.8;
109
        private static GeometryFactory geomFactory = new GeometryFactory();
110
        private static final double IRRELEVANT_DISTANCE = 0.00000001;
111
        private static Random rnd = new Random();
112
        private static DecimalFormat df = new DecimalFormat();
113
        private static DecimalFormatSymbols dfs = new DecimalFormatSymbols();
114

    
115
        /**
116
         * COnstructs a geometry from a file that contains a vertex per line:
117
         * 
118
         * x1 y1 z1 x2 y2 z2 ...
119
         * 
120
         * @param filepath
121
         *            vertices text file path
122
         * @param polygon
123
         *            whether it is a polygon or not
124
         * @return the created geometry
125
         * @throws CreateGeometryException
126
         */
127
        public static Geometry readGeometry3D(URL filepath, boolean polygon)
128
                        throws CreateGeometryException {
129

    
130
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
131

    
132
                GeneralPathX gpx = new GeneralPathX();
133
                File file = new File(filepath.getFile());
134
                List<Double> z = new ArrayList<Double>();
135

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

    
141
                        boolean move = true;
142

    
143
                        String line = br.readLine();
144

    
145
                        while (line != null) {
146
                                coords = parseLine(line);
147

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

    
159
                                        move = false;
160
                                }
161

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

    
169
                if (polygon) {
170
                        Surface surface = (Surface) geomManager.create(
171
                                        Geometry.TYPES.SURFACE, Geometry.SUBTYPES.GEOM2DZ);
172
                        surface.setGeneralPath(gpx);
173
                        for (int i = 0; i < z.size(); i++) {
174
                                surface
175
                                                .setCoordinateAt(i, 3, ((Double) z.get(i))
176
                                                                .doubleValue());
177
                        }
178
                        return surface;
179
                } else {
180
                        Curve curve = (Curve) geomManager.create(Geometry.TYPES.CURVE,
181
                                        Geometry.SUBTYPES.GEOM2DZ);
182
                        curve.setGeneralPath(gpx);
183
                        for (int i = 0; i < z.size(); i++) {
184
                                curve.setCoordinateAt(i, 3, ((Double) z.get(i)).doubleValue());
185
                        }
186
                        return curve;
187
                }
188
        }
189

    
190
        /**
191
         * 
192
         * @param line
193
         * @return
194
         */
195
        private static double[] parseLine(String line) {
196
                String[] sep = line.split(" ");
197
                double[] resp = new double[3];
198

    
199
                for (int i = 0; i < 3; i++)
200
                        resp[i] = 0.0;
201

    
202
                try {
203
                        resp[0] = Double.parseDouble(sep[0]);
204
                } catch (Exception ex) {
205
                }
206

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

    
213
                        if (sep.length > 2) {
214
                                try {
215
                                        resp[2] = Double.parseDouble(sep[2]);
216
                                } catch (Exception ex) {
217
                                }
218
                        }
219
                }
220

    
221
                return resp;
222
        }
223

    
224
        /**
225
         * 
226
         * @param mp2d
227
         * @param c
228
         * @param srid
229
         * @param hasSrid
230
         * @return
231
         * @throws SQLException
232
         */
233
        private static STRUCT multiPoint2DToStruct(MultiPoint2D mp2d, Connection c,
234
                        int srid, boolean hasSrid) throws SQLException {
235
                int np = mp2d.getNumgeometries();
236
                boolean threed = (mp2d instanceof MultiPoint2DZ);
237
                int gtype = 2005;
238
                int dim = 2;
239
                MultiPoint2DZ mp3d = null;
240

    
241
                if (threed) {
242
                        gtype = 3005;
243
                        dim = 3;
244
                        mp3d = (MultiPoint2DZ) mp2d;
245
                }
246

    
247
                NUMBER[] indices = new NUMBER[3];
248
                indices[0] = new NUMBER(1);
249
                indices[1] = new NUMBER(1);
250
                indices[2] = new NUMBER(np);
251

    
252
                NUMBER[] ords = new NUMBER[dim * np];
253

    
254
                for (int i = 0; i < np; i++) {
255
                        ords[dim * i] = new NUMBER(mp2d.getPoint(i).getX());
256
                        ords[(dim * i) + 1] = new NUMBER(mp2d.getPoint(i).getY());
257

    
258
                        if (threed) {
259
                                ords[(dim * i) + 2] = new NUMBER(mp3d.getZs()[i]);
260
                        }
261
                }
262

    
263
                STRUCT resp;
264
                StructDescriptor dsc = StructDescriptor.createDescriptor(
265
                                "MDSYS.SDO_GEOMETRY", c);
266
                Object[] obj = new Object[5];
267
                obj[0] = new NUMBER(gtype);
268

    
269
                if (hasSrid) {
270
                        obj[1] = new NUMBER(srid);
271
                } else { // , boolean hasSrid
272
                        obj[1] = null;
273
                }
274

    
275
                obj[2] = null;
276
                obj[3] = indices;
277
                obj[4] = ords;
278
                resp = new STRUCT(dsc, c, obj);
279

    
280
                return resp;
281
        }
282

    
283
        /**
284
         * 
285
         * @param fcirc
286
         * @param srid
287
         * @param _conn
288
         * @param hasSrid
289
         * @return
290
         * @throws SQLException
291
         */
292
        private static STRUCT getCircleAsStruct(Circle2D fcirc, int srid,
293
                        Connection _conn, boolean hasSrid) throws SQLException {
294
                int geotype = 2003;
295
                NUMBER[] indices = new NUMBER[3];
296
                indices[0] = new NUMBER(1);
297
                indices[1] = new NUMBER(1003);
298
                indices[2] = new NUMBER(4);
299

    
300
                NUMBER[] ords = new NUMBER[6];
301
                Coordinate[] three_points = getThreePointsOfCircumference(fcirc
302
                                .getCenter(), fcirc.getRadious());
303

    
304
                for (int i = 0; i < three_points.length; i++) {
305
                        ords[i * 2] = new NUMBER(three_points[i].x);
306
                        ords[(i * 2) + 1] = new NUMBER(three_points[i].y);
307
                }
308

    
309
                STRUCT resp;
310
                StructDescriptor dsc = StructDescriptor.createDescriptor(
311
                                "MDSYS.SDO_GEOMETRY", _conn);
312
                Object[] obj = new Object[5];
313
                obj[0] = new NUMBER(geotype);
314

    
315
                if (hasSrid) {
316
                        obj[1] = new NUMBER(srid);
317
                } else {
318
                        obj[1] = null;
319
                }
320

    
321
                obj[2] = null;
322
                obj[3] = indices;
323
                obj[4] = ords;
324
                resp = new STRUCT(dsc, _conn, obj);
325

    
326
                return resp;
327
        }
328

    
329
        /**
330
         * 
331
         * @param cntr
332
         * @param radius
333
         * @return
334
         */
335
        private static Coordinate[] getThreePointsOfCircumference(Point cntr,
336
                        double radius) {
337
                Coordinate[] resp = new Coordinate[3];
338
                double x;
339
                double y;
340
                double alpha = 0;
341

    
342
                for (int i = 0; i < 3; i++) {
343
                        alpha = (i * 120.0 * Math.PI) / 180.0;
344
                        x = cntr.getX() + (radius * Math.cos(alpha));
345
                        y = cntr.getY() + (radius * Math.sin(alpha));
346
                        resp[i] = new Coordinate(x, y);
347
                }
348

    
349
                return resp;
350
        }
351

    
352
        /**
353
         * 
354
         * @param pto
355
         * @return
356
         */
357
        private static Coordinate getSingleCoordinate(Point pto) {
358
                // TODO Auto-generated method stub
359
                Coordinate resp = new Coordinate();
360
                resp.x = pto.getX();
361
                resp.y = pto.getY();
362

    
363
                if (pto instanceof Point2DZ) {
364
                        resp.z = ((Point2DZ) pto).getCoordinateAt(3);
365
                }
366

    
367
                return resp;
368
        }
369

    
370
        /**
371
         * 
372
         * @param cc
373
         * @return
374
         */
375
        private static List<Coordinate> ensureSensibleLineString(List cc) {
376
                if (cc.size() == 2) {
377
                        if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(cc
378
                                        .size() - 1))) {
379
                                List resp = new ArrayList();
380
                                resp.add(cc.get(0));
381

    
382
                                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
383
                                newc.x = newc.x + IRRELEVANT_DISTANCE;
384
                                resp.add(newc);
385

    
386
                                return resp;
387
                        }
388
                }
389

    
390
                return cc;
391
        }
392

    
393
        /**
394
         * 
395
         * @param c1
396
         * @param c2
397
         * @return
398
         */
399
        private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
400
                if (c1.x != c2.x) {
401
                        return false;
402
                }
403

    
404
                if (c1.y != c2.y) {
405
                        return false;
406
                }
407

    
408
                return true;
409
        }
410

    
411
        /**
412
         * 
413
         * @param cc
414
         * @return
415
         */
416
        private static List getClosedRelevantPolygon(List cc) {
417
                if (cc.size() == 2) {
418
                        return getMinClosedCoords((Coordinate) cc.get(0));
419
                }
420

    
421
                if (cc.size() == 3) {
422
                        if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
423
                                return getMinClosedCoords((Coordinate) cc.get(0));
424
                        }
425

    
426
                        if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
427
                                return getMinClosedCoords((Coordinate) cc.get(0));
428
                        }
429

    
430
                        if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
431
                                return getMinClosedCoords((Coordinate) cc.get(1));
432
                        }
433

    
434
                        cc.add(cc.get(0));
435

    
436
                        return cc;
437
                }
438

    
439
                if (!sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(cc
440
                                .size() - 1))) {
441
                        cc.add(cc.get(0));
442
                }
443

    
444
                return cc;
445
        }
446

    
447
        /**
448
         * 
449
         * @param c
450
         * @return
451
         */
452
        private static List getMinClosedCoords(Coordinate c) {
453
                List resp = new ArrayList();
454
                resp.add(c);
455

    
456
                Coordinate nc = new Coordinate(c);
457
                nc.x = nc.x + IRRELEVANT_DISTANCE;
458
                resp.add(nc);
459

    
460
                Coordinate nc2 = new Coordinate(nc);
461
                nc2.y = nc2.y + IRRELEVANT_DISTANCE;
462
                resp.add(nc2);
463

    
464
                resp.add(new Coordinate(c));
465

    
466
                return resp;
467
        }
468

    
469
        /**
470
         * 
471
         * @param c
472
         * @return
473
         */
474
        private static LinearRing getMinLinearRing(Coordinate c) {
475
                Coordinate[] p = new Coordinate[4];
476
                p[0] = c;
477

    
478
                Coordinate nc = new Coordinate(c);
479
                nc.x = nc.x + IRRELEVANT_DISTANCE;
480

    
481
                Coordinate nc2 = new Coordinate(nc);
482
                nc2.y = nc2.y - IRRELEVANT_DISTANCE;
483
                p[1] = nc;
484
                p[2] = nc2;
485
                p[3] = new Coordinate(c);
486

    
487
                CoordinateArraySequence cs = new CoordinateArraySequence(p);
488
                LinearRing ls = new LinearRing(cs, geomFactory);
489

    
490
                return ls;
491
        }
492

    
493
        /**
494
         * 
495
         * @return
496
         */
497
        private static double[] getMinLinearRingZ() {
498
                double[] resp = new double[4];
499

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

    
503
                return resp;
504
        }
505

    
506
        /**
507
         * 
508
         * @param testPoint
509
         * @param pointList
510
         * @return
511
         */
512
        private static boolean pointInList(Coordinate testPoint,
513
                        Coordinate[] pointList) {
514
                int t;
515
                int numpoints;
516
                Coordinate p;
517

    
518
                numpoints = Array.getLength(pointList);
519

    
520
                for (t = 0; t < numpoints; t++) {
521
                        p = pointList[t];
522

    
523
                        if ((testPoint.x == p.x)
524
                                        && (testPoint.y == p.y)
525
                                        && ((testPoint.z == p.z) || (!(testPoint.z == testPoint.z))) // nan
526
                        // test;
527
                        // x!=x
528
                        // iff
529
                        // x
530
                        // is
531
                        // nan
532
                        ) {
533
                                return true;
534
                        }
535
                }
536

    
537
                return false;
538
        }
539

    
540
        /***
541
         * 
542
         * @param mpolygon
543
         * @return
544
         */
545
        private static List getPolygonsEasily(Geometry mpolygon) {
546
                boolean threed = false;
547

    
548
                if (mpolygon instanceof Surface2DZ) {
549
                        threed = true;
550
                }
551

    
552
                int start_ind = 0;
553
                int end_ind = 0;
554
                int ind = 0;
555
                int new_size;
556
                List arrayCoords = null;
557
                List resp = new ArrayList();
558
                Coordinate[] points = null;
559
                int theType = -99;
560
                double[] theData = new double[6];
561
                Coordinate onlyCoord = null;
562
                int numParts = 0;
563

    
564
                PathIterator theIterator = mpolygon.getPathIterator(null, FLATNESS);
565

    
566
                while (!theIterator.isDone()) {
567
                        // while not done
568
                        theType = theIterator.currentSegment(theData);
569

    
570
                        if (onlyCoord == null) {
571
                                onlyCoord = new Coordinate();
572
                                onlyCoord.x = theData[0];
573
                                onlyCoord.y = theData[1];
574
                        }
575

    
576
                        switch (theType) {
577
                        case PathIterator.SEG_MOVETO:
578

    
579
                                if (arrayCoords == null) {
580
                                        arrayCoords = new ArrayList();
581
                                } else {
582
                                        end_ind = ind - 1;
583

    
584
                                        arrayCoords = getClosedRelevantPolygon(arrayCoords);
585
                                        new_size = arrayCoords.size();
586

    
587
                                        if (arrayCoords != null) {
588
                                                points = CoordinateArrays
589
                                                                .toCoordinateArray(arrayCoords);
590

    
591
                                                try {
592
                                                        LinearRing aux = geomFactory
593
                                                                        .createLinearRing(points);
594
                                                        double[] z = null;
595

    
596
                                                        if (threed) {
597
                                                                z = getZ((Surface2DZ) mpolygon, start_ind,
598
                                                                                end_ind, new_size);
599
                                                        }
600

    
601
                                                        LineString3D ring = new LineString3D(aux, z);
602

    
603
                                                        if (CGAlgorithms.isCCW(points)) {
604
                                                                resp.add(ring);
605
                                                        } else {
606
                                                                resp.add(ring.createReverse());
607
                                                        }
608
                                                } catch (Exception e) {
609
                                                        logger.error("Topology exception: "
610
                                                                        + e.getMessage());
611

    
612
                                                        return null;
613
                                                }
614
                                        }
615

    
616
                                        arrayCoords = new ArrayList();
617

    
618
                                        start_ind = ind;
619
                                }
620

    
621
                                numParts++;
622

    
623
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
624
                                ind++;
625

    
626
                                break;
627

    
628
                        case PathIterator.SEG_LINETO:
629
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
630
                                ind++;
631

    
632
                                break;
633

    
634
                        case PathIterator.SEG_QUADTO:
635
                                logger.info("SEG_QUADTO Not supported here");
636
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
637
                                arrayCoords.add(new Coordinate(theData[2], theData[3]));
638
                                ind++;
639
                                ind++;
640

    
641
                                break;
642

    
643
                        case PathIterator.SEG_CUBICTO:
644
                                logger.info("SEG_CUBICTO Not supported here");
645
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
646
                                arrayCoords.add(new Coordinate(theData[2], theData[3]));
647
                                arrayCoords.add(new Coordinate(theData[4], theData[5]));
648
                                ind++;
649
                                ind++;
650
                                ind++;
651

    
652
                                break;
653

    
654
                        case PathIterator.SEG_CLOSE:
655

    
656
                                // Coordinate firstCoord = (Coordinate) arrayCoords.get(0);
657
                                // arrayCoords.add(new Coordinate(firstCoord.x, firstCoord.y));
658
                                break;
659
                        } // end switch
660

    
661
                        theIterator.next();
662
                } // end while loop
663

    
664
                end_ind = ind - 1;
665

    
666
                // null shape:
667
                if (arrayCoords == null) {
668
                        arrayCoords = new ArrayList();
669

    
670
                        Coordinate _c = new Coordinate(0, 0, 0);
671
                        arrayCoords.add(new Coordinate(_c));
672
                        arrayCoords.add(new Coordinate(_c));
673
                }
674

    
675
                // --------------------------------------------
676
                arrayCoords = getClosedRelevantPolygon(arrayCoords);
677
                new_size = arrayCoords.size();
678

    
679
                if (arrayCoords != null) {
680
                        points = CoordinateArrays.toCoordinateArray(arrayCoords);
681

    
682
                        try {
683
                                LinearRing aux = geomFactory.createLinearRing(points);
684
                                double[] z = null;
685

    
686
                                if (threed) {
687
                                        z = getZ((Surface2DZ) mpolygon, start_ind, end_ind,
688
                                                        new_size);
689
                                }
690

    
691
                                LineString3D ring = new LineString3D(aux, z);
692

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

    
701
                                return null;
702
                        }
703
                }
704

    
705
                if (resp.size() == 0) {
706
                        resp.add(new LineString3D(getMinLinearRing(onlyCoord),
707
                                        getMinLinearRingZ()));
708
                }
709

    
710
                return resp;
711
        }
712

    
713
        /**
714
         * Utility method to reverse an array of doubles.
715
         * 
716
         * @param _z
717
         *            an array of doubles to be reversed.
718
         * 
719
         * @return the reversed array of doubles
720
         */
721
        public static double[] reverseArray(double[] _z) {
722
                int size = _z.length;
723
                double[] resp = new double[size];
724

    
725
                for (int i = 0; i < size; i++) {
726
                        resp[i] = _z[size - 1 - i];
727
                }
728

    
729
                return resp;
730
        }
731

    
732
        /**
733
         * Utility method to reverse an array of coordinates
734
         * 
735
         * @param _z
736
         *            an array of coordinaes to be reversed.
737
         * 
738
         * @return the reversed array of coordinates
739
         */
740
        public static Coordinate[] reverseCoordinateArray(Coordinate[] _z) {
741
                int size = _z.length;
742
                Coordinate[] resp = new Coordinate[size];
743

    
744
                for (int i = 0; i < size; i++) {
745
                        resp[i] = _z[size - 1 - i];
746
                }
747

    
748
                return resp;
749
        }
750

    
751
        /**
752
         * 
753
         * @param geom
754
         * @param _str
755
         * @param _end
756
         * @param size
757
         * @return
758
         */
759
        private static double[] getZ(Geometry geom, int _str, int _end, int size) {
760
                double[] resp = new double[size];
761
                
762
                double[] allz = new double[1];
763
                
764
                if(geom instanceof Point2DZ){
765
                        allz[0] = ((Point2DZ)geom).getCoordinateAt(3);
766
                }
767
                if(geom instanceof MultiPoint2DZ){
768
                        allz = ((MultiPoint2DZ)geom).getZs();                        
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 MultiCurve2DZ){
778
                        allz = ((MultiCurve2DZ)geom).getZs();                        
779
                }
780
                if(geom instanceof Surface2DZ){
781
                        allz[0] = ((Surface2DZ)geom).getCoordinateAt(3);
782
                }
783
                if(geom instanceof MultiSurface2DZ){
784
                        allz = ((MultiSurface2DZ)geom).getZs();                        
785
                }
786
                
787
                
788

    
789
                for (int i = _str; ((i <= _end) && ((i - _str) < size)); i++) {
790
                        resp[i - _str] = allz[i];
791
                }
792

    
793
                if ((_end - _str + 1) < size) {
794
                        double repe = allz[_end];
795

    
796
                        for (int i = (_end - _str + 1); i < size; i++) {
797
                                resp[i] = repe;
798
                        }
799
                }
800

    
801
                return resp;
802
        }
803

    
804
        /**
805
         * 
806
         * @param mlines
807
         * @return
808
         */
809
        private static List<LineString3D> getLineStrings(Geometry mlines) {
810
                boolean threed = false;
811

    
812
                if (mlines instanceof Curve2DZ) {
813
                        threed = true;
814
                }
815

    
816
                int start_ind = 0;
817
                int end_ind = 0;
818
                int ind = 0;
819
                int new_size = 0;
820

    
821
                LineString3D lin;
822

    
823
                List<LineString3D> arrayLines = new ArrayList<LineString3D>();
824
                PathIterator theIterator = mlines.getPathIterator(null, FLATNESS);
825
                int theType = -99;
826
                double[] theData = new double[6];
827
                List arrayCoords = null;
828
                int numParts = 0;
829

    
830
                while (!theIterator.isDone()) {
831
                        // while not done
832
                        theType = theIterator.currentSegment(theData);
833

    
834
                        switch (theType) {
835
                        case PathIterator.SEG_MOVETO:
836

    
837
                                if (arrayCoords == null) {
838
                                        arrayCoords = new ArrayList();
839
                                } else {
840
                                        end_ind = ind - 1;
841
                                        arrayCoords = ensureSensibleLineString(arrayCoords);
842
                                        new_size = arrayCoords.size();
843

    
844
                                        LineString aux = geomFactory
845
                                                        .createLineString(CoordinateArrays
846
                                                                        .toCoordinateArray(arrayCoords));
847
                                        double[] z = null;
848

    
849
                                        if (threed) {
850
                                                z = getZ((Curve2DZ) mlines, start_ind, end_ind,
851
                                                                new_size);
852
                                        }
853

    
854
                                        lin = new LineString3D(aux, z);
855
                                        arrayLines.add(lin);
856
                                        arrayCoords = new ArrayList();
857

    
858
                                        start_ind = ind;
859
                                }
860

    
861
                                numParts++;
862
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
863

    
864
                                break;
865

    
866
                        case PathIterator.SEG_LINETO:
867
                                arrayCoords.add(new Coordinate(theData[0], theData[1]));
868

    
869
                                break;
870

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

    
874
                                break;
875

    
876
                        case PathIterator.SEG_CUBICTO:
877
                                logger.info("Not supported here: SEG_CUBICTO");
878

    
879
                                break;
880

    
881
                        case PathIterator.SEG_CLOSE:
882

    
883
                                Coordinate firstCoord = (Coordinate) arrayCoords.get(0);
884
                                arrayCoords.add(new Coordinate(firstCoord.x, firstCoord.y));
885

    
886
                                break;
887
                        } // end switch
888

    
889
                        theIterator.next();
890
                        ind++;
891
                } // end while loop
892

    
893
                arrayCoords = ensureSensibleLineString(arrayCoords);
894
                new_size = arrayCoords.size();
895

    
896
                LineString aux = geomFactory.createLineString(CoordinateArrays
897
                                .toCoordinateArray(arrayCoords));
898
                double[] z = null;
899

    
900
                if (threed) {
901
                        z = getZ((Curve2DZ) mlines, start_ind, end_ind, new_size);
902
                }
903

    
904
                lin = new LineString3D(aux, z);
905
                arrayLines.add(lin);
906

    
907
                return arrayLines;
908
        }
909

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

    
922
                if (threed) {
923
                        for (int i = 0; i < size; i++) {
924
                                resp = resp + cc[i].x + " " + cc[i].y + " " + z[i] + ", ";
925
                        }
926

    
927
                        resp = resp.substring(0, resp.length() - 2);
928
                        resp = resp + ")";
929
                } else {
930
                        for (int i = 0; i < size; i++) {
931
                                resp = resp + cc[i].x + " " + cc[i].y + ", ";
932
                        }
933

    
934
                        resp = resp.substring(0, resp.length() - 2);
935
                        resp = resp + ")";
936
                }
937

    
938
                return resp;
939
        }
940

    
941
        /**
942
         * 
943
         * @param ml
944
         * @param threed
945
         * @return
946
         */
947
        private static String multiLineStringToWKT(List ml, boolean threed) {
948
                String resp = "MULTILINESTRING(";
949

    
950
                for (int i = 0; i < ml.size(); i++) {
951
                        LineString3D ls = (LineString3D) ml.get(i);
952
                        resp = resp + lineStringToWKT(ls, threed) + ", ";
953
                }
954

    
955
                resp = resp.substring(0, resp.length() - 2) + ")";
956

    
957
                return resp;
958
        }
959

    
960
        /**
961
         * 
962
         * @param pols
963
         * @param threed
964
         * @return
965
         */
966
        private static String polygonsToWKT(List pols, boolean threed) {
967
                String resp = "MULTIPOLYGON(";
968
                LineString3D ls = null;
969

    
970
                for (int i = 0; i < pols.size(); i++) {
971
                        ls = (LineString3D) pols.get(i);
972
                        resp = resp + "(" + lineStringToWKT(ls, threed) + "), ";
973
                }
974

    
975
                resp = resp.substring(0, resp.length() - 2) + ")";
976

    
977
                return resp;
978
        }
979

    
980
        /**
981
         * 
982
         * @param shell
983
         * @param holes
984
         * @param threed
985
         * @return
986
         */
987
        private static String shellAndHolesToWKT(LineString3D shell,
988
                        List holes, boolean threed) {
989
                String resp = "(";
990
                resp = resp + lineStringToWKT(shell, threed);
991

    
992
                if (holes.size() > 0) {
993
                        for (int i = 0; i < holes.size(); i++) {
994
                                LineString3D ls = (LineString3D) holes.get(i);
995
                                resp = resp + ", " + lineStringToWKT(ls, threed);
996
                        }
997
                }
998

    
999
                resp = resp + ")";
1000

    
1001
                return resp;
1002
        }
1003

    
1004
        /**
1005
         * 
1006
         * @param shells
1007
         * @param hFs
1008
         * @param threed
1009
         * @return
1010
         */
1011
        private static String multiPolygonToWKT(List shells, List hFs,
1012
                        boolean threed) {
1013
                String resp = "MULTIPOLYGON(";
1014
                LineString3D ls = null;
1015
                List holes;
1016

    
1017
                for (int i = 0; i < shells.size(); i++) {
1018
                        ls = (LineString3D) shells.get(i);
1019
                        holes = (List) hFs.get(i);
1020
                        resp = resp + shellAndHolesToWKT(ls, holes, threed) + ", ";
1021
                }
1022

    
1023
                resp = resp.substring(0, resp.length() - 2) + ")";
1024

    
1025
                return resp;
1026
        }
1027

    
1028
        /**
1029
         * 
1030
         * @param point
1031
         * @param threed
1032
         * @return
1033
         */
1034
        private static String pointToWKT(Point point, boolean threed) {
1035
                String resp = "POINT(" + point.getX() + " " + point.getY();
1036

    
1037
                if ((threed) && (point instanceof Point2DZ)) {
1038
                        resp = resp + " " + ((Point2DZ) point).getCoordinateAt(3);
1039
                }
1040

    
1041
                resp = resp + ")";
1042

    
1043
                return resp;
1044
        }
1045

    
1046
        /**
1047
         * 
1048
         * @param n
1049
         * @param d
1050
         * @return
1051
         */
1052
        private static int twoDIndexToDimsIndex(int n, int d) {
1053
                return ((d * (n - 1)) / 2) + 1;
1054
        }
1055

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

    
1067
                for (int i = 3; i < infos.length; i = i + 3) {
1068
                        int oldind = infos[i].intValue();
1069
                        oldind = twoDIndexToDimsIndex(oldind, d);
1070
                        infos[i] = new NUMBER(oldind);
1071

    
1072
                        //
1073
                        oldind = infos[i + 1].intValue();
1074
                        infos[i + 1] = new NUMBER(infos[1].intValue());
1075
                }
1076

    
1077
                ARRAY resp = new ARRAY(old.getDescriptor(), old.getOracleConnection(),
1078
                                infos);
1079

    
1080
                return resp;
1081
        }
1082

    
1083
        /**
1084
         * 
1085
         * @param p
1086
         * @param ls
1087
         * @return
1088
         */
1089
        private static boolean isPointInsideLineString(Coordinate p, LineString ls) {
1090
                Envelope env = ls.getEnvelopeInternal();
1091

    
1092
                if (!env.contains(p)) {
1093
                        return false;
1094
                }
1095

    
1096
                return CGAlgorithms.isPointInRing(p, ls.getCoordinates());
1097
        }
1098

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

    
1114
                if (size <= 10) {
1115
                        for (int i = 0; i < size; i++) {
1116
                                aux = inc[i];
1117

    
1118
                                if (!isPointInsideLineString(aux, _out)) {
1119
                                        return false;
1120
                                }
1121
                        }
1122

    
1123
                        return true;
1124
                } else {
1125
                        for (int i = 0; i < samples; i++) {
1126
                                aux = inc[rnd.nextInt(size)];
1127

    
1128
                                if (!isPointInsideLineString(aux, _out)) {
1129
                                        return false;
1130
                                }
1131
                        }
1132

    
1133
                        return true;
1134
                }
1135
        }
1136

    
1137
        /**
1138
         * 
1139
         * @param pols
1140
         * @param srid
1141
         * @param threed
1142
         * @param _conn
1143
         * @param agu_bien
1144
         * @param hasSrid
1145
         * @return
1146
         * @throws SQLException
1147
         */
1148
        private static STRUCT getMultiPolygonAsStruct(List pols, int srid,
1149
                        boolean threed, Connection _conn, boolean agu_bien, boolean hasSrid)
1150
                        throws SQLException {
1151
                int size = pols.size();
1152
                int geotype = 2007;
1153
                int dim = 2;
1154
                int acum = 0;
1155

    
1156
                if (threed) {
1157
                        geotype = 3007;
1158
                        dim = 3;
1159
                }
1160

    
1161
                NUMBER[] indices = new NUMBER[3 * size];
1162

    
1163
                for (int i = 0; i < size; i++) {
1164
                        indices[3 * i] = new NUMBER(acum + 1);
1165
                        indices[(3 * i) + 1] = new NUMBER(1003);
1166
                        indices[(3 * i) + 2] = new NUMBER(1);
1167
                        acum = acum
1168
                                        + (dim * ((LineString3D) pols.get(i)).getLs()
1169
                                                        .getNumPoints());
1170
                }
1171

    
1172
                int _ind = 0;
1173
                NUMBER[] ords = new NUMBER[acum];
1174

    
1175
                for (int i = 0; i < size; i++) {
1176
                        LineString3D ls = (LineString3D) pols.get(i);
1177
                        int num_p = ls.getLs().getNumPoints();
1178

    
1179
                        for (int j = 0; j < num_p; j++) {
1180
                                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1181
                                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1182

    
1183
                                if (threed) {
1184
                                        ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1185
                                }
1186

    
1187
                                _ind = _ind + dim;
1188
                        }
1189
                }
1190

    
1191
                STRUCT resp;
1192
                StructDescriptor dsc = StructDescriptor.createDescriptor(
1193
                                "MDSYS.SDO_GEOMETRY", _conn);
1194
                Object[] obj = new Object[5];
1195
                obj[0] = new NUMBER(geotype);
1196

    
1197
                if (hasSrid) {
1198
                        obj[1] = new NUMBER(srid);
1199
                } else {
1200
                        obj[1] = null;
1201
                }
1202

    
1203
                obj[2] = null;
1204
                obj[3] = indices;
1205
                obj[4] = ords;
1206
                resp = new STRUCT(dsc, _conn, obj);
1207

    
1208
                return resp;
1209
        }
1210

    
1211
        /**
1212
         * 
1213
         * @param lines
1214
         * @param srid
1215
         * @param threed
1216
         * @param _conn
1217
         * @param hasSrid
1218
         * @return
1219
         * @throws SQLException
1220
         */
1221
        private static STRUCT getMultiLineAsStruct(List lines, int srid,
1222
                        boolean threed, Connection _conn, boolean hasSrid)
1223
                        throws SQLException {
1224
                /*
1225
                 * if (lines.size() == 1) { return
1226
                 * getOneLineStringAsStruct((LineString3D) lines.get(0), srid, threed,
1227
                 * _conn); }
1228
                 */
1229
                int size = lines.size();
1230
                int geotype = 2006;
1231
                int dim = 2;
1232
                int acum = 0;
1233

    
1234
                if (threed) {
1235
                        geotype = 3006;
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
1246
                                        + (dim * ((LineString3D) lines.get(i)).getLs()
1247
                                                        .getNumPoints());
1248
                }
1249

    
1250
                int _ind = 0;
1251
                NUMBER[] ords = new NUMBER[acum];
1252

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

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

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

    
1265
                                _ind = _ind + dim;
1266
                        }
1267
                }
1268

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

    
1275
                if (hasSrid) {
1276
                        obj[1] = new NUMBER(srid);
1277
                } else {
1278
                        obj[1] = null;
1279
                }
1280

    
1281
                obj[2] = null;
1282
                obj[3] = indices;
1283
                obj[4] = ords;
1284
                resp = new STRUCT(dsc, _conn, obj);
1285

    
1286
                return resp;
1287
        }
1288

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

    
1305
                if (threed) {
1306
                        geotype = 3001;
1307
                        dim = 3;
1308
                }
1309

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

    
1315
                StructDescriptor ord_dsc = StructDescriptor.createDescriptor(
1316
                                "MDSYS.SDO_POINT_TYPE", _conn);
1317
                STRUCT ords_st = new STRUCT(ord_dsc, _conn, ords);
1318

    
1319
                STRUCT resp;
1320

    
1321
                StructDescriptor dsc = StructDescriptor.createDescriptor(
1322
                                "MDSYS.SDO_GEOMETRY", _conn);
1323
                Object[] obj = new Object[5];
1324

    
1325
                obj[0] = new NUMBER(geotype);
1326

    
1327
                if (hasSrid) {
1328
                        obj[1] = new NUMBER(srid);
1329
                } else {
1330
                        obj[1] = null;
1331
                }
1332

    
1333
                obj[2] = ords_st;
1334
                obj[3] = null;
1335
                obj[4] = null;
1336
                resp = new STRUCT(dsc, _conn, obj);
1337

    
1338
                return resp;
1339
        }
1340

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

    
1355
                double m11;
1356
                double m12;
1357
                double m13;
1358
                double m14;
1359

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

    
1364
                        // not a circle
1365
                        return resp;
1366
                }
1367

    
1368
                double[][] a = new double[3][3];
1369

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

    
1376
                m11 = determinant(a, 3);
1377

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

    
1385
                m12 = determinant(a, 3);
1386

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

    
1395
                m13 = determinant(a, 3);
1396

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

    
1404
                m14 = determinant(a, 3);
1405

    
1406
                Double resp_radius = new Double(0);
1407
                Point2D resp_center = new Point2D.Double(0, 0);
1408

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

    
1422
                return resp;
1423
        }
1424

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

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

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

    
1445
                                for (int i = 1; i < n; i++) { // create minor
1446

    
1447
                                        int j2 = 0;
1448

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

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

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

    
1465
                return resp;
1466
        }
1467

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

    
1480
                int size = list.size();
1481

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

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

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

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

    
1518
                return resp;
1519
        }
1520

    
1521
        /**
1522
         * 
1523
         * @param containings
1524
         * @return
1525
         */
1526
        private static int[] getIndicesOfShells(int[] containings) {
1527
                List resp = new ArrayList();
1528

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

    
1535
                int size = resp.size();
1536
                int[] _resp = new int[size];
1537

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

    
1542
                return _resp;
1543
        }
1544

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

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

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

    
1562
                int size = resp.size();
1563
                int[] _resp = new int[size];
1564

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

    
1569
                return _resp;
1570
        }
1571

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

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

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

    
1591
                int size = resp.size();
1592
                int[] _resp = new int[size];
1593

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

    
1598
                return _resp;
1599
        }
1600

    
1601
        /**
1602
         * 
1603
         * @param ind
1604
         * @param final_contn
1605
         * @param all
1606
         * @return
1607
         */
1608
        private static List getHolesOf(int ind, int[] final_contn,
1609
                        List all) {
1610
                List resp_ind = new ArrayList();
1611

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

    
1618
                List resp = new ArrayList();
1619

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

    
1625
                return resp;
1626
        }
1627

    
1628
        /**
1629
         * 
1630
         * @param final_contn
1631
         * @param all
1632
         * @return
1633
         */
1634
        private static List getShellsIn(int[] final_contn, List all) {
1635
                List resp_ind = new ArrayList();
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 resp = new ArrayList();
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 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 = (LineString3D) 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 resp_shells = new ArrayList();
1685
                List resp_holes_for_shells = new ArrayList();
1686
                List 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 srid,
1728
                        boolean threed, Connection _conn, boolean agu_bien, boolean hasSrid)
1729
                        throws SQLException {
1730
                List 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
                return getMultiPolygonAsStruct(sh, ho, srid, threed, _conn, agu_bien,
1737
                                hasSrid);
1738
        }
1739

    
1740
        /**
1741
         * 
1742
         * @param hh
1743
         * @return
1744
         */
1745
        private static List reverseHoles(List hh) {
1746
                List resp = new ArrayList();
1747

    
1748
                for (int i = 0; i < hh.size(); i++) {
1749
                        List item = (ArrayList) hh.get(i);
1750
                        List newitem = new ArrayList();
1751

    
1752
                        for (int j = 0; j < item.size(); j++) {
1753
                                LineString3D ls = (LineString3D) item.get(j);
1754
                                newitem.add(ls.createReverse());
1755
                        }
1756

    
1757
                        resp.add(newitem);
1758
                }
1759

    
1760
                return resp;
1761
        }
1762

    
1763
        /**
1764
         * 
1765
         * @param shells
1766
         * @param holes
1767
         * @param srid
1768
         * @param threed
1769
         * @param _conn
1770
         * @param explicito
1771
         * @param hasSrid
1772
         * @return
1773
         * @throws SQLException
1774
         */
1775
        private static STRUCT getMultiPolygonAsStruct(List shells,
1776
                        List holes, int srid, boolean threed, Connection _conn,
1777
                        boolean explicito, boolean hasSrid) throws SQLException {
1778
                int t = 1003;
1779

    
1780
                if (explicito) {
1781
                        t = 2003;
1782
                }
1783

    
1784
                int size = shells.size() + getTotalSize(holes);
1785
                int geotype = 2003;
1786
                if (size > 1)
1787
                        geotype = 2007;
1788

    
1789
                int dim = 2;
1790

    
1791
                if (threed) {
1792
                        geotype = geotype + 1000;
1793
                        dim = 3;
1794
                }
1795

    
1796
                NUMBER[] indices = new NUMBER[3 * size];
1797

    
1798
                int acum = 0;
1799
                int start_ind = 0;
1800

    
1801
                for (int i = 0; i < shells.size(); i++) {
1802
                        indices[start_ind] = new NUMBER(acum + 1);
1803
                        indices[start_ind + 1] = new NUMBER(1003);
1804
                        indices[start_ind + 2] = new NUMBER(1);
1805
                        start_ind = start_ind + 3;
1806
                        acum = acum
1807
                                        + (dim * ((LineString3D) shells.get(i)).getLs()
1808
                                                        .getNumPoints());
1809

    
1810
                        List item_holes = (List) holes.get(i);
1811

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

    
1823
                int _ind = 0;
1824
                NUMBER[] ords = new NUMBER[acum];
1825

    
1826
                for (int i = 0; i < shells.size(); i++) {
1827
                        // --------------------------------
1828
                        LineString3D ls = (LineString3D) shells.get(i);
1829
                        int num_p = ls.getLs().getNumPoints();
1830

    
1831
                        for (int j = 0; j < num_p; j++) {
1832
                                ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(j).x);
1833
                                ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(j).y);
1834

    
1835
                                if (threed) {
1836
                                        ords[_ind + 2] = new NUMBER(ls.getZc()[j]);
1837
                                }
1838

    
1839
                                _ind = _ind + dim;
1840
                        }
1841

    
1842
                        // -------------------------------
1843
                        List item_holes = (ArrayList) holes.get(i);
1844

    
1845
                        for (int j = 0; j < item_holes.size(); j++) {
1846
                                ls = (LineString3D) item_holes.get(j);
1847
                                num_p = ls.getLs().getNumPoints();
1848

    
1849
                                for (int k = 0; k < num_p; k++) {
1850
                                        ords[_ind] = new NUMBER(ls.getLs().getCoordinateN(k).x);
1851
                                        ords[_ind + 1] = new NUMBER(ls.getLs().getCoordinateN(k).y);
1852

    
1853
                                        if (threed) {
1854
                                                ords[_ind + 2] = new NUMBER(ls.getZc()[k]);
1855
                                        }
1856

    
1857
                                        _ind = _ind + dim;
1858
                                }
1859
                        }
1860
                }
1861

    
1862
                STRUCT resp;
1863
                StructDescriptor dsc = StructDescriptor.createDescriptor(
1864
                                "MDSYS.SDO_GEOMETRY", _conn);
1865
                Object[] obj = new Object[5];
1866
                obj[0] = new NUMBER(geotype);
1867

    
1868
                if (hasSrid) {
1869
                        obj[1] = new NUMBER(srid);
1870
                } else {
1871
                        obj[1] = null;
1872
                }
1873

    
1874
                obj[2] = null;
1875
                obj[3] = indices;
1876
                obj[4] = ords;
1877

    
1878
                // String ind_str = printArray(indices);
1879
                // String ord_str = printArray(ords);
1880
                resp = new STRUCT(dsc, _conn, obj);
1881

    
1882
                return resp;
1883
        }
1884

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

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

    
1897
                resp = resp.substring(0, resp.length() - 2) + "]";
1898

    
1899
                return resp;
1900
        }
1901

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

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

    
1944
                for (int i = 0; i < size; i++) {
1945
                        sts[i] = OracleSpatialDriver.iGeometryToSTRUCT(geoms[i],
1946
                                        _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
1947
                }
1948

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

    
1953
                STRUCT aux = sts[0];
1954

    
1955
                for (int i = 1; i < size; i++) {
1956
                        aux = appendStructs(aux, sts[i], _conn);
1957
                }
1958

    
1959
                return aux;
1960
        }
1961

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

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

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

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

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

    
1990
                        StructDescriptor dsc = st1.getDescriptor();
1991

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

    
1999
                        STRUCT resp = new STRUCT(dsc, _conn, atts);
2000

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

    
2006
                return null;
2007
        }
2008

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

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

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

    
2043
                return resp;
2044
        }
2045

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

    
2059
                return df.format(n);
2060
        }
2061

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

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

    
2080
                return false;
2081
        }
2082

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

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

    
2101
                return _resp;
2102
        }
2103

    
2104
        /**
2105
         * Utility method to deal with oracle coordinate arrays.
2106
         */
2107
        public static ARRAY getDevelopedOrdsArray(ARRAY ords) {
2108
                ARRAY _resp = null;
2109

    
2110
                try {
2111
                        Datum[] resp = new Datum[10];
2112
                        Datum[] corners = ords.getOracleArray();
2113

    
2114
                        // x
2115
                        resp[0] = corners[0];
2116
                        resp[2] = corners[2];
2117
                        resp[4] = corners[2];
2118
                        resp[6] = corners[0];
2119
                        resp[8] = corners[0];
2120

    
2121
                        // y
2122
                        resp[1] = corners[1];
2123
                        resp[3] = corners[1];
2124
                        resp[5] = corners[3];
2125
                        resp[7] = corners[3];
2126
                        resp[9] = corners[1];
2127
                        _resp = new ARRAY(ords.getDescriptor(), ords
2128
                                        .getInternalConnection(), resp);
2129
                } catch (SQLException se) {
2130
                        logger.error("While creating ARRAY: " + se.getMessage(), se);
2131
                }
2132

    
2133
                return _resp;
2134
        }
2135

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

    
2155
                try {
2156
                        infoARRAY = (ARRAY) aux[3];
2157
                        ordsARRAY = (ARRAY) aux[4];
2158

    
2159
                        if (polStructIsRectStruct(infoARRAY, ordsARRAY)) {
2160
                                infoARRAY = getDevelopedInfoArray(infoARRAY);
2161
                                ordsARRAY = getDevelopedOrdsArray(ordsARRAY);
2162
                        }
2163

    
2164
                        dims = ((NUMBER) aux[0]).intValue() / 1000;
2165

    
2166
                        if (dims == 0) {
2167
                                dims = 2;
2168
                        }
2169

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

    
2174
                        int last_index = ords_array.length - dims + 1;
2175

    
2176
                        // set indices:
2177
                        start_ind = new int[info_array_size];
2178
                        end_ind = new int[info_array_size];
2179

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

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

    
2186
                        end_ind[info_array_size - 1] = last_index;
2187

    
2188
                        int lineType = PathIterator.SEG_LINETO;
2189

    
2190
                        if (end_ind[0] == 0) { // collection of paths
2191

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

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

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

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

    
2219
                return resp;
2220
        }
2221

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

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

    
2240
                return resp;
2241
        }
2242

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

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

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

    
2272
                int ind = 1;
2273

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

    
2278
                if (ltype == PathIterator.SEG_QUADTO) { // (interpretation = 2)
2279

    
2280
                        double x2;
2281
                        double y2;
2282

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

    
2288
                                indx2 = zero_based_start + ((ind + 1) * d);
2289

    
2290
                                if (indx >= length) {
2291
                                        indx2 = zero_based_start;
2292
                                }
2293

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

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

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

    
2313
                return return_following_must_do_first;
2314
        }
2315

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

    
2327
                case OracleValues.ORACLE_GTYPE_POINT:
2328
                case OracleValues.ORACLE_GTYPE_MULTIPOINT:
2329
                        return Geometry.TYPES.POINT;
2330

    
2331
                case OracleValues.ORACLE_GTYPE_LINE:
2332
                case OracleValues.ORACLE_GTYPE_MULTILINE:
2333
                        return Geometry.TYPES.CURVE;
2334

    
2335
                case OracleValues.ORACLE_GTYPE_POLYGON:
2336
                case OracleValues.ORACLE_GTYPE_MULTIPOLYGON:
2337
                        return Geometry.TYPES.SURFACE;
2338

    
2339
                case OracleValues.ORACLE_GTYPE_COLLECTION:
2340
                        return Geometry.TYPES.AGGREGATE;
2341
                }
2342

    
2343
                logger.warn("Unknown oracle geometry type: " + otype);
2344

    
2345
                return Geometry.TYPES.NULL;
2346
        }
2347

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

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

    
2364
                return resp;
2365
        }
2366

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

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

    
2383
                return resp;
2384
        }
2385

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

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

    
2401
                        return false;
2402
                }
2403

    
2404
                if (info == null) {
2405
                        return false;
2406
                }
2407

    
2408
                boolean resp = ((info.length == 3) && (info[2] == 4));
2409

    
2410
                return resp;
2411
        }
2412

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

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

    
2429
                if (resp < 2) {
2430
                        resp = 2;
2431
                }
2432

    
2433
                return resp;
2434
        }
2435

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

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

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

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

    
2458
                return resp;
2459
        }
2460

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

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

    
2493
                return null;
2494
        }
2495

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

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

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

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

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

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

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

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

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

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

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

    
2598
        }
2599

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

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

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

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

    
2639
                int resp = Geometry.TYPES.NULL;
2640

    
2641
                if (complex) {
2642

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

    
2653
                } else {
2654

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

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

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

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

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

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

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

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

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

    
2715
                HashMap m = new HashMap();
2716

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

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

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

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

    
2731
                return iter.hasNext();
2732
        }
2733

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

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

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

    
2758
                return resp;
2759
        }
2760

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

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

    
2777
                return resp;
2778
        }
2779

    
2780
        /**
2781
         * 
2782
         * @param the_data
2783
         * @param dim
2784
         * @return
2785
         * @throws CreateGeometryException
2786
         */
2787
        public static Geometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) throws CreateGeometryException {
2788
                
2789
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2790
                
2791
                Geometry geom = null;
2792

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

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

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

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

    
2818
                return geom;
2819
        }
2820

    
2821
        /**
2822
         * 
2823
         * @param the_data
2824
         * @return
2825
         * @throws CreateGeometryException
2826
         */
2827
        private static Geometry getCircleFromStruct(Datum[] the_data) throws CreateGeometryException {
2828
                
2829
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2830
                
2831
                double[] threep = null;
2832

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

    
2839
                        return geomManager.createNullGeometry(Geometry.SUBTYPES.GEOM2D);
2840
                }
2841

    
2842
                Point2D[] three = new Point2D.Double[3];
2843
                three[0] = new Point2D.Double(threep[0], threep[1]);
2844
                three[1] = new Point2D.Double(threep[2], threep[3]);
2845
                three[2] = new Point2D.Double(threep[4], threep[5]);
2846

    
2847
                Object[] cent_rad = OracleUtils.getCenterAndRadiousOfCirc(three);
2848

    
2849
                Point2D cent = (Point2D) cent_rad[0];
2850
                double radious = ((Double) cent_rad[1]).doubleValue();
2851

    
2852
                Geometry circ = geomManager.create(Geometry.TYPES.CIRCLE, Geometry.SUBTYPES.GEOM2D);
2853
                ((Circle2D)circ).setPoints(cent, radious);
2854
                
2855
                return circ;
2856
        }
2857

    
2858
        /**
2859
         * 
2860
         * @param the_data
2861
         * @param dim
2862
         * @return
2863
         * @throws CreateGeometryException 
2864
         */
2865
        public static Geometry getFMapGeometryMultiLineString(Datum[] the_data,
2866
                        int dim) throws CreateGeometryException {
2867

    
2868
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2869
                
2870
                GeneralPathX gpx = OracleUtils.structToGPX(the_data);
2871
                Geometry geom = null;
2872
                double[] ords = null;
2873

    
2874
                if (dim == 2) {
2875
                        geom = geomManager.createCurve(gpx, Geometry.SUBTYPES.GEOM2D);
2876
                } else {
2877
                        ords = OracleUtils.getOrds(the_data);
2878

    
2879
                        double[] z = getIndBigDecimalModule(ords, 2, dim);
2880
                        geom = geomManager.createCurve(gpx, Geometry.SUBTYPES.GEOM2DZ);
2881
                        for (int i = 0; i < z.length; i++) {
2882
                                ((Curve2DZ)geom).setCoordinateAt(i, 3, z[i]);
2883
                        }                        
2884
                }
2885

    
2886
                return geom;
2887
        }
2888

    
2889
        /**
2890
         * 
2891
         * @param the_data
2892
         * @param dim
2893
         * @return
2894
         * @throws CreateGeometryException 
2895
         */
2896
        public static Geometry getFMapGeometryPoint(Datum[] the_data, int dim) throws CreateGeometryException {
2897

    
2898
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2899

    
2900
                double[] ords = OracleUtils.getOrds(the_data);
2901

    
2902
                if (ords == null) { // sdo_point
2903

    
2904
                        return getFMapGeometrySdoPoint(the_data, dim);
2905
                }
2906

    
2907
                Geometry geom = null;
2908
                int total_size = ords.length;
2909
                int no_po = total_size / dim;
2910
                double[] x = new double[no_po];
2911
                double[] y = new double[no_po];
2912
                double[] z = new double[no_po];
2913

    
2914
                for (int i = 0; i < no_po; i++) {
2915
                        x[i] = ords[i * dim]; // pp[i].getX();
2916
                        y[i] = ords[(i * dim) + 1];
2917

    
2918
                        if (dim >= 3) {
2919
                                z[i] = ords[(i * dim) + 2];
2920
                        }
2921
                }
2922

    
2923
                if (dim == 2) {
2924
                        if (no_po == 1) {
2925
                                geom = geomManager.createPoint(x[0], y[0],
2926
                                                Geometry.SUBTYPES.GEOM2D);
2927
                        } else {
2928
                                geom = geomManager.create(Geometry.TYPES.MULTIPOINT,
2929
                                                Geometry.SUBTYPES.GEOM2D);
2930

    
2931
                                ((MultiPoint2D) geom).setPoints(x, y);
2932
                        }
2933
                } else {
2934
                        if (no_po == 1) {                                
2935
                                geom = geomManager.createPoint(x[0], y[0],
2936
                                                Geometry.SUBTYPES.GEOM2DZ);
2937
                                ((Point2DZ)geom).setCoordinateAt(3, z[0]);
2938
                        } else {                                
2939
                                geom = geomManager.create(Geometry.TYPES.MULTIPOINT,
2940
                                                Geometry.SUBTYPES.GEOM2DZ);
2941
                                ((MultiPoint2DZ) geom).setPoints(x, y);
2942
                                Point2DZ pto = null;
2943
                                for (int i = 0; i < x.length; i++) {
2944
                                        pto = (Point2DZ)geomManager.create(Geometry.TYPES.POINT,
2945
                                                        Geometry.SUBTYPES.GEOM2DZ);
2946
                                        pto.setX(x[i]);
2947
                                        pto.setY(y[i]);
2948
                                        pto.setCoordinateAt(3, z[i]);
2949
                                        ((MultiPoint2DZ) geom).addPoint(pto);
2950
                                }
2951
                        }
2952
                }
2953

    
2954
                return geom;
2955
        }
2956

    
2957
        /**
2958
         * 
2959
         * @param the_data
2960
         * @param d
2961
         * @return
2962
         * @throws CreateGeometryException
2963
         */
2964
        public static Geometry getFMapGeometrySdoPoint(Datum[] the_data, int d)
2965
                        throws CreateGeometryException {
2966

    
2967
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
2968

    
2969
                double x = 0;
2970
                double y = 0;
2971
                double z = 0;
2972

    
2973
                try {
2974
                        Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
2975
                        x = ((NUMBER) aux[0]).doubleValue();
2976
                        y = ((NUMBER) aux[1]).doubleValue();
2977

    
2978
                        if (d > 2) {
2979
                                z = ((NUMBER) aux[2]).doubleValue();
2980
                        }
2981
                } catch (SQLException se) {
2982
                        logger.error("While getting sdo point ordinates: "
2983
                                        + se.getMessage(), se);
2984
                }
2985

    
2986
                Geometry geom = null;
2987

    
2988
                if (d == 2) {
2989
                        geom = geomManager.createPoint(x, y, Geometry.SUBTYPES.GEOM2D);
2990
                } else {
2991

    
2992
                        Point2DZ point = (Point2DZ) geomManager.create(
2993
                                        Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DZ);
2994
                        point.setX(x);
2995
                        point.setY(y);
2996
                        point.setCoordinateAt(3, z);
2997
                        geom = point;
2998
                }
2999

    
3000
                return geom;
3001
        }
3002

    
3003
        /**
3004
         * 
3005
         * @param the_data
3006
         * @return
3007
         */
3008
        public static boolean isActuallyACollection(Datum[] the_data) {
3009
                int[] info = null;
3010

    
3011
                try {
3012
                        ARRAY aux = (ARRAY) the_data[3];
3013

    
3014
                        if (aux == null) {
3015
                                return false;
3016
                        }
3017

    
3018
                        info = aux.getIntArray();
3019
                } catch (SQLException se) {
3020
                        logger.error("While checking collection: " + se.getMessage());
3021
                        return false;
3022
                }
3023

    
3024
                if (info == null) {
3025
                        return false; // sdo_point
3026
                }
3027

    
3028
                int size = info.length / 3;
3029

    
3030
                if (size == 1) {
3031
                        return false;
3032
                }
3033

    
3034
                if (size == 2) {
3035
                        return ((info[1] % 1000) != (info[4] % 1000))
3036
                                        && (!((info[1] == 1005) && (info[4] == 2)));
3037
                }
3038

    
3039
                int second = info[4] % 1000;
3040
                int item = 0;
3041

    
3042
                for (int i = 2; i < size; i++) {
3043
                        item = info[(i * 3) + 1] % 1000;
3044
                        if ((item != second) && (!((item == 5) && (second == 2)))) {
3045
                                return true;
3046
                        }
3047
                }
3048

    
3049
                return false;
3050
        }
3051

    
3052
        /**
3053
         * 
3054
         * @param info
3055
         * @return
3056
         */
3057
        public static Datum[] updateIndexes(Datum[] info) {
3058
                int size = info.length / 3;
3059
                NUMBER[] resp = new NUMBER[3 * size];
3060

    
3061
                try {
3062
                        int rest = info[0].intValue() - 1;
3063

    
3064
                        for (int i = 0; i < size; i++) {
3065
                                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
3066
                                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
3067
                                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
3068
                        }
3069
                } catch (SQLException se) {
3070
                        logger.error("Unexpected error: " + se.getMessage());
3071
                }
3072

    
3073
                return resp;
3074
        }
3075

    
3076
        /**
3077
         * 
3078
         * @param all
3079
         * @param first_inc
3080
         * @param last_inc
3081
         * @return
3082
         */
3083
        public static double[] getSubSet(double[] all, int first_inc, int last_inc) {
3084
                double[] resp = new double[last_inc - first_inc + 1];
3085

    
3086
                for (int i = first_inc; i <= last_inc; i++) {
3087
                        resp[i - first_inc] = all[i];
3088
                }
3089

    
3090
                return resp;
3091
        }
3092

    
3093
        /**
3094
         * 
3095
         * @param all
3096
         * @param groups
3097
         * @return
3098
         * @throws SQLException
3099
         */
3100
        public static Object[] getOrdOfGroups(Datum[] all, Object[] groups)
3101
                        throws SQLException {
3102
                Object[] resp = new Object[groups.length];
3103

    
3104
                if (resp.length == 1) {
3105
                        resp[0] = all;
3106

    
3107
                        return resp;
3108
                }
3109

    
3110
                int ind = 0;
3111
                Datum[] aux = (Datum[]) groups[1];
3112
                int _end = aux[0].intValue() - 2;
3113
                Datum[] ord_aux = getSubSet(all, 0, _end);
3114

    
3115
                int _start = _end + 1;
3116
                resp[ind] = ord_aux;
3117
                ind++;
3118

    
3119
                for (int i = 2; i < groups.length; i++) {
3120
                        aux = (Datum[]) groups[i];
3121
                        _end = aux[0].intValue() - 2;
3122
                        ord_aux = getSubSet(all, _start, _end);
3123
                        resp[ind] = ord_aux;
3124
                        ind++;
3125
                        _start = _end + 1;
3126
                }
3127

    
3128
                // last
3129
                _end = all.length - 1;
3130
                ord_aux = getSubSet(all, _start, _end);
3131
                resp[groups.length - 1] = ord_aux;
3132

    
3133
                return resp;
3134
        }
3135

    
3136
        /**
3137
         * 
3138
         * @param all
3139
         * @param groups
3140
         * @return
3141
         */
3142
        public static Object[] getOrdOfGroups(double[] all, Object[] groups) {
3143
                Object[] resp = new Object[groups.length];
3144

    
3145
                if (resp.length == 1) {
3146
                        resp[0] = all;
3147

    
3148
                        return resp;
3149
                }
3150

    
3151
                int ind = 0;
3152
                int[] aux = (int[]) groups[1];
3153
                int _end = aux[0] - 2;
3154
                double[] ord_aux = getSubSet(all, 0, _end);
3155

    
3156
                int _start = _end + 1;
3157
                resp[ind] = ord_aux;
3158
                ind++;
3159

    
3160
                for (int i = 2; i < groups.length; i++) {
3161
                        aux = (int[]) groups[i];
3162
                        _end = aux[0] - 2;
3163
                        ord_aux = getSubSet(all, _start, _end);
3164
                        resp[ind] = ord_aux;
3165
                        ind++;
3166
                        _start = _end + 1;
3167
                }
3168

    
3169
                // last
3170
                _end = all.length - 1;
3171
                ord_aux = getSubSet(all, _start, _end);
3172
                resp[groups.length - 1] = ord_aux;
3173

    
3174
                return resp;
3175
        }
3176

    
3177
        /**
3178
         * 
3179
         * @param all_elem
3180
         * @return
3181
         */
3182
        public static Object[] groupByElement(int[] all_elem) {
3183
                ArrayList resp = new ArrayList();
3184

    
3185
                int size = all_elem.length / 3;
3186

    
3187
                int[] aux = getNthGroupOfThree(all_elem, 0);
3188

    
3189
                int[] newaux;
3190
                int i = 1;
3191

    
3192
                while (i < size) {
3193
                        newaux = getNthGroupOfThree(all_elem, i);
3194

    
3195
                        if (newaux[0] == aux[0]) {
3196
                                // aux[2] says how many components
3197
                                for (int j = 0; j < aux[2]; j++) {
3198
                                        aux = appendIntArrays(aux, getNthGroupOfThree(all_elem, j
3199
                                                        + i));
3200
                                }
3201

    
3202
                                resp.add(aux);
3203
                                i = i + aux[2];
3204
                                aux = getNthGroupOfThree(all_elem, i);
3205
                        } else {
3206
                                if (newaux[1] == 2003) {
3207
                                        aux = appendIntArrays(aux, newaux);
3208
                                } else {
3209
                                        resp.add(aux);
3210
                                        aux = getNthGroupOfThree(all_elem, i);
3211
                                }
3212
                        }
3213

    
3214
                        i++;
3215
                }
3216

    
3217
                resp.add(aux);
3218

    
3219
                return resp.toArray();
3220
        }
3221

    
3222
        /**
3223
         * 
3224
         * @param all_elem
3225
         * @return
3226
         */
3227
        public static boolean isSimpleCollectionOfLines(Datum[] all_elem) {
3228

    
3229
                try {
3230
                        int size = all_elem.length;
3231
                        if (all_elem[1].intValue() != 4)
3232
                                return false;
3233
                        int size3 = size / 3;
3234

    
3235
                        for (int i = 1; i < size3; i++) {
3236
                                if (all_elem[3 * i + 1].intValue() != 2)
3237
                                        return false;
3238
                        }
3239
                        return true;
3240

    
3241
                } catch (SQLException ex) {
3242
                        logger.error("While is simple line collection: " + ex.getMessage());
3243
                }
3244

    
3245
                return false;
3246
        }
3247

    
3248
        /**
3249
         * 
3250
         * @param elem
3251
         * @return
3252
         */
3253
        public static Datum[] removeThreeFirst(Datum[] elem) {
3254
                int sz = elem.length;
3255
                Datum[] resp = new Datum[sz - 3];
3256
                for (int i = 3; i < sz; i++)
3257
                        resp[i - 3] = elem[i];
3258
                return resp;
3259
        }
3260

    
3261
        /**
3262
         * 
3263
         * @param all_elem
3264
         * @return
3265
         */
3266
        public static Object[] groupByElement(Datum[] all_elem) {
3267

    
3268
                if (isSimpleCollectionOfLines(all_elem)) {
3269
                        Object[] r = new Object[1];
3270
                        r[0] = removeThreeFirst(all_elem);
3271
                        return r;
3272
                }
3273

    
3274
                ArrayList resp = new ArrayList();
3275

    
3276
                int size = all_elem.length / 3;
3277

    
3278
                Datum[] aux = getNthGroupOfThree(all_elem, 0);
3279

    
3280
                Datum[] newaux;
3281
                int i = 1;
3282
                boolean add_last_time = true;
3283

    
3284
                try {
3285
                        while (i < size) {
3286
                                newaux = getNthGroupOfThree(all_elem, i);
3287

    
3288
                                if (newaux[0].intValue() == aux[0].intValue()) {
3289
                                        // aux[2] says how many components
3290
                                        for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
3291
                                                aux = appendDatArrays(aux, getNthGroupOfThree(all_elem,
3292
                                                                j + i));
3293
                                        }
3294

    
3295
                                        resp.add(aux);
3296
                                        i = i + ((NUMBER) aux[2]).intValue();
3297
                                        if (i < size) { // in some cases (line collection, 4)
3298
                                                aux = getNthGroupOfThree(all_elem, i);
3299
                                        } else {
3300
                                                add_last_time = false;
3301
                                        }
3302
                                } else {
3303
                                        if (((NUMBER) newaux[1]).intValue() == 2003) {
3304
                                                aux = appendDatArrays(aux, newaux);
3305
                                        } else {
3306
                                                resp.add(aux);
3307
                                                aux = getNthGroupOfThree(all_elem, i);
3308
                                        }
3309
                                }
3310

    
3311
                                i++;
3312
                        }
3313
                } catch (SQLException se) {
3314
                        logger.error("Unexpected error: " + se.getMessage());
3315
                }
3316

    
3317
                if (add_last_time) {
3318
                        resp.add(aux);
3319
                }
3320

    
3321
                return resp.toArray();
3322
        }
3323

    
3324
        /**
3325
         * 
3326
         * @param r
3327
         * @param hasSrid
3328
         * @param isView
3329
         * @param _isGeogCS
3330
         * @param _oracleSRID
3331
         * @param __conn
3332
         * @return
3333
         */
3334
        public static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
3335
                        boolean isView, boolean _isGeogCS, String _oracleSRID,
3336
                        Connection __conn) {
3337
                Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
3338
                Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
3339

    
3340
                if ((_isGeogCS) && (isView)) {
3341
                        c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
3342
                        c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
3343
                }
3344

    
3345
                STRUCT resp = null;
3346

    
3347
                try {
3348

    
3349
                        int size = 5;
3350
                        Object[] new_obj = new Object[size];
3351

    
3352
                        new_obj[0] = new NUMBER(2003);
3353

    
3354
                        if (hasSrid) {
3355
                                new_obj[1] = new NUMBER(_oracleSRID);
3356
                        } else {
3357
                                new_obj[1] = null;
3358
                        }
3359

    
3360
                        new_obj[2] = null;
3361

    
3362
                        NUMBER[] elem_info = new NUMBER[3];
3363
                        elem_info[0] = new NUMBER(1);
3364
                        elem_info[1] = new NUMBER(1003);
3365
                        elem_info[2] = new NUMBER(3);
3366
                        new_obj[3] = elem_info;
3367

    
3368
                        NUMBER[] ords = null;
3369
                        ords = new NUMBER[4];
3370
                        ords[0] = new NUMBER(c1.getX());
3371
                        ords[1] = new NUMBER(c1.getY());
3372
                        ords[2] = new NUMBER(c2.getX());
3373
                        ords[3] = new NUMBER(c2.getY());
3374
                        new_obj[4] = ords;
3375

    
3376
                        StructDescriptor dsc = StructDescriptor.createDescriptor(
3377
                                        "MDSYS.SDO_GEOMETRY", __conn);
3378

    
3379
                        resp = new STRUCT(dsc, __conn, new_obj);
3380
                } catch (Exception ex) {
3381
                        logger.error(
3382
                                        "Error while creating rect struct: " + ex.getMessage(), ex);
3383
                }
3384

    
3385
                return resp;
3386
        }
3387

    
3388
        /**
3389
         * 
3390
         * @param r1
3391
         * @param r2
3392
         * @return
3393
         */
3394
        public static Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
3395
                if (r1.getMaxX() <= r2.getMinX()) {
3396
                        return null;
3397
                }
3398

    
3399
                if (r2.getMaxX() <= r1.getMinX()) {
3400
                        return null;
3401
                }
3402

    
3403
                if (r1.getMaxY() <= r2.getMinY()) {
3404
                        return null;
3405
                }
3406

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

    
3411
                double minx = Math.max(r1.getMinX(), r2.getMinX());
3412
                double miny = Math.max(r1.getMinY(), r2.getMinY());
3413
                double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
3414
                double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
3415

    
3416
                double w = maxx - minx;
3417
                double h = maxy - miny;
3418

    
3419
                return new Rectangle2D.Double(minx, miny, w, h);
3420
        }
3421

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

    
3434
                if (!thas)
3435
                        return false;
3436
                if (oracleSRID2 == null)
3437
                        return false;
3438

    
3439
                int ora_cs = 0;
3440

    
3441
                try {
3442
                        ora_cs = Integer.parseInt(oracleSRID2);
3443
                } catch (Exception ex) {
3444
                        return false;
3445
                }
3446

    
3447
                if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
3448
                        return true;
3449
                } else {
3450
                        return false;
3451
                }
3452
        }
3453

    
3454
        /**
3455
         * 
3456
         * @param sample
3457
         * @return
3458
         * @throws SQLException
3459
         */
3460
        public static int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
3461

    
3462
                int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue();
3463

    
3464
                int type_part = code % 10;
3465
                int dim_part = code / 1000;
3466

    
3467
                int z_added = 0;
3468
                if (dim_part == 3) {
3469
                        z_added = Geometry.SUBTYPES.GEOM3D;
3470
                } else {
3471
                        if (dim_part == 4) {
3472
                                z_added = Geometry.SUBTYPES.GEOM3DM;
3473
                        }
3474
                }
3475

    
3476
                switch (type_part) {
3477
                case 1:
3478
                        return z_added + Geometry.TYPES.POINT;
3479

    
3480
                case 2:
3481
                        return z_added + Geometry.TYPES.CURVE;
3482

    
3483
                case 3:
3484
                        return z_added + Geometry.TYPES.SURFACE;
3485

    
3486
                case 4:
3487
                        return z_added + Geometry.TYPES.AGGREGATE;
3488

    
3489
                case 5:
3490
                        return z_added + Geometry.TYPES.MULTIPOINT;
3491

    
3492
                case 6:
3493
                        return z_added + Geometry.TYPES.MULTICURVE;
3494

    
3495
                case 7:
3496
                        return z_added + Geometry.TYPES.MULTISURFACE;
3497
                }
3498

    
3499
                logger.error("Unknown geometry type: " + code);
3500

    
3501
                return Geometry.TYPES.NULL;
3502
        }
3503

    
3504
        /**
3505
         * 
3506
         * @param info
3507
         * @return
3508
         */
3509
        public static int[] updateIndexes(int[] info) {
3510
                int size = info.length / 3;
3511
                int[] resp = new int[3 * size];
3512
                int rest = info[0] - 1;
3513

    
3514
                for (int i = 0; i < size; i++) {
3515
                        resp[3 * i] = info[3 * i] - rest;
3516
                        resp[(3 * i) + 1] = info[(3 * i) + 1];
3517
                        resp[(3 * i) + 2] = info[(3 * i) + 2];
3518
                }
3519

    
3520
                return resp;
3521
        }
3522

    
3523
        /**
3524
         * 
3525
         * @param head
3526
         * @param tail
3527
         * @return
3528
         */
3529
        public static int[] appendIntArrays(int[] head, int[] tail) {
3530
                int[] resp = new int[head.length + tail.length];
3531
                int hsize = head.length;
3532

    
3533
                for (int i = 0; i < hsize; i++) {
3534
                        resp[i] = head[i];
3535
                }
3536

    
3537
                for (int i = 0; i < tail.length; i++) {
3538
                        resp[hsize + i] = tail[i];
3539
                }
3540

    
3541
                return resp;
3542
        }
3543

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

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

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

    
3562
                return resp;
3563
        }
3564

    
3565
        /**
3566
         * 
3567
         * @param list
3568
         * @param n
3569
         * @return
3570
         */
3571
        public static int[] getNthGroupOfThree(int[] list, int n) {
3572
                int[] resp = new int[3];
3573
                resp[0] = list[3 * n];
3574
                resp[1] = list[(3 * n) + 1];
3575
                resp[2] = list[(3 * n) + 2];
3576

    
3577
                return resp;
3578
        }
3579

    
3580
        /**
3581
         * 
3582
         * @param list
3583
         * @param n
3584
         * @return
3585
         */
3586
        public static Datum[] getNthGroupOfThree(Datum[] list, int n) {
3587
                Datum[] resp = new Datum[3];
3588
                resp[0] = list[3 * n];
3589
                resp[1] = list[(3 * n) + 1];
3590
                resp[2] = list[(3 * n) + 2];
3591

    
3592
                return resp;
3593
        }
3594

    
3595
        /**
3596
         * 
3597
         * @param all
3598
         * @param first_inc
3599
         * @param last_inc
3600
         * @return
3601
         */
3602
        public static Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
3603
                Datum[] resp = new Datum[last_inc - first_inc + 1];
3604

    
3605
                for (int i = first_inc; i <= last_inc; i++) {
3606
                        resp[i - first_inc] = all[i];
3607
                }
3608

    
3609
                return resp;
3610
        }
3611

    
3612
        /**
3613
         * 
3614
         * @param _type
3615
         * @return
3616
         */
3617
        public static int maxSizeForFieldType(int _type) {
3618
                switch (_type) {
3619
                case Types.VARCHAR:
3620
                        return OracleValues.VARCHAR2_STANDARD_SIZE;
3621

    
3622
                case Types.LONGVARCHAR:
3623
                        return OracleValues.VARCHAR2_LONG_SIZE;
3624
                }
3625

    
3626
                return -1;
3627
        }
3628

    
3629
        /**
3630
         * 
3631
         * @param tname
3632
         * @param suffix
3633
         * @return
3634
         */
3635
        public static String getDerivedName(String tname, String suffix) {
3636
                int ind = tname.lastIndexOf(".");
3637
                if (ind == -1) {
3638
                        int l = Math.min(28, tname.length());
3639
                        return tname.substring(0, l) + "_" + suffix;
3640
                } else {
3641
                        String pre = tname.substring(0, ind);
3642
                        String post = tname.substring(ind + 1, tname.length());
3643
                        int lpost = Math.min(24, post.length());
3644
                        int lpre = Math.min(3, pre.length());
3645
                        return pre.substring(0, lpre) + "_" + post.substring(0, lpost)
3646
                                        + "_" + suffix;
3647
                }
3648
        }
3649

    
3650
}