    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/io/sdeapi/SpatialQuery.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    package org.deegree.io.sdeapi;
    037
    038    import java.io.ByteArrayInputStream;
    039    import java.util.ArrayList;
    040    import java.util.Vector;
    041
    042    import org.deegree.datatypes.Types;
    043    import org.deegree.framework.log.ILogger;
    044    import org.deegree.framework.log.LoggerFactory;
    045    import org.deegree.framework.util.StringTools;
    046    import org.deegree.model.spatialschema.Curve;
    047    import org.deegree.model.spatialschema.Envelope;
    048    import org.deegree.model.spatialschema.Geometry;
    049    import org.deegree.model.spatialschema.GeometryFactory;
    050    import org.deegree.model.spatialschema.MultiCurve;
    051    import org.deegree.model.spatialschema.MultiPoint;
    052    import org.deegree.model.spatialschema.MultiSurface;
    053    import org.deegree.model.spatialschema.Point;
    054    import org.deegree.model.spatialschema.Position;
    055    import org.deegree.model.spatialschema.Surface;
    056    import org.deegree.model.spatialschema.SurfaceInterpolation;
    057    import org.deegree.model.spatialschema.SurfaceInterpolationImpl;
    058    import org.deegree.model.table.DefaultTable;
    059    import org.deegree.model.table.Table;
    060    import org.deegree.model.table.TableException;
    061
    062    import com.esri.sde.sdk.client.SDEPoint;
    063    import com.esri.sde.sdk.client.SeColumnDefinition;
    064    import com.esri.sde.sdk.client.SeConnection;
    065    import com.esri.sde.sdk.client.SeException;
    066    import com.esri.sde.sdk.client.SeExtent;
    067    import com.esri.sde.sdk.client.SeFilter;
    068    import com.esri.sde.sdk.client.SeLayer;
    069    import com.esri.sde.sdk.client.SeQuery;
    070    import com.esri.sde.sdk.client.SeRow;
    071    import com.esri.sde.sdk.client.SeShape;
    072    import com.esri.sde.sdk.client.SeShapeFilter;
    073    import com.esri.sde.sdk.client.SeSqlConstruct;
    074    import com.esri.sde.sdk.client.SeTable;
    075
    076    /**
    077     * This class handles a complete ArcSDE request: If instanciated, the class can open a
    078     * connection/instance of the specified ArcSDE server, set a bounding box as a spatial filter to
    079     * query the defined layer. The resultset of the query contains the geometries as well as the
    080     * tabular data associated with them. The table is stored as a deegree Table object whereas the
    081     * geometries are stored as an array of deegree GM_Objects. Depending on the datatype of the
    082     * geometries, the array of GM_Objects might be GM_Point, GM_Curve etc.
    083     * <p>
    084     * Some bits of sample code to create a query:
    085     * <p>
    086     * <code>
    087     *        SpatialQuery sq = new SpatialQuery();<br>
    088     *        try {<br>
    089     *        &nbsp;sq.openConnection(server, instance, database, user, password);<br>
    090     *        &nbsp;sq.setLayer(layer);<br>
    091     *        &nbsp;sq.setSpatialFilter(minX, minY, maxX, maxY);<br>
    092     *        &nbsp;sp.runSpatialQuery();<br>
    093     *        &nbsp;GM_Object[] deegree_gm_obj = sq.getGeometries();<br>
    094     *        &nbsp;Table deegree_table = sq.getTable();<br>
    095     *        &nbsp;sq.closeConnection();<br>
    096     *        } catch ( SeException sexp ) {<br>
    097     *        }<br>
    098     * </code>
    099     *
    100     * @author <a href="mailto:bedel@giub.uni-bonn.de">Markus Bedel</a>
    101     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    102     * @version $Revision: 18195 $ $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    103     */
    104    public class SpatialQuery {
    105
    106        private static final ILogger LOG = LoggerFactory.getLogger( SpatialQuery.class );
    107
    108        // Connection to SDE
    109        private SeConnection conn = null;
    110
    111        // Currently opened Layer and associated Table
    112        private SeLayer layer = null;
    113
    114        // Current Spatial Filter - a BoundingBox
    115        private SeShape spatialFilter = null;
    116
    117        private SeTable table = null;
    118
    119        // The Query ResultObjects
    120        private Geometry[] deegreeGeom = null;
    121
    122        /**
    123         * Creates a new SpatialQuery object.
    124         *
    125         * @param server
    126         * @param port
    127         * @param database
    128         * @param user
    129         * @param password
    130         *
    131         * @throws SeException
    132         */
    133        public SpatialQuery( String server, int port, String database, String user, String password ) throws SeException {
    134            openConnection( server, port, database, user, password );
    135        }
    136
    137        /**
    138         * Connect to the ArcSDE server <br>
    139         * throws SeException
    140         *
    141         * @param server
    142         * @param port
    143         * @param database
    144         * @param user
    145         * @param password
    146         * @throws SeException
    147         */
    148        public void openConnection( String server, int port, String database, String user, String password )
    149                                throws SeException {
    150            conn = new SeConnection( server, port, database, user, password );
    151        }
    152
    153        /**
    154         * Close the current connection to the ArcSDE server <br>
    155         * throws SeException
    156         *
    157         * @throws SeException
    158         */
    159        public void closeConnection()
    160                                throws SeException {
    161            conn.close();
    162        }
    163
    164        /**
    165         * Set a SDE layer to work on and appropriate table <br>
    166         * throws SeException
    167         *
    168         * @param layername
    169         * @throws SeException
    170         */
    171        public void setLayer( String layername )
    172                                throws SeException {
    173            Vector<?> layerList = conn.getLayers();
    174            String spatialCol = null;
    175
    176            for ( int i = 0; i < layerList.size(); i++ ) {
    177                SeLayer layer = (SeLayer) layerList.elementAt( i );
    178                if ( layer.getQualifiedName().trim().equalsIgnoreCase( layername ) ) {
    179                    spatialCol = layer.getSpatialColumn();
    180                    break;
    181                }
    182            }
    183
    184            layer = new SeLayer( conn, layername, spatialCol );
    185            table = new SeTable( conn, layer.getQualifiedName() );
    186
    187        }
    188
    189        /**
    190         * Get the current SDE layer <br>
    191         * returns null if it not yet set.
    192         *
    193         * @return null if it not yet set.
    194         */
    195        public SeLayer getLayer() {
    196            return layer;
    197        }
    198
    199        /**
    200         * Set a SpatialFilter to Query (BoundingBox) <br>
    201         * throws SeException
    202         *
    203         * @param minx
    204         * @param miny
    205         * @param maxx
    206         * @param maxy
    207         * @throws SeException
    208         */
    209        public void setSpatialFilter( double minx, double miny, double maxx, double maxy )
    210                                throws SeException {
    211
    212            Envelope layerBBox = GeometryFactory.createEnvelope( layer.getExtent().getMinX(), layer.getExtent().getMinY(),
    213                                                                 layer.getExtent().getMaxX(), layer.getExtent().getMaxY(),
    214                                                                 null );
    215
    216            Envelope query = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, null );
    217            query = query.createIntersection( layerBBox );
    218
    219            if ( query != null ) {
    220                spatialFilter = new SeShape( layer.getCoordRef() );
    221                SeExtent extent = new SeExtent( query.getMin().getX(), query.getMin().getY(), query.getMax().getX(),
    222                                                query.getMax().getY() );
    223                spatialFilter.generateRectangle( extent );
    224            } else {
    225                spatialFilter = null;
    226            }
    227
    228        }
    229
    230        /**
    231         * Get the current Spatial Filter <br>
    232         * returns null if it not yet set.
    233         *
    234         * @return null if it not yet set.
    235         */
    236        public SeShape getSpatialFilter() {
    237            return spatialFilter;
    238        }
    239
    240        /**
    241         * Get GM_Object[] containing the queried Geometries <br>
    242         * returns null if no query has been done yet.
    243         *
    244         * @return null if no query has been done yet.
    245         */
    246        public Geometry[] getGeometries() {
    247            return deegreeGeom;
    248        }
    249
    250        /**
    251         * Runs a spatial query against the opened layer using the specified spatial filter. <br>
    252         * throws SeException
    253         *
    254         * @param cols
    255         * @return the resulting table
    256         * @throws SeException
    257         * @throws DeegreeSeException
    258         */
    259        public Table runSpatialQuery( String[] cols )
    260                                throws SeException, DeegreeSeException {
    261
    262            Table deegreeTable = null;
    263            if ( spatialFilter != null ) {
    264                SeShapeFilter[] filters = new SeShapeFilter[1];
    265
    266                filters[0] = new SeShapeFilter( layer.getQualifiedName(), layer.getSpatialColumn(), spatialFilter,
    267                                                SeFilter.METHOD_ENVP );
    268
    269                SeColumnDefinition[] tableDef = table.describe();
    270                if ( cols == null || cols.length == 0 ) {
    271                    cols = new String[tableDef.length];
    272                    for ( int i = 0; i < tableDef.length; i++ ) {
    273                        cols[i] = tableDef[i].getName();
    274                    }
    275                }
    276
    277                SeSqlConstruct sqlCons = new SeSqlConstruct( layer.getQualifiedName() );
    278                SeQuery spatialQuery = new SeQuery( conn, cols, sqlCons );
    279
    280                spatialQuery.prepareQuery();
    281                spatialQuery.setSpatialConstraints( SeQuery.SE_OPTIMIZE, false, filters );
    282                spatialQuery.execute();
    283
    284                SeRow row = spatialQuery.fetch();
    285
    286                int numRows = 0;
    287                if ( row != null ) {
    288                    int numCols = row.getNumColumns();
    289                    // Fetch all the features that satisfied the query
    290                    deegreeTable = initTable( row );
    291
    292                    ArrayList<Geometry> list = new ArrayList<Geometry>( 20000 );
    293                    Object[] tableObj = null;
    294
    295                    while ( row != null ) {
    296                        int colNum = 0;
    297                        tableObj = new Object[deegreeTable.getColumnCount()];
    298
    299                        for ( int i = 0; i < numCols; i++ ) {
    300                            SeColumnDefinition colDef = row.getColumnDef( i );
    301
    302                            if ( row.getIndicator( (short) i ) != SeRow.SE_IS_NULL_VALUE ) {
    303                                switch ( colDef.getType() ) {
    304                                case SeColumnDefinition.TYPE_INT16:
    305                                    tableObj[colNum++] = row.getShort( i );
    306                                    break;
    307                                case SeColumnDefinition.TYPE_INT32:
    308                                    tableObj[colNum++] = row.getInteger( i );
    309                                    break;
    310                                case SeColumnDefinition.TYPE_FLOAT32:
    311                                    tableObj[colNum++] = row.getFloat( i );
    312                                    break;
    313                                case SeColumnDefinition.TYPE_FLOAT64:
    314                                    tableObj[colNum++] = row.getDouble( i );
    315                                    break;
    316                                case SeColumnDefinition.TYPE_STRING:
    317                                    tableObj[colNum++] = row.getString( i );
    318                                    break;
    319                                case SeColumnDefinition.TYPE_BLOB:
    320                                    ByteArrayInputStream bis = (ByteArrayInputStream) row.getObject( i );
    321                                    tableObj[colNum++] = bis;
    322                                    break;
    323                                case SeColumnDefinition.TYPE_DATE:
    324                                    tableObj[colNum++] = row.getTime( i ).getTime();
    325                                    break;
    326                                case SeColumnDefinition.TYPE_RASTER:
    327                                    LOG.logInfo( colDef.getName() + " : Cant handle this" );
    328                                    break;
    329                                case SeColumnDefinition.TYPE_SHAPE:
    330                                    SeShape spVal = row.getShape( i );
    331                                    createGeometry( spVal, list );
    332                                    break;
    333                                default:
    334                                    LOG.logInfo( "Unknown Table DataType" );
    335                                    break;
    336                                } // End switch(type)
    337                            } // End if
    338                        } // End for
    339
    340                        numRows++;
    341
    342                        try {
    343                            deegreeTable.appendRow( tableObj );
    344                        } catch ( TableException tex ) {
    345                            throw new DeegreeSeException( tex.toString() );
    346                        }
    347
    348                        row = spatialQuery.fetch();
    349                    } // End while
    350                    spatialQuery.close();
    351
    352                    deegreeGeom = list.toArray( new Geometry[list.size()] );
    353                } else {
    354                    try {
    355                        deegreeTable = new DefaultTable( layer.getQualifiedName(), new String[] { "NONE" },
    356                                                         new int[] { Types.VARCHAR }, 2 );
    357                    } catch ( Exception e ) {
    358                        e.printStackTrace();
    359                    }
    360                    deegreeGeom = new Geometry[0];
    361                }
    362            } else {
    363                try {
    364                    deegreeTable = new DefaultTable( layer.getQualifiedName(), new String[] { "NONE" },
    365                                                     new int[] { Types.VARCHAR }, 2 );
    366                } catch ( Exception e ) {
    367                    e.printStackTrace();
    368                }
    369                deegreeGeom = new Geometry[0];
    370            }
    371
    372            return deegreeTable;
    373        } // End method runSpatialQuery
    374
    375        /**
    376         * Initialize Table object - used with first row of the SpatialQuery This method sets the
    377         * TableName, TableColumnNames and their DataTypes <br>
    378         * throws SeException
    379         */
    380        private Table initTable( SeRow row )
    381                                throws SeException, DeegreeSeException {
    382            ArrayList<String> colNames = new ArrayList<String>( 50 );
    383            ArrayList<Integer> colTypes = new ArrayList<Integer>( 50 );
    384            Table deegreeTable = null;
    385            SeColumnDefinition colDef = null;
    386
    387            for ( int i = 0; i < row.getNumColumns(); i++ ) {
    388                try {
    389                    colDef = row.getColumnDef( i );
    390                } catch ( SeException sexp ) {
    391                    sexp.printStackTrace();
    392                    throw new DeegreeSeException( sexp.toString() );
    393                }
    394
    395                switch ( colDef.getType() ) {
    396                case SeColumnDefinition.TYPE_INT16:
    397                    colNames.add( colDef.getName().toUpperCase() );
    398                    colTypes.add( new Integer( Types.SMALLINT ) );
    399                    break;
    400                case SeColumnDefinition.TYPE_INT32:
    401                    colNames.add( colDef.getName().toUpperCase() );
    402                    colTypes.add( new Integer( Types.INTEGER ) );
    403                    break;
    404                case SeColumnDefinition.TYPE_FLOAT32:
    405                    colNames.add( colDef.getName().toUpperCase() );
    406                    colTypes.add( new Integer( Types.FLOAT ) );
    407                    break;
    408                case SeColumnDefinition.TYPE_FLOAT64:
    409                    colNames.add( colDef.getName().toUpperCase() );
    410                    colTypes.add( new Integer( Types.DOUBLE ) );
    411                    break;
    412                case SeColumnDefinition.TYPE_STRING:
    413                    colNames.add( colDef.getName().toUpperCase() );
    414                    colTypes.add( new Integer( Types.VARCHAR ) );
    415                    break;
    416                case SeColumnDefinition.TYPE_BLOB:
    417                    // there is an open issue with fetching blobs,
    418                    // look at this document:
    419                    // "ArcSDE 8.1 Java API - BLOB columns"
    420                    // http://support.esri.com/Search/KbDocument.asp?dbid=17068
    421                    colNames.add( colDef.getName().toUpperCase() );
    422                    colTypes.add( new Integer( Types.ARRAY ) );
    423                    break;
    424                case SeColumnDefinition.TYPE_DATE:
    425                    colNames.add( colDef.getName().toUpperCase() );
    426                    colTypes.add( new Integer( Types.DATE ) );
    427                    break;
    428                default:
    429                    break;
    430                }
    431            }
    432
    433            String[] colN = new String[colNames.size()];
    434            colN = colNames.toArray( colN );
    435
    436            int[] colT = new int[colTypes.size()];
    437            for ( int i = 0; i < colT.length; i++ ) {
    438                colT[i] = colTypes.get( i ).intValue();
    439            }
    440
    441            try {
    442                deegreeTable = new DefaultTable( layer.getQualifiedName(), colN, colT, 20000 );
    443            } catch ( TableException tex ) {
    444                tex.printStackTrace();
    445                throw new DeegreeSeException( tex.toString() );
    446            }
    447            return deegreeTable;
    448        } // End Method initTable
    449
    450        /**
    451         * CreateGeometry - used with every row of the SpatialQuery Depending on the layers' geometries
    452         * datatype different operations are made to create the appropriate object. <br>
    453         * Available ArcSDE ShapeTypes: <br>
    454         * TYPE_POINT (impl) <br>
    455         * TYPE_MULTI_POINT (impl) <br>
    456         * TYPE_SIMPLE_LINE (impl) <br>
    457         * TYPE_MULTI_SIMPLE_LINE (impl) <br>
    458         * TYPE_LINE (impl) <br>
    459         * TYPE_MULTI_LINE (impl) <br>
    460         * TYPE_POLYGON (impl) <br>
    461         * TYPE_MULTI_POLYGON (impl) <br>
    462         * TYPE_NIL (impl)
    463         *
    464         * <br>
    465         * throws SeException
    466         */
    467        private void createGeometry( SeShape shape, ArrayList<Geometry> list )
    468                                throws SeException, DeegreeSeException {
    469
    470            int shptype = shape.getType();
    471
    472            ArrayList<?> al = shape.getAllPoints( SeShape.TURN_DEFAULT, true );
    473            // Retrieve the array of SDEPoints
    474            SDEPoint[] points = (SDEPoint[]) al.get( 0 );
    475            // Retrieve the part offsets array.
    476            int[] partOffset = (int[]) al.get( 1 );
    477            // Retrieve the sub-part offsets array.
    478            int[] subPartOffset = (int[]) al.get( 2 );
    479
    480            int numPoints = shape.getNumOfPoints();
    481
    482            int numParts = shape.getNumParts();
    483
    484            switch ( shptype ) {
    485            // a single point
    486            case SeShape.TYPE_NIL:
    487                Point gmPoint = GeometryFactory.createPoint( -9E9, -9E9, null );
    488                list.add( gmPoint );
    489                LOG.logInfo( "Found SeShape.TYPE_NIL." );
    490                LOG.logInfo( "The queried layer does not have valid geometries" );
    491                break;
    492            // a single point
    493            case SeShape.TYPE_POINT:
    494                gmPoint = GeometryFactory.createPoint( points[0].getX(), points[0].getY(), null );
    495                list.add( gmPoint );
    496                break;
    497            // an array of points
    498            case SeShape.TYPE_MULTI_POINT:
    499                Point[] gmPoints = new Point[numPoints];
    500
    501                for ( int pt = 0; pt < numPoints; pt++ ) {
    502                    gmPoints[pt] = GeometryFactory.createPoint( points[pt].getX(), points[pt].getY(), null );
    503                }
    504
    505                try {
    506                    MultiPoint gmMultiPoint = GeometryFactory.createMultiPoint( gmPoints );
    507                    list.add( gmMultiPoint );
    508                } catch ( Exception gme ) {
    509                    gme.printStackTrace();
    510                    throw new DeegreeSeException( gme.toString() );
    511                }
    512
    513                break;
    514            // a single line, simple as it does not intersect itself
    515            case SeShape.TYPE_SIMPLE_LINE:
    516                // or a single, non-simple line
    517            case SeShape.TYPE_LINE:
    518
    519                Position[] gmSimpleLinePosition = new Position[numPoints];
    520
    521                for ( int pt = 0; pt < numPoints; pt++ ) {
    522                    gmSimpleLinePosition[pt] = GeometryFactory.createPosition( points[pt].getX(), points[pt].getY() );
    523                }
    524
    525                try {
    526                    Curve gmCurve = GeometryFactory.createCurve( gmSimpleLinePosition, null );
    527                    list.add( gmCurve );
    528                } catch ( Exception gme ) {
    529                    gme.printStackTrace();
    530                    throw new DeegreeSeException( gme.toString() );
    531                }
    532
    533                break;
    534            // an array of lines, simple as they do not intersect with themself
    535            case SeShape.TYPE_MULTI_SIMPLE_LINE:
    536                // or an array of non-simple lines
    537            case SeShape.TYPE_MULTI_LINE:
    538
    539                Curve[] gmCurves = new Curve[numParts];
    540
    541                for ( int partNo = 0; partNo < numParts; partNo++ ) {
    542                    int lastPoint = shape.getNumPoints( partNo + 1, 1 ) + partOffset[partNo];
    543                    Position[] gmMultiSimpleLinePosition = new Position[shape.getNumPoints( partNo + 1, 1 )];
    544                    int i = 0;
    545
    546                    for ( int pt = partOffset[partNo]; pt < lastPoint; pt++ ) {
    547                        gmMultiSimpleLinePosition[i] = GeometryFactory.createPosition( points[pt].getX(), points[pt].getY() );
    548                        i++;
    549                    }
    550
    551                    try {
    552                        gmCurves[partNo] = GeometryFactory.createCurve( gmMultiSimpleLinePosition, null );
    553                    } catch ( Exception gme ) {
    554                        gme.printStackTrace();
    555                        throw new DeegreeSeException( gme.toString() );
    556                    }
    557                }
    558
    559                try {
    560                    MultiCurve gmMultiCurve = GeometryFactory.createMultiCurve( gmCurves );
    561                    list.add( gmMultiCurve );
    562                } catch ( Exception gme ) {
    563                    gme.printStackTrace();
    564                    throw new DeegreeSeException( gme.toString() );
    565                }
    566
    567                break;
    568            // a single polygon which might contain islands
    569            case SeShape.TYPE_POLYGON:
    570
    571                int numSubParts = shape.getNumSubParts( 1 );
    572                Position[] gmPolygonExteriorRing = new Position[shape.getNumPoints( 1, 1 )];
    573
    574                int kk = shape.getNumPoints( 1, 1 );
    575                for ( int pt = 0; pt < kk; pt++ ) {
    576                    gmPolygonExteriorRing[pt] = GeometryFactory.createPosition( points[pt].getX(), points[pt].getY() );
    577                }
    578
    579                Position[][] gmPolygonInteriorRings = null;
    580
    581                // if it is a donut create inner rings
    582                if ( numSubParts > 1 ) {
    583                    gmPolygonInteriorRings = new Position[numSubParts - 1][];
    584
    585                    int j = 0;
    586
    587                    for ( int subPartNo = 1; subPartNo < numSubParts; subPartNo++ ) {
    588                        int lastPoint = shape.getNumPoints( 1, subPartNo + 1 ) + subPartOffset[subPartNo];
    589                        Position[] gmPolygonPosition = new Position[shape.getNumPoints( 1, subPartNo + 1 )];
    590                        int i = 0;
    591
    592                        for ( int pt = subPartOffset[subPartNo]; pt < lastPoint; pt++ ) {
    593                            gmPolygonPosition[i] = GeometryFactory.createPosition( points[pt].getX(), points[pt].getY() );
    594                            i++;
    595                        }
    596
    597                        gmPolygonInteriorRings[j] = gmPolygonPosition;
    598                        j++;
    599                    }
    600                }
    601
    602                try {
    603                    Surface gmSurface = GeometryFactory.createSurface( gmPolygonExteriorRing, gmPolygonInteriorRings,
    604                                                                       new SurfaceInterpolationImpl(), null );
    605                    list.add( gmSurface );
    606                } catch ( Exception gme ) {
    607                    gme.printStackTrace();
    608                    throw new DeegreeSeException( gme.toString() );
    609                }
    610
    611                break;
    612            // an array of polygons which might contain islands
    613            case SeShape.TYPE_MULTI_POLYGON:
    614
    615                Surface[] gmMultiPolygonSurface = getMultiPolygon( shape, points, partOffset, subPartOffset );
    616
    617                try {
    618                    MultiSurface gmMultiSurface = GeometryFactory.createMultiSurface( gmMultiPolygonSurface );
    619                    list.add( gmMultiSurface );
    620                } catch ( Exception gme ) {
    621                    gme.printStackTrace();
    622                    throw new DeegreeSeException( gme.toString() );
    623                }
    624
    625                break;
    626            default:
    627                LOG.logInfo( "Unknown GeometryType - ID: " + shape.getType() );
    628                break;
    629            } // End of switch
    630        } // End Method createGeometry
    631
    632        /**
    633         * @param shape
    634         * @param points
    635         * @param partOffset
    636         * @param subPartOffset
    637         * @throws SeException
    638         */
    639        private Surface[] getMultiPolygon( SeShape shape, SDEPoint[] points, int[] partOffset, int[] subPartOffset )
    640                                throws SeException, DeegreeSeException {
    641            Surface[] surfaces = new Surface[partOffset.length];
    642            int hh = 0;
    643            for ( int i = 0; i < partOffset.length; i++ ) {
    644                // cnt = number of all rings of the current polygon (part)
    645                int cnt = shape.getNumSubParts( i + 1 );
    646
    647                // exterior ring
    648                int count = shape.getNumPoints( i + 1, 1 );
    649                Position[] ex = new Position[count];
    650                int off = subPartOffset[hh];
    651                for ( int j = 0; j < count; j++ ) {
    652                    ex[j] = GeometryFactory.createPosition( points[j + off].getX(), points[j + off].getY() );
    653                }
    654
    655                // interior ring
    656                Position[][] inn = null;
    657                if ( cnt > 1 ) {
    658                    inn = new Position[cnt - 1][];
    659                }
    660                hh++;
    661                for ( int j = 1; j < cnt; j++ ) {
    662                    inn[j - 1] = new Position[shape.getNumPoints( i + 1, j + 1 )];
    663                    off = subPartOffset[hh];
    664                    for ( int k = 0; k < inn[j - 1].length; k++ ) {
    665                        inn[j - 1][k] = GeometryFactory.createPosition( points[j + off - 1].getX(),
    666                                                                        points[j + off - 1].getY() );
    667                    }
    668                    hh++;
    669                }
    670
    671                try {
    672                    SurfaceInterpolation si = new SurfaceInterpolationImpl();
    673                    surfaces[i] = GeometryFactory.createSurface( ex, inn, si, null );
    674                } catch ( Exception e ) {
    675                    throw new DeegreeSeException( StringTools.stackTraceToString( e ) );
    676                }
    677            }
    678
    679            return surfaces;
    680        }
    681
    682    } // End Class SpatialQueryEx