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