001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/io/datastore/sql/oracle/JGeometryAdapter.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005     Department of Geography, University of Bonn
006     and
007     lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035     ----------------------------------------------------------------------------*/
036    
037    package org.deegree.io.datastore.sql.oracle;
038    
039    import java.util.ArrayList;
040    import java.util.List;
041    
042    import oracle.spatial.geometry.JGeometry;
043    
044    import org.deegree.model.crs.CoordinateSystem;
045    import org.deegree.model.spatialschema.Curve;
046    import org.deegree.model.spatialschema.Geometry;
047    import org.deegree.model.spatialschema.GeometryException;
048    import org.deegree.model.spatialschema.GeometryFactory;
049    import org.deegree.model.spatialschema.MultiCurve;
050    import org.deegree.model.spatialschema.MultiPoint;
051    import org.deegree.model.spatialschema.MultiSurface;
052    import org.deegree.model.spatialschema.Point;
053    import org.deegree.model.spatialschema.Position;
054    import org.deegree.model.spatialschema.Ring;
055    import org.deegree.model.spatialschema.Surface;
056    
057    /**
058     * Adapter between deegree <code>Geometry</code> objects and Oracle <code>JGeometry</code> objects.
059     * 
060     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </A>
061     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
062     * @author last edited by: $Author: mschneider $
063     * 
064     * @version $Revision: 21832 $, $Date: 2010-01-08 16:41:39 +0100 (Fr, 08 Jan 2010) $
065     */
066    public class JGeometryAdapter {
067    
068        private JGeometryAdapter() {
069            // avoid instantiation
070        }
071    
072        /**
073         * Converts a deegree <code>Geometry</code> instance to a corresponding Oracle <code>JGeometry</code> object.
074         * 
075         * @param geometry
076         *            deegree <code>Geometry</code> to be converted
077         * @param srid
078         *            coordinate system for created Oracle <code>JGeometry</code> objects
079         * @return corresponding Oracle <code>JGeometry</code>
080         * @throws GeometryException
081         */
082        public static JGeometry export( Geometry geometry, int srid )
083                                throws GeometryException {
084            JGeometry jGeometry = null;
085    
086            if ( geometry instanceof Point ) {
087                jGeometry = exportPoint( (Point) geometry, srid );
088            } else if ( geometry instanceof MultiPoint ) {
089                jGeometry = exportMultiPoint( (MultiPoint) geometry, srid );
090            } else if ( geometry instanceof Curve ) {
091                jGeometry = exportCurve( (Curve) geometry, srid );
092            } else if ( geometry instanceof MultiCurve ) {
093                jGeometry = exportMultiCurve( (MultiCurve) geometry, srid );
094            } else if ( geometry instanceof Surface ) {
095                jGeometry = exportSurface( (Surface) geometry, srid );
096            } else if ( geometry instanceof MultiSurface ) {
097                jGeometry = exportMultiSurface( (MultiSurface) geometry, srid );
098            } else {
099                throw new GeometryException( "Cannot export geometry of type '" + geometry.getClass()
100                                             + "' to Oracle JGeometry: Unsupported type." );
101            }
102            return jGeometry;
103        }
104    
105        /**
106         * Converts an Oracle <code>JGeometry</code> instance to a corresponding deegree <code>Geometry</code> object.
107         * 
108         * @param jGeometry
109         *            Oracle <code>JGeometry</code> to be converted
110         * @param crs
111         *            coordinate system of the created deegree <code>Geometry</code> object
112         * @return corresponding deegree <code>Geometry</code>
113         * @throws GeometryException
114         */
115        public static Geometry wrap( JGeometry jGeometry, CoordinateSystem crs )
116                                throws GeometryException {
117            Geometry geo = null;
118    
119            switch ( jGeometry.getType() ) {
120            case JGeometry.GTYPE_POINT:
121                geo = wrapPoint( jGeometry, crs );
122                break;
123            case JGeometry.GTYPE_CURVE:
124                geo = wrapCurve( jGeometry, crs );
125                break;
126            case JGeometry.GTYPE_POLYGON:
127                geo = wrapSurface( jGeometry, crs );
128                break;
129            case JGeometry.GTYPE_MULTIPOINT:
130                geo = wrapMultiPoint( jGeometry, crs );
131                break;
132            case JGeometry.GTYPE_MULTICURVE:
133                geo = wrapMultiCurve( jGeometry, crs );
134                break;
135            case JGeometry.GTYPE_MULTIPOLYGON:
136                geo = wrapMultiSurface( jGeometry, crs );
137                break;
138            case JGeometry.GTYPE_COLLECTION:
139            default: {
140                throw new GeometryException( "Cannot export Oracle JGeometry of type '" + jGeometry.getType()
141                                             + "' to deegree geometry: Unsupported type." );
142            }
143            }
144            return geo;
145        }
146    
147        /**
148         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_POINT</code> from a <code>Point</code>.
149         * 
150         * @param point
151         * @param srid
152         *            coordinate system for created Oracle <code>JGeometry</code> objects
153         */
154        private static JGeometry exportPoint( Point point, int srid ) {
155            int dimension = point.getCoordinateDimension();
156            double[] coords = point.getAsArray();
157            if ( dimension == 2 ) {
158                coords = new double[] { coords[0], coords[1] };
159            } else {
160                coords = new double[] { coords[0], coords[1], coords[2] };
161            }
162            return JGeometry.createPoint( coords, point.getCoordinateDimension(), srid );
163        }
164    
165        /**
166         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTIPOINT</code> from a <code>MultiPoint</code>.
167         * 
168         * @param multiPoint
169         * @param srid
170         *            coordinate system for created Oracle <code>JGeometry</code> objects
171         */
172        private static JGeometry exportMultiPoint( MultiPoint multiPoint, int srid ) {
173            Point[] points = multiPoint.getAllPoints();
174            int dimension = multiPoint.getCoordinateDimension();
175            Object[] coords = new Object[points.length];
176            for ( int i = 0; i < coords.length; i++ ) {
177                double[] d = points[i].getAsArray();
178                if ( dimension == 2 ) {
179                    coords[i] = new double[] { d[0], d[1] };
180                } else {
181                    coords[i] = new double[] { d[0], d[1], d[2] };
182                }
183            }
184            return JGeometry.createMultiPoint( coords, multiPoint.getCoordinateDimension(), srid );
185        }
186    
187        /**
188         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_CURVE</code> from a <code>Curve</code>.
189         * 
190         * @param curve
191         * @param srid
192         *            coordinate system for created Oracle <code>JGeometry</code> objects
193         */
194        private static JGeometry exportCurve( Curve curve, int srid )
195                                throws GeometryException {
196            int dimension = curve.getCoordinateDimension();
197            Position[] positions = curve.getAsLineString().getPositions();
198            double[] ordinates = new double[positions.length * dimension];
199            int ordinateIndex = 0;
200            for ( int i = 0; i < positions.length; i++ ) {
201                double[] position = positions[i].getAsArray();
202                for ( int j = 0; j < dimension; j++ ) {
203                    ordinates[ordinateIndex++] = position[j];
204                }
205            }
206            return JGeometry.createLinearLineString( ordinates, dimension, srid );
207        }
208    
209        /**
210         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTICURVE</code> from a <code>MultiCurve</code>.
211         * 
212         * @param multiCurve
213         * @param srid
214         *            coordinate system for created Oracle <code>JGeometry</code> objects
215         * @throws GeometryException
216         */
217        private static JGeometry exportMultiCurve( MultiCurve multiCurve, int srid )
218                                throws GeometryException {
219            int dimension = multiCurve.getCoordinateDimension();
220            Curve[] curves = multiCurve.getAllCurves();
221            Object[] coords = new Object[curves.length];
222            for ( int i = 0; i < curves.length; i++ ) {
223                Position[] positions = curves[i].getAsLineString().getPositions();
224                double[] ordinates = new double[positions.length * dimension];
225                int ordinateIndex = 0;
226                for ( int j = 0; j < positions.length; j++ ) {
227                    double[] position = positions[j].getAsArray();
228                    for ( int k = 0; k < dimension; k++ ) {
229                        ordinates[ordinateIndex++] = position[k];
230                    }
231                }
232                coords[i] = ordinates;
233            }
234            return JGeometry.createLinearMultiLineString( coords, dimension, srid );
235        }
236    
237        /**
238         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_POLYGON</code> from a <code>Surface</code>.
239         * 
240         * @param surface
241         * @param srid
242         *            coordinate system for created Oracle <code>JGeometry</code> objects
243         */
244        private static JGeometry exportSurface( Surface surface, int srid ) {
245            int dimension = surface.getCoordinateDimension();
246            Ring exteriorRing = surface.getSurfaceBoundary().getExteriorRing();
247            Ring[] interiorRings = surface.getSurfaceBoundary().getInteriorRings();
248            Object[] coords = null;
249            if ( interiorRings != null ) {
250                coords = new Object[1 + interiorRings.length];
251            } else {
252                coords = new Object[1];
253            }
254    
255            // counter for rings
256            int ringIndex = 0;
257            Position[] positions = exteriorRing.getPositions();
258            double[] ringOrdinates = new double[positions.length * dimension];
259            int ordinateIndex = 0;
260    
261            // process exterior ring
262            for ( int i = 0; i < positions.length; i++ ) {
263                double[] ordinates = positions[i].getAsArray();
264                for ( int j = 0; j < dimension; j++ ) {
265                    ringOrdinates[ordinateIndex++] = ordinates[j];
266                }
267            }
268            coords[ringIndex++] = ringOrdinates;
269    
270            // process interior rings
271            if ( interiorRings != null ) {
272                for ( int interiorRingIndex = 0; interiorRingIndex < interiorRings.length; interiorRingIndex++ ) {
273                    positions = interiorRings[interiorRingIndex].getPositions();
274                    ringOrdinates = new double[positions.length * dimension];
275                    ordinateIndex = 0;
276                    for ( int i = 0; i < positions.length; i++ ) {
277                        double[] ordinates = positions[i].getAsArray();
278                        for ( int j = 0; j < dimension; j++ ) {
279                            ringOrdinates[ordinateIndex++] = ordinates[j];
280                        }
281                    }
282                    coords[ringIndex++] = ringOrdinates;
283                }
284            }
285            return JGeometry.createLinearPolygon( coords, dimension, srid );
286        }
287    
288        /**
289         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTIPOLYGON</code> from a
290         * <code>MultiSurface</code>.
291         * 
292         * @param multiSurface
293         * @param srid
294         *            coordinate system for created Oracle <code>JGeometry</code> objects
295         */
296        private static JGeometry exportMultiSurface( MultiSurface multiSurface, int srid ) {
297    
298            List<Integer> elemInfoList = new ArrayList<Integer>( 50 );
299            List<Double> ordinateList = new ArrayList<Double>( 5000 );
300            Surface[] surfaces = multiSurface.getAllSurfaces();
301            int ordinateIdx = 1;
302            int dimension = multiSurface.getCoordinateDimension();
303            // for each surface
304            for ( int surfaceIdx = 0; surfaceIdx < surfaces.length; surfaceIdx++ ) {
305                Surface surface = surfaces[surfaceIdx];
306                // process exterior ring
307                Ring exteriorRing = surface.getSurfaceBoundary().getExteriorRing();
308                Position[] positions = exteriorRing.getPositions();
309                elemInfoList.add( new Integer( ordinateIdx ) );
310                elemInfoList.add( new Integer( 1003 ) );
311                elemInfoList.add( new Integer( 1 ) );
312                for ( int i = 0; i < positions.length; i++ ) {
313                    double[] ordinates = positions[i].getAsArray();
314                    for ( int j = 0; j < dimension; j++ ) {
315                        ordinateList.add( new Double( ordinates[j] ) );
316                        ordinateIdx++;
317                    }
318                }
319                // process interior rings
320                Ring[] interiorRings = surface.getSurfaceBoundary().getInteriorRings();
321                if ( interiorRings != null ) {
322                    for ( int interiorRingIdx = 0; interiorRingIdx < interiorRings.length; interiorRingIdx++ ) {
323                        positions = interiorRings[interiorRingIdx].getPositions();
324                        elemInfoList.add( new Integer( ordinateIdx ) );
325                        elemInfoList.add( new Integer( 2003 ) );
326                        elemInfoList.add( new Integer( 1 ) );
327                        for ( int i = 0; i < positions.length; i++ ) {
328                            double[] ordinates = positions[i].getAsArray();
329                            for ( int j = 0; j < dimension; j++ ) {
330                                ordinateList.add( new Double( ordinates[j] ) );
331                                ordinateIdx++;
332                            }
333                        }
334                    }
335                }
336            }
337            int[] elemInfo = new int[elemInfoList.size()];
338            for ( int i = 0; i < elemInfo.length; i++ ) {
339                elemInfo[i] = elemInfoList.get( i ).intValue();
340            }
341            double[] ordinates = new double[ordinateList.size()];
342            for ( int i = 0; i < ordinates.length; i++ ) {
343                ordinates[i] = ordinateList.get( i ).doubleValue();
344            }
345            return new JGeometry( JGeometry.GTYPE_MULTIPOLYGON, srid, elemInfo, ordinates );
346        }
347    
348        /**
349         * Creates a <code>Point</code> from an Oracle <code>JGeometry</code> with type <code>GTYPE_POINT</code>.
350         * 
351         * @param geometry
352         *            Oracle SDO geometry (must be of type <code>GTYPE_POINT</code>)
353         * @param crs
354         *            coordinate system of the created deegree <code>Geometry</code> object
355         * @return deegree geometry
356         * 
357         */
358        private static Point wrapPoint( JGeometry geometry, CoordinateSystem crs ) {
359    
360            int[] elemInfo = geometry.getElemInfo();
361            double ord[];
362            if ( elemInfo != null && elemInfo.length == 6 && elemInfo[5] == 0 ) {
363                // SDO geometry is an oriented point
364                int dimension = geometry.getDimensions();
365                double[] fullOrd = geometry.getOrdinatesArray();
366                ord = new double[dimension];
367                for ( int i = 0; i < dimension; i++ ) {
368                    ord[i] = fullOrd[i];
369                }
370            } else {
371                ord = geometry.getPoint();
372            }
373    
374            Position pos = GeometryFactory.createPosition( ord );
375            return GeometryFactory.createPoint( pos, crs );
376        }
377    
378        /**
379         * Creates a <code>MultiPoint</code> from an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTIPOINT</code>.
380         * 
381         * @param geometry
382         *            Oracle SDO geometry (must be of type <code>GTYPE_MULTIPOINT</code>)
383         * @param crs
384         *            coordinate system of the created deegree <code>Geometry</code> object
385         * @return deegree geometry
386         */
387        private static MultiPoint wrapMultiPoint( JGeometry geometry, CoordinateSystem crs ) {
388    
389            int[] elemInfo = geometry.getElemInfo();
390    
391            int dimension = geometry.getDimensions();
392            double[] ordinates = geometry.getOrdinatesArray();
393            if ( elemInfo != null ) {
394                ArrayList<Point> points = new ArrayList<Point>();
395    
396                for ( int i = 0; i < elemInfo.length; i += 3 ) {
397                    int offset = elemInfo[i] - 1;
398                    double[] pointOrdinates = new double[dimension];
399                    // elemInfo[i + 2] == 0 for oriented points
400                    for ( int j = 0; j < elemInfo[i + 2]; j++ ) {
401                        for ( int k = 0; k < dimension; k++ ) {
402                            pointOrdinates[k] = ordinates[offset++];
403                        }
404                        Position position = GeometryFactory.createPosition( pointOrdinates );
405                        points.add( GeometryFactory.createPoint( position, crs ) );
406                    }
407                }
408                return GeometryFactory.createMultiPoint( points.toArray( new Point[points.size()] ) );
409            }
410            Point[] points = new Point[geometry.getNumPoints()];
411    
412            for ( int i = 0; i < points.length; i++ ) {
413                double[] pointOrdinates = new double[dimension];
414                for ( int j = 0; j < dimension; j++ ) {
415                    pointOrdinates[j] = ordinates[i * dimension + j];
416                }
417                Position position = GeometryFactory.createPosition( pointOrdinates );
418                points[i] = GeometryFactory.createPoint( position, crs );
419            }
420            return GeometryFactory.createMultiPoint( points );
421        }
422    
423        /**
424         * Creates a <code>Curve</code> from an Oracle <code>JGeometry</code> with type <code>GTYPE_CURVE</code>.
425         * 
426         * @param geometry
427         *            Oracle SDO geometry (must be of type <code>GTYPE_CURVE</code>)
428         * @param crs
429         *            coordinate system of the created deegree <code>Geometry</code> object
430         * @return deegree geometry
431         * @throws GeometryException
432         */
433        private static Curve wrapCurve( JGeometry geometry, CoordinateSystem crs )
434                                throws GeometryException {
435            return GeometryFactory.createCurve( geometry.getOrdinatesArray(), geometry.getDimensions(), crs );
436        }
437    
438        /**
439         * Creates a <code>MultiCurve</code> from an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTICURVE</code>.
440         * 
441         * @param geometry
442         *            Oracle SDO geometry (must be of type <code>GTYPE_MULTICURVE</code>)
443         * @param crs
444         *            coordinate system of the created deegree <code>Geometry</code> object
445         * @return deegree geometry
446         * @throws GeometryException
447         */
448        private static MultiCurve wrapMultiCurve( JGeometry geometry, CoordinateSystem crs )
449                                throws GeometryException {
450            Object[] ooe = geometry.getOrdinatesOfElements();
451            int dim = geometry.getDimensions();
452            Curve[] curves = new Curve[ooe.length];
453            for ( int i = 0; i < ooe.length; i++ ) {
454                curves[i] = GeometryFactory.createCurve( (double[]) ooe[i], dim, crs );
455            }
456            return GeometryFactory.createMultiCurve( curves );
457        }
458    
459        /**
460         * Creates a <code>Surface</code> from an Oracle <code>JGeometry</code> with type <code>GTYPE_POLYGON</code>.
461         * 
462         * @param geometry
463         *            Oracle SDO geometry (must be of type <code>GTYPE_POLYGON</code>)
464         * @param crs
465         *            coordinate system of the created deegree <code>Geometry</code> object
466         * @return deegree geometry
467         * @throws GeometryException
468         */
469        private static Surface wrapSurface( JGeometry geometry, CoordinateSystem crs )
470                                throws GeometryException {
471            Object[] ooe = geometry.getOrdinatesOfElements();
472            int dim = geometry.getDimensions();
473            double[] exteriorRingOrdinates = (double[]) ooe[0];
474            double[][] interiorRingsOrdinates = null;
475            if ( exteriorRingOrdinates.length == 4 ) {
476                // it's a box
477                double[] tmp = new double[10];
478                tmp[0] = exteriorRingOrdinates[0];
479                tmp[1] = exteriorRingOrdinates[1];
480                tmp[2] = exteriorRingOrdinates[0];
481                tmp[3] = exteriorRingOrdinates[3];
482                tmp[4] = exteriorRingOrdinates[2];
483                tmp[5] = exteriorRingOrdinates[3];
484                tmp[6] = exteriorRingOrdinates[2];
485                tmp[7] = exteriorRingOrdinates[1];
486                tmp[8] = exteriorRingOrdinates[0];
487                tmp[9] = exteriorRingOrdinates[1];
488                exteriorRingOrdinates = tmp;
489            } else {
490                if ( ooe.length > 1 ) {
491                    interiorRingsOrdinates = new double[ooe.length - 1][];
492                    for ( int i = 0; i < ooe.length - 1; i++ ) {
493                        interiorRingsOrdinates[i] = (double[]) ooe[i + 1];
494                    }
495                }
496            }
497            return GeometryFactory.createSurface( exteriorRingOrdinates, interiorRingsOrdinates, dim, crs );
498        }
499    
500        /**
501         * Creates a <code>MultiSurface</code> from an Oracle <code>JGeometry</code> with type
502         * <code>GTYPE_MULTIPOLYGON</code>.
503         * 
504         * @param geometry
505         *            Oracle SDO geometry (must be of type <code>GTYPE_MULTIPOLYGON</code>)
506         * @param crs
507         *            coordinate system of the created deegree <code>Geometry</code> object
508         * @return deegree geometry
509         * @throws GeometryException
510         */
511        private static MultiSurface wrapMultiSurface( JGeometry geometry, CoordinateSystem crs )
512                                throws GeometryException {
513            Object[] ooe = geometry.getOrdinatesOfElements();
514            int dim = geometry.getDimensions();
515            List<Surface> list = new ArrayList<Surface>( 100 );
516    
517            int i = 0;
518            while ( i < ooe.length ) {
519                double[] ext = (double[]) ooe[i++];
520                Surface surf = GeometryFactory.createSurface( ext, null, dim, crs );
521                boolean within = false;
522                List<double[]> temp = new ArrayList<double[]>( 100 );
523                if ( i < ooe.length - 1 ) {
524                    do {
525                        double[] ord = (double[]) ooe[i++];
526                        double[] pnt = new double[dim];
527                        for ( int j = 0; j < pnt.length; j++ ) {
528                            pnt[j] = ord[j];
529                        }
530                        Position pos = GeometryFactory.createPosition( pnt );
531                        within = surf.contains( pos );
532                        if ( within ) {
533                            temp.add( ord );
534                        }
535                    } while ( within && i < ooe.length );
536                    if ( !within ) {
537                        i--;
538                    }
539                }
540                double[][] in = new double[temp.size()][];
541                in = temp.toArray( in );
542                list.add( GeometryFactory.createSurface( ext, in, dim, crs ) );
543            }
544    
545            Surface[] polys = new Surface[list.size()];
546            polys = list.toArray( polys );
547            return GeometryFactory.createMultiSurface( polys );
548        }
549    }