001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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>
059     * objects.
060     *
061     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </A>
062     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
063     * @author last edited by: $Author: mschneider $
064     *
065     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
066     */
067    public class JGeometryAdapter {
068    
069        private JGeometryAdapter() {
070            // avoid instantiation
071        }
072    
073        /**
074         * Converts a deegree <code>Geometry</code> instance to a corresponding Oracle
075         * <code>JGeometry</code> object.
076         *
077         * @param geometry
078         *            deegree <code>Geometry</code> to be converted
079         * @param srid
080         *            coordinate system for created Oracle <code>JGeometry</code> objects
081         * @return corresponding Oracle <code>JGeometry</code>
082         * @throws GeometryException
083         */
084        public static JGeometry export( Geometry geometry, int srid )
085                                throws GeometryException {
086            JGeometry jGeometry = null;
087    
088            if ( geometry instanceof Point ) {
089                jGeometry = exportPoint( (Point) geometry, srid );
090            } else if ( geometry instanceof MultiPoint ) {
091                jGeometry = exportMultiPoint( (MultiPoint) geometry, srid );
092            } else if ( geometry instanceof Curve ) {
093                jGeometry = exportCurve( (Curve) geometry, srid );
094            } else if ( geometry instanceof MultiCurve ) {
095                jGeometry = exportMultiCurve( (MultiCurve) geometry, srid );
096            } else if ( geometry instanceof Surface ) {
097                jGeometry = exportSurface( (Surface) geometry, srid );
098            } else if ( geometry instanceof MultiSurface ) {
099                jGeometry = exportMultiSurface( (MultiSurface) geometry, srid );
100            } else {
101                throw new GeometryException( "Cannot export geometry of type '" + geometry.getClass()
102                                             + "' to Oracle JGeometry: Unsupported type." );
103            }
104            return jGeometry;
105        }
106    
107        /**
108         * Converts an Oracle <code>JGeometry</code> instance to a corresponding deegree
109         * <code>Geometry</code> object.
110         *
111         * @param jGeometry
112         *            Oracle <code>JGeometry</code> to be converted
113         * @param crs
114         *            coordinate system of the created deegree <code>Geometry</code> object
115         * @return corresponding deegree <code>Geometry</code>
116         * @throws GeometryException
117         */
118        public static Geometry wrap( JGeometry jGeometry, CoordinateSystem crs )
119                                throws GeometryException {
120            Geometry geo = null;
121    
122            switch ( jGeometry.getType() ) {
123            case JGeometry.GTYPE_POINT:
124                geo = wrapPoint( jGeometry, crs );
125                break;
126            case JGeometry.GTYPE_CURVE:
127                geo = wrapCurve( jGeometry, crs );
128                break;
129            case JGeometry.GTYPE_POLYGON:
130                geo = wrapSurface( jGeometry, crs );
131                break;
132            case JGeometry.GTYPE_MULTIPOINT:
133                geo = wrapMultiPoint( jGeometry, crs );
134                break;
135            case JGeometry.GTYPE_MULTICURVE:
136                geo = wrapMultiCurve( jGeometry, crs );
137                break;
138            case JGeometry.GTYPE_MULTIPOLYGON:
139                geo = wrapMultiSurface( jGeometry, crs );
140                break;
141            case JGeometry.GTYPE_COLLECTION:
142            default: {
143                throw new GeometryException( "Cannot export Oracle JGeometry of type '" + jGeometry.getType()
144                                             + "' to deegree geometry: Unsupported type." );
145            }
146            }
147            return geo;
148        }
149    
150        /**
151         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_POINT</code> from a
152         * <code>Point</code>.
153         *
154         * @param point
155         * @param srid
156         *            coordinate system for created Oracle <code>JGeometry</code> objects
157         */
158        private static JGeometry exportPoint( Point point, int srid ) {
159            int dimension = point.getCoordinateDimension();
160            double[] coords = point.getAsArray();
161            if ( dimension == 2 ) {
162                coords = new double[] { coords[0], coords[1] };
163            } else {
164                coords = new double[] { coords[0], coords[1], coords[2] };
165            }
166            return JGeometry.createPoint( coords, point.getCoordinateDimension(), srid );
167        }
168    
169        /**
170         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTIPOINT</code> from a
171         * <code>MultiPoint</code>.
172         *
173         * @param multiPoint
174         * @param srid
175         *            coordinate system for created Oracle <code>JGeometry</code> objects
176         */
177        private static JGeometry exportMultiPoint( MultiPoint multiPoint, int srid ) {
178            Point[] points = multiPoint.getAllPoints();
179            int dimension = multiPoint.getCoordinateDimension();
180            Object[] coords = new Object[points.length];
181            for ( int i = 0; i < coords.length; i++ ) {
182                double[] d = points[i].getAsArray();
183                if ( dimension == 2 ) {
184                    coords[i] = new double[] { d[0], d[1] };
185                } else {
186                    coords[i] = new double[] { d[0], d[1], d[2] };
187                }
188            }
189            return JGeometry.createMultiPoint( coords, multiPoint.getCoordinateDimension(), srid );
190        }
191    
192        /**
193         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_CURVE</code> from a
194         * <code>Curve</code>.
195         *
196         * @param curve
197         * @param srid
198         *            coordinate system for created Oracle <code>JGeometry</code> objects
199         */
200        private static JGeometry exportCurve( Curve curve, int srid )
201                                throws GeometryException {
202            int dimension = curve.getCoordinateDimension();
203            Position[] positions = curve.getAsLineString().getPositions();
204            double[] ordinates = new double[positions.length * dimension];
205            int ordinateIndex = 0;
206            for ( int i = 0; i < positions.length; i++ ) {
207                double[] position = positions[i].getAsArray();
208                for ( int j = 0; j < dimension; j++ ) {
209                    ordinates[ordinateIndex++] = position[j];
210                }
211            }
212            return JGeometry.createLinearLineString( ordinates, dimension, srid );
213        }
214    
215        /**
216         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTICURVE</code> from a
217         * <code>MultiCurve</code>.
218         *
219         * @param multiCurve
220         * @param srid
221         *            coordinate system for created Oracle <code>JGeometry</code> objects
222         * @throws GeometryException
223         */
224        private static JGeometry exportMultiCurve( MultiCurve multiCurve, int srid )
225                                throws GeometryException {
226            int dimension = multiCurve.getCoordinateDimension();
227            Curve[] curves = multiCurve.getAllCurves();
228            Object[] coords = new Object[curves.length];
229            for ( int i = 0; i < curves.length; i++ ) {
230                Position[] positions = curves[i].getAsLineString().getPositions();
231                double[] ordinates = new double[positions.length * dimension];
232                int ordinateIndex = 0;
233                for ( int j = 0; j < positions.length; j++ ) {
234                    double[] position = positions[j].getAsArray();
235                    for ( int k = 0; k < dimension; k++ ) {
236                        ordinates[ordinateIndex++] = position[k];
237                    }
238                }
239                coords[i] = ordinates;
240            }
241            return JGeometry.createLinearMultiLineString( coords, dimension, srid );
242        }
243    
244        /**
245         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_POLYGON</code> from a
246         * <code>Surface</code>.
247         *
248         * @param surface
249         * @param srid
250         *            coordinate system for created Oracle <code>JGeometry</code> objects
251         */
252        private static JGeometry exportSurface( Surface surface, int srid ) {
253            int dimension = surface.getCoordinateDimension();
254            Ring exteriorRing = surface.getSurfaceBoundary().getExteriorRing();
255            Ring[] interiorRings = surface.getSurfaceBoundary().getInteriorRings();
256            Object[] coords = null;
257            if ( interiorRings != null ) {
258                coords = new Object[1 + interiorRings.length];
259            } else {
260                coords = new Object[1];
261            }
262    
263            // counter for rings
264            int ringIndex = 0;
265            Position[] positions = exteriorRing.getPositions();
266            double[] ringOrdinates = new double[positions.length * dimension];
267            int ordinateIndex = 0;
268    
269            // process exterior ring
270            for ( int i = 0; i < positions.length; i++ ) {
271                double[] ordinates = positions[i].getAsArray();
272                for ( int j = 0; j < dimension; j++ ) {
273                    ringOrdinates[ordinateIndex++] = ordinates[j];
274                }
275            }
276            coords[ringIndex++] = ringOrdinates;
277    
278            // process interior rings
279            if ( interiorRings != null ) {
280                for ( int interiorRingIndex = 0; interiorRingIndex < interiorRings.length; interiorRingIndex++ ) {
281                    positions = interiorRings[interiorRingIndex].getPositions();
282                    ringOrdinates = new double[positions.length * dimension];
283                    ordinateIndex = 0;
284                    for ( int i = 0; i < positions.length; i++ ) {
285                        double[] ordinates = positions[i].getAsArray();
286                        for ( int j = 0; j < dimension; j++ ) {
287                            ringOrdinates[ordinateIndex++] = ordinates[j];
288                        }
289                    }
290                    coords[ringIndex++] = ringOrdinates;
291                }
292            }
293            return JGeometry.createLinearPolygon( coords, dimension, srid );
294        }
295    
296        /**
297         * Creates an Oracle <code>JGeometry</code> with type <code>GTYPE_MULTIPOLYGON</code> from a
298         * <code>MultiSurface</code>.
299         *
300         * @param multiSurface
301         * @param srid
302         *            coordinate system for created Oracle <code>JGeometry</code> objects
303         */
304        private static JGeometry exportMultiSurface( MultiSurface multiSurface, int srid ) {
305    
306            List<Integer> elemInfoList = new ArrayList<Integer>( 50 );
307            List<Double> ordinateList = new ArrayList<Double>( 5000 );
308            Surface[] surfaces = multiSurface.getAllSurfaces();
309            int ordinateIdx = 1;
310            int dimension = multiSurface.getCoordinateDimension();
311            // for each surface
312            for ( int surfaceIdx = 0; surfaceIdx < surfaces.length; surfaceIdx++ ) {
313                Surface surface = surfaces[surfaceIdx];
314                // process exterior ring
315                Ring exteriorRing = surface.getSurfaceBoundary().getExteriorRing();
316                Position[] positions = exteriorRing.getPositions();
317                elemInfoList.add( new Integer( ordinateIdx ) );
318                elemInfoList.add( new Integer( 1003 ) );
319                elemInfoList.add( new Integer( 1 ) );
320                for ( int i = 0; i < positions.length; i++ ) {
321                    double[] ordinates = positions[i].getAsArray();
322                    for ( int j = 0; j < dimension; j++ ) {
323                        ordinateList.add( new Double( ordinates[j] ) );
324                        ordinateIdx++;
325                    }
326                }
327                // process interior rings
328                Ring[] interiorRings = surface.getSurfaceBoundary().getInteriorRings();
329                if ( interiorRings != null ) {
330                    for ( int interiorRingIdx = 0; interiorRingIdx < interiorRings.length; interiorRingIdx++ ) {
331                        positions = interiorRings[interiorRingIdx].getPositions();
332                        elemInfoList.add( new Integer( ordinateIdx ) );
333                        elemInfoList.add( new Integer( 2003 ) );
334                        elemInfoList.add( new Integer( 1 ) );
335                        for ( int i = 0; i < positions.length; i++ ) {
336                            double[] ordinates = positions[i].getAsArray();
337                            for ( int j = 0; j < dimension; j++ ) {
338                                ordinateList.add( new Double( ordinates[j] ) );
339                                ordinateIdx++;
340                            }
341                        }
342                    }
343                }
344            }
345            int[] elemInfo = new int[elemInfoList.size()];
346            for ( int i = 0; i < elemInfo.length; i++ ) {
347                elemInfo[i] = elemInfoList.get( i ).intValue();
348            }
349            double[] ordinates = new double[ordinateList.size()];
350            for ( int i = 0; i < ordinates.length; i++ ) {
351                ordinates[i] = ordinateList.get( i ).doubleValue();
352            }
353            return new JGeometry( JGeometry.GTYPE_MULTIPOLYGON, srid, elemInfo, ordinates );
354        }
355    
356        /**
357         * Creates a <code>Point</code> from an Oracle <code>JGeometry</code> with type
358         * <code>GTYPE_POINT</code>.
359         *
360         * @param geometry
361         *            Oracle SDO geometry (must be of type <code>GTYPE_POINT</code>)
362         * @param crs
363         *            coordinate system of the created deegree <code>Geometry</code> object
364         * @return deegree geometry
365         *
366         */
367        private static Point wrapPoint( JGeometry geometry, CoordinateSystem crs ) {
368            double[] ord = geometry.getPoint();
369            Position pos = GeometryFactory.createPosition( ord );
370            return GeometryFactory.createPoint( pos, crs );
371        }
372    
373        /**
374         * Creates a <code>MultiPoint</code> from an Oracle <code>JGeometry</code> with type
375         * <code>GTYPE_MULTIPOINT</code>.
376         *
377         * @param geometry
378         *            Oracle SDO geometry (must be of type <code>GTYPE_MULTIPOINT</code>)
379         * @param crs
380         *            coordinate system of the created deegree <code>Geometry</code> object
381         * @return deegree geometry
382         */
383        private static MultiPoint wrapMultiPoint( JGeometry geometry, CoordinateSystem crs ) {
384    
385            Point[] points = new Point[geometry.getNumPoints()];
386            double[] ordinates = geometry.getOrdinatesArray();
387            int dimension = geometry.getDimensions();
388    
389            for ( int i = 0; i < points.length; i++ ) {
390                double[] pointOrdinates = new double[dimension];
391                for ( int j = 0; j < dimension; j++ ) {
392                    pointOrdinates[j] = ordinates[i * dimension + j];
393                }
394                Position position = GeometryFactory.createPosition( pointOrdinates );
395                points[i] = GeometryFactory.createPoint( position, crs );
396            }
397            return GeometryFactory.createMultiPoint( points );
398        }
399    
400        /**
401         * Creates a <code>Curve</code> from an Oracle <code>JGeometry</code> with type
402         * <code>GTYPE_CURVE</code>.
403         *
404         * @param geometry
405         *            Oracle SDO geometry (must be of type <code>GTYPE_CURVE</code>)
406         * @param crs
407         *            coordinate system of the created deegree <code>Geometry</code> object
408         * @return deegree geometry
409         * @throws GeometryException
410         */
411        private static Curve wrapCurve( JGeometry geometry, CoordinateSystem crs )
412                                throws GeometryException {
413            return GeometryFactory.createCurve( geometry.getOrdinatesArray(), geometry.getDimensions(), crs );
414        }
415    
416        /**
417         * Creates a <code>MultiCurve</code> from an Oracle <code>JGeometry</code> with type
418         * <code>GTYPE_MULTICURVE</code>.
419         *
420         * @param geometry
421         *            Oracle SDO geometry (must be of type <code>GTYPE_MULTICURVE</code>)
422         * @param crs
423         *            coordinate system of the created deegree <code>Geometry</code> object
424         * @return deegree geometry
425         * @throws GeometryException
426         */
427        private static MultiCurve wrapMultiCurve( JGeometry geometry, CoordinateSystem crs )
428                                throws GeometryException {
429            Object[] ooe = geometry.getOrdinatesOfElements();
430            int dim = geometry.getDimensions();
431            Curve[] curves = new Curve[ooe.length];
432            for ( int i = 0; i < ooe.length; i++ ) {
433                curves[i] = GeometryFactory.createCurve( (double[]) ooe[i], dim, crs );
434            }
435            return GeometryFactory.createMultiCurve( curves );
436        }
437    
438        /**
439         * Creates a <code>Surface</code> from an Oracle <code>JGeometry</code> with type
440         * <code>GTYPE_POLYGON</code>.
441         *
442         * @param geometry
443         *            Oracle SDO geometry (must be of type <code>GTYPE_POLYGON</code>)
444         * @param crs
445         *            coordinate system of the created deegree <code>Geometry</code> object
446         * @return deegree geometry
447         * @throws GeometryException
448         */
449        private static Surface wrapSurface( JGeometry geometry, CoordinateSystem crs )
450                                throws GeometryException {
451            Object[] ooe = geometry.getOrdinatesOfElements();
452            int dim = geometry.getDimensions();
453            double[] exteriorRingOrdinates = (double[]) ooe[0];
454            double[][] interiorRingsOrdinates = null;
455            if ( exteriorRingOrdinates.length == 4 ) {
456                // it's a box
457                double[] tmp = new double[10];
458                tmp[0] = exteriorRingOrdinates[0];
459                tmp[1] = exteriorRingOrdinates[1];
460                tmp[2] = exteriorRingOrdinates[0];
461                tmp[3] = exteriorRingOrdinates[3];
462                tmp[4] = exteriorRingOrdinates[2];
463                tmp[5] = exteriorRingOrdinates[3];
464                tmp[6] = exteriorRingOrdinates[2];
465                tmp[7] = exteriorRingOrdinates[1];
466                tmp[8] = exteriorRingOrdinates[0];
467                tmp[9] = exteriorRingOrdinates[1];
468                exteriorRingOrdinates = tmp;
469            } else {
470                if ( ooe.length > 1 ) {
471                    interiorRingsOrdinates = new double[ooe.length - 1][];
472                    for ( int i = 0; i < ooe.length - 1; i++ ) {
473                        interiorRingsOrdinates[i] = (double[]) ooe[i + 1];
474                    }
475                }
476            }
477            return GeometryFactory.createSurface( exteriorRingOrdinates, interiorRingsOrdinates, dim, crs );
478        }
479    
480        /**
481         * Creates a <code>MultiSurface</code> from an Oracle <code>JGeometry</code> with type
482         * <code>GTYPE_MULTIPOLYGON</code>.
483         *
484         * @param geometry
485         *            Oracle SDO geometry (must be of type <code>GTYPE_MULTIPOLYGON</code>)
486         * @param crs
487         *            coordinate system of the created deegree <code>Geometry</code> object
488         * @return deegree geometry
489         * @throws GeometryException
490         */
491        private static MultiSurface wrapMultiSurface( JGeometry geometry, CoordinateSystem crs )
492                                throws GeometryException {
493            Object[] ooe = geometry.getOrdinatesOfElements();
494            int dim = geometry.getDimensions();
495            List<Surface> list = new ArrayList<Surface>( 100 );
496    
497            int i = 0;
498            while ( i < ooe.length ) {
499                double[] ext = (double[]) ooe[i++];
500                Surface surf = GeometryFactory.createSurface( ext, null, dim, crs );
501                boolean within = false;
502                List<double[]> temp = new ArrayList<double[]>( 100 );
503                if ( i < ooe.length - 1 ) {
504                    do {
505                        double[] ord = (double[]) ooe[i++];
506                        double[] pnt = new double[dim];
507                        for ( int j = 0; j < pnt.length; j++ ) {
508                            pnt[j] = ord[j];
509                        }
510                        Position pos = GeometryFactory.createPosition( pnt );
511                        within = surf.contains( pos );
512                        if ( within ) {
513                            temp.add( ord );
514                        }
515                    } while ( within && i < ooe.length );
516                    if ( !within ) {
517                        i--;
518                    }
519                }
520                double[][] in = new double[temp.size()][];
521                in = temp.toArray( in );
522                list.add( GeometryFactory.createSurface( ext, in, dim, crs ) );
523            }
524    
525            Surface[] polys = new Surface[list.size()];
526            polys = list.toArray( polys );
527            return GeometryFactory.createMultiSurface( polys );
528        }
529    }