001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 * sq.openConnection(server, instance, database, user, password);<br>
090 * sq.setLayer(layer);<br>
091 * sq.setSpatialFilter(minX, minY, maxX, maxY);<br>
092 * sp.runSpatialQuery();<br>
093 * GM_Object[] deegree_gm_obj = sq.getGeometries();<br>
094 * Table deegree_table = sq.getTable();<br>
095 * 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