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