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