001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/spatialschema/GMLGeometryAdapter.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 53177 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: klaus.greve@uni-bonn.de 041 042 043 ---------------------------------------------------------------------------*/ 044 package org.deegree.model.spatialschema; 045 046 import java.io.ByteArrayOutputStream; 047 import java.io.OutputStream; 048 import java.io.PrintWriter; 049 import java.io.StringReader; 050 import java.rmi.RemoteException; 051 import java.util.ArrayList; 052 import java.util.HashMap; 053 import java.util.List; 054 import java.util.Map; 055 import java.util.StringTokenizer; 056 057 import org.deegree.framework.log.ILogger; 058 import org.deegree.framework.log.LoggerFactory; 059 import org.deegree.framework.util.StringTools; 060 import org.deegree.framework.xml.ElementList; 061 import org.deegree.framework.xml.NamespaceContext; 062 import org.deegree.framework.xml.XMLFragment; 063 import org.deegree.framework.xml.XMLParsingException; 064 import org.deegree.framework.xml.XMLTools; 065 import org.deegree.i18n.Messages; 066 import org.deegree.model.crs.CRSFactory; 067 import org.deegree.model.crs.CoordinateSystem; 068 import org.deegree.model.crs.UnknownCRSException; 069 import org.deegree.ogcbase.CommonNamespaces; 070 import org.deegree.ogcbase.InvalidGMLException; 071 import org.w3c.dom.Document; 072 import org.w3c.dom.Element; 073 import org.w3c.dom.Node; 074 075 /** 076 * Adapter class for converting GML geometries to deegree geometries and vice versa. Some logical 077 * problems results from the fact that an envelope isn't a geometry according to ISO 19107 (where 078 * the deegree geometry model is based on) but according to GML2/3 specification it is.<br> 079 * So if the wrap(..) method is called with an envelope a <tt>Surface</tt> will be returned 080 * representing the envelops shape. To export an <tt>Envelope</tt> to a GML box/envelope two 081 * specialized export methods are available.<BR> 082 * The export method(s) doesn't return a DOM element as one may expect but a <tt>StringBuffer</tt>. 083 * This is done because the transformation from deegree geometries to GML mainly is required when a 084 * GML representation of a geometry shall be serialized to a file or to a network connection. For 085 * both cases the string representation is required and it is simply faster to create the string 086 * directly instead of first creating a DOM tree that after this must be serialized to a string.<BR> 087 * In future version geometries will be serialized to a stream. 088 * 089 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 090 * @author last edited by: $Author: rbezema $ 091 * 092 * @version $Revision: 11344 $, $Date: 2008-04-22 13:38:48 +0200 (Di, 22 Apr 2008) $ 093 */ 094 public class GMLGeometryAdapter { 095 096 private static final ILogger LOG = LoggerFactory.getLogger( GMLGeometryAdapter.class ); 097 098 private static final NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); 099 100 private static Map<String, CoordinateSystem> crsMap = new HashMap<String, CoordinateSystem>(); 101 102 private static final String COORD = CommonNamespaces.GML_PREFIX + ":coord"; 103 104 private static final String COORDINATES = CommonNamespaces.GML_PREFIX + ":coordinates"; 105 106 private static final String POS = CommonNamespaces.GML_PREFIX + ":pos"; 107 108 private static final String POSLIST = CommonNamespaces.GML_PREFIX + ":posList"; 109 110 /** 111 * Converts the given string representation of a GML geometry object to a corresponding 112 * <code>Geometry</code>. Notice that GML Boxes will be converted to Surfaces because in ISO 113 * 19107 Envelopes are no geometries. 114 * 115 * @param gml 116 * @param srsName 117 * default SRS for the geometry (may be overwritten in geometry elements) 118 * @return corresponding geometry object 119 * @throws GeometryException 120 * @throws XMLParsingException 121 */ 122 public static Geometry wrap( String gml, String srsName ) 123 throws GeometryException, XMLParsingException { 124 StringReader sr = new StringReader( gml ); 125 Document doc = null; 126 try { 127 doc = XMLTools.parse( sr ); 128 } catch ( Exception e ) { 129 LOG.logError( "could not parse: '" + gml + "' as GML/XML", e ); 130 throw new XMLParsingException( "could not parse: '" + gml + "' as GML/XML: " + e.getMessage() ); 131 } 132 return wrap( doc.getDocumentElement(), srsName ); 133 } 134 135 /** 136 * Converts the given DOM representation of a GML geometry to a corresponding 137 * <code>Geometry</code>. Notice that GML Boxes will be converted to Surfaces because in ISO 138 * 19107 Envelopes are no geometries. 139 * <p> 140 * Currently, the following conversions are supported: 141 * <ul> 142 * <li>GML Point -> Point 143 * <li>GML MultiPoint -> MultiPoint 144 * <li>GML LineString -> Curve 145 * <li>GML MultiLineString -> MultiCurve 146 * <li>GML Polygon -> Surface 147 * <li>GML MultiPolygon -> MultiSurface 148 * <li>GML Box -> Surface 149 * <li>GML Curve -> Curve 150 * <li>GML Surface -> Surface 151 * <li>GML MultiCurve -> MultiCurve 152 * <li>GML MultiSurface -> MultiSurface 153 * </ul> 154 * <p> 155 * 156 * @param element 157 * @param srsName 158 * default SRS for the geometry 159 * @return corresponding <code>Geometry</code> instance 160 * @throws GeometryException 161 * if type unsupported or conversion failed 162 */ 163 public static Geometry wrap( Element element, String srsName ) 164 throws GeometryException { 165 166 Geometry geometry = null; 167 try { 168 String name = element.getLocalName(); 169 if ( ( name.equals( "Point" ) ) || ( name.equals( "Center" ) ) ) { 170 geometry = wrapPoint( element, srsName ); 171 } else if ( name.equals( "LineString" ) ) { 172 geometry = wrapLineString( element, srsName ); 173 } else if ( name.equals( "Polygon" ) ) { 174 geometry = wrapPolygon( element, srsName ); 175 } else if ( name.equals( "MultiPoint" ) ) { 176 geometry = wrapMultiPoint( element, srsName ); 177 } else if ( name.equals( "MultiLineString" ) ) { 178 geometry = wrapMultiLineString( element, srsName ); 179 } else if ( name.equals( "MultiPolygon" ) ) { 180 geometry = wrapMultiPolygon( element, srsName ); 181 } else if ( name.equals( "Box" ) || name.equals( "Envelope" ) ) { 182 geometry = wrapBoxAsSurface( element, srsName ); 183 } else if ( name.equals( "Curve" ) ) { 184 geometry = wrapCurveAsCurve( element, srsName ); 185 } else if ( name.equals( "Surface" ) ) { 186 geometry = wrapSurfaceAsSurface( element, srsName ); 187 } else if ( name.equals( "MultiCurve" ) ) { 188 geometry = wrapMultiCurveAsMultiCurve( element, srsName ); 189 } else if ( name.equals( "MultiSurface" ) ) { 190 geometry = wrapMultiSurfaceAsMultiSurface( element, srsName ); 191 } else if ( name.equals( "CompositeSurface" ) ) { 192 geometry = wrapCompositeSurface( element, srsName ); 193 } else { 194 new GeometryException( "Not a supported geometry type: " + name ); 195 } 196 } catch ( Exception e ) { 197 LOG.logError( e.getMessage(), e ); 198 throw new GeometryException( StringTools.stackTraceToString( e ) ); 199 } 200 return geometry; 201 } 202 203 /** 204 * Returns an instance of {@link Envelope} created from the passed <code>gml:Box</code> or 205 * <code>gml:Envelope</code> element. 206 * 207 * @param element 208 * <code>gml:Box</code> or <code>gml:Envelope</code> element 209 * @param srsName 210 * default SRS for the geometry 211 * @return instance of <code>Envelope</code> 212 * @throws XMLParsingException 213 * @throws InvalidGMLException 214 * @throws UnknownCRSException 215 */ 216 public static Envelope wrapBox( Element element, String srsName ) 217 throws XMLParsingException, InvalidGMLException, UnknownCRSException { 218 srsName = findSrsName( element, srsName ); 219 CoordinateSystem crs = null; 220 if ( srsName != null ) { 221 crs = getCRS( srsName ); 222 } 223 Position[] bb = null; 224 List nl = XMLTools.getNodes( element, COORD, nsContext ); 225 if ( nl != null && nl.size() > 0 ) { 226 bb = new Position[2]; 227 bb[0] = createPositionFromCoord( (Element) nl.get( 0 ) ); 228 bb[1] = createPositionFromCoord( (Element) nl.get( 1 ) ); 229 } else { 230 nl = XMLTools.getNodes( element, COORDINATES, nsContext ); 231 if ( nl != null && nl.size() > 0 ) { 232 bb = createPositionFromCoordinates( (Element) nl.get( 0 ) ); 233 } else { 234 nl = XMLTools.getNodes( element, POS, nsContext ); 235 if ( nl != null && nl.size() > 0 ) { 236 bb = new Position[2]; 237 bb[0] = createPositionFromPos( (Element) nl.get( 0 ) ); 238 bb[1] = createPositionFromPos( (Element) nl.get( 1 ) ); 239 } else { 240 Element lowerCorner = (Element) XMLTools.getRequiredNode( element, "gml:lowerCorner", nsContext ); 241 Element upperCorner = (Element) XMLTools.getRequiredNode( element, "gml:upperCorner", nsContext ); 242 bb = new Position[2]; 243 bb[0] = createPositionFromCorner( lowerCorner ); 244 bb[1] = createPositionFromCorner( upperCorner ); 245 } 246 } 247 } 248 Envelope box = GeometryFactory.createEnvelope( bb[0], bb[1], crs ); 249 return box; 250 } 251 252 /** 253 * Returns an instance of {@link Curve} created from the passed <code>gml:Curve</code> 254 * element. 255 * 256 * @param element 257 * <code>gml:Curve</code> element 258 * @param srsName 259 * default SRS for the geometry 260 * @return corresponding Curve instance 261 * @throws XMLParsingException 262 * @throws GeometryException 263 * @throws UnknownCRSException 264 */ 265 protected static Curve wrapCurveAsCurve( Element element, String srsName ) 266 throws XMLParsingException, GeometryException, UnknownCRSException { 267 268 srsName = findSrsName( element, srsName ); 269 CoordinateSystem crs = null; 270 if ( srsName != null ) { 271 crs = getCRS( srsName ); 272 } 273 274 Element segment = (Element) XMLTools.getRequiredNode( element, "gml:segments", nsContext ); 275 CurveSegment[] segments = parseCurveSegments( crs, segment ); 276 277 return GeometryFactory.createCurve( segments, crs ); 278 } 279 280 /** 281 * parses CurveSegments 282 * 283 * @param crs 284 * @param segment 285 * @return CurveSegments 286 * @throws XMLParsingException 287 * @throws GeometryException 288 */ 289 private static CurveSegment[] parseCurveSegments( CoordinateSystem crs, Element segment ) 290 throws XMLParsingException, GeometryException { 291 List<Node> list = XMLTools.getNodes( segment, "child::*", nsContext ); 292 293 CurveSegment[] segments = new CurveSegment[list.size()]; 294 for ( int i = 0; i < list.size(); i++ ) { 295 if ( list.get( i ).getLocalName().equals( "LineStringSegment" ) ) { 296 segments[i] = parseLineStringSegment( (Element) list.get( i ), crs ); 297 } else if ( list.get( i ).getLocalName().equals( "Arc" ) ) { 298 segments[i] = parseArc( (Element) list.get( i ), crs ); 299 } else { 300 throw new GeometryException( "not supported type for a CurveSegment: " + list.get( i ).getLocalName() ); 301 } 302 } 303 return segments; 304 } 305 306 /** 307 * parses an Arc 308 * 309 * @param element 310 * @param crs 311 * @return 312 * @throws GeometryException 313 */ 314 private static CurveSegment parseArc( Element element, CoordinateSystem crs ) 315 throws GeometryException { 316 CurveSegment segment = null; 317 try { 318 Position[] pos = createPositions( element, null ); 319 segment = GeometryFactory.createCurveSegment( pos, crs ); 320 } catch ( Exception e ) { 321 throw new GeometryException( "Error creating segments for the element Arc." ); 322 } 323 return segment; 324 } 325 326 /** 327 * parses a LineStringSegment (linear interpolated CurveSegment) 328 * 329 * @param element 330 * @param crs 331 * @return 332 * @throws GeometryException 333 */ 334 private static CurveSegment parseLineStringSegment( Element element, CoordinateSystem crs ) 335 throws GeometryException { 336 CurveSegment segment = null; 337 try { 338 Position[] pos = createPositions( element, null ); 339 segment = GeometryFactory.createCurveSegment( pos, crs ); 340 } catch ( Exception e ) { 341 throw new GeometryException( "Error creating segments for the element LineStringSegment." ); 342 } 343 return segment; 344 345 } 346 347 /** 348 * Returns an instance of {@link MultiCurve} created from the passed <code>gml:MultiCurve</code> 349 * element. 350 * 351 * @param element 352 * <code>gml:MultiCurve</code> element 353 * @param srsName 354 * default SRS for the geometry 355 * @return <code>MultiCurve</code> instance 356 * @throws XMLParsingException 357 * @throws GeometryException 358 * @throws UnknownCRSException 359 * @throws InvalidGMLException 360 */ 361 protected static MultiCurve wrapMultiCurveAsMultiCurve( Element element, String srsName ) 362 throws XMLParsingException, GeometryException, UnknownCRSException, InvalidGMLException { 363 364 srsName = findSrsName( element, srsName ); 365 CoordinateSystem crs = null; 366 if ( srsName != null ) { 367 crs = getCRS( srsName ); 368 } 369 370 MultiCurve multiCurve = null; 371 try { 372 // gml:curveMember 373 List listCurveMember = XMLTools.getNodes( element, "gml:curveMember", nsContext ); 374 List<Curve> curveList = new ArrayList<Curve>(); 375 if ( listCurveMember.size() > 0 ) { 376 377 for ( int i = 0; i < listCurveMember.size(); i++ ) { 378 Element curveMember = (Element) listCurveMember.get( i ); 379 Element curve = (Element) XMLTools.getNode( curveMember, "gml:Curve", nsContext ); 380 if ( curve != null ) { 381 curveList.add( wrapCurveAsCurve( curve, srsName ) ); 382 } else { 383 curve = (Element) XMLTools.getRequiredNode( curveMember, "gml:LineString", nsContext ); 384 curveList.add( wrapLineString( curve, srsName ) ); 385 } 386 } 387 } 388 Element curveMembers = (Element) XMLTools.getNode( element, "gml:curveMembers", nsContext ); 389 if ( curveMembers != null ) { 390 // gml:curveMembers 391 List listCurves = XMLTools.getNodes( curveMembers, "gml:Curve", nsContext ); 392 if ( listCurves != null ) { 393 for ( int i = 0; i < listCurves.size(); i++ ) { 394 Element curve = (Element) listCurves.get( i ); 395 curveList.add( wrapCurveAsCurve( curve, srsName ) ); 396 } 397 } 398 listCurves = XMLTools.getNodes( curveMembers, "gml:LineString", nsContext ); 399 if ( listCurves != null ) { 400 for ( int i = 0; i < listCurves.size(); i++ ) { 401 Element curve = (Element) listCurves.get( i ); 402 curveList.add( wrapLineString( curve, srsName ) ); 403 } 404 } 405 } 406 Curve[] curves = new Curve[curveList.size()]; 407 multiCurve = GeometryFactory.createMultiCurve( curveList.toArray( curves ), crs ); 408 } catch ( XMLParsingException e ) { 409 LOG.logError( e.getMessage(), e ); 410 throw new XMLParsingException( "Error parsing <gml:curveMember> elements. Please check the xml document." ); 411 } catch ( GeometryException e ) { 412 LOG.logError( e.getMessage(), e ); 413 throw new GeometryException( 414 "Error creating a curve from the curve element. Please check the GML specifications " 415 + "for correct element declaration." ); 416 } 417 return multiCurve; 418 } 419 420 /** 421 * Returns an instance of {@link Surface} created from the passed <code>gml:Surface</code> 422 * element. 423 * 424 * @param element 425 * @param srsName 426 * default SRS for the geometry 427 * @return Surface 428 * @throws XMLParsingException 429 * @throws GeometryException 430 * @throws UnknownCRSException 431 */ 432 protected static Surface wrapSurfaceAsSurface( Element element, String srsName ) 433 throws XMLParsingException, GeometryException, UnknownCRSException { 434 435 srsName = findSrsName( element, srsName ); 436 CoordinateSystem crs = null; 437 if ( srsName != null ) { 438 crs = getCRS( srsName ); 439 } 440 441 Element patches = extractPatches( element ); 442 List<Element> polygonList = XMLTools.getRequiredElements( patches, "gml:Polygon | gml:PolygonPatch", nsContext ); 443 444 SurfacePatch[] surfacePatches = new SurfacePatch[polygonList.size()]; 445 446 for ( int i = 0; i < polygonList.size(); i++ ) { 447 Curve exteriorRing = null; 448 Element polygon = polygonList.get( i ); 449 try { 450 Element exterior = (Element) XMLTools.getNode( polygon, "gml:exterior | gml:outerBounderyIs", nsContext ); 451 if ( exterior != null ) { 452 exteriorRing = parseRing( crs, exterior ); 453 } else { 454 String msg = Messages.getMessage( "GEOM_SURFACE_NO_EXTERIOR_RING" ); 455 throw new XMLParsingException( msg ); 456 } 457 458 List<Element> interiorList = XMLTools.getElements( polygon, "gml:interior | gml:outerBounderyIs", 459 nsContext ); 460 Curve[] interiorRings = null; 461 if ( interiorList != null && interiorList.size() > 0 ) { 462 463 interiorRings = new Curve[interiorList.size()]; 464 465 for ( int j = 0; j < interiorRings.length; j++ ) { 466 Element interior = interiorList.get( j ); 467 interiorRings[j] = parseRing( crs, interior ); 468 } 469 } 470 surfacePatches[i] = GeometryFactory.createSurfacePatch( exteriorRing, interiorRings, crs ); 471 } catch ( InvalidGMLException e ) { 472 LOG.logError( e.getMessage(), e ); 473 throw new XMLParsingException( "Error parsing the polygon element '" + polygon.getNodeName() 474 + "' to create a surface geometry." ); 475 } 476 477 } 478 Surface surface = null; 479 try { 480 surface = GeometryFactory.createSurface( surfacePatches, crs ); 481 } catch ( GeometryException e ) { 482 throw new GeometryException( "Error creating a surface from '" + surfacePatches.length + "' polygons." ); 483 } 484 return surface; 485 } 486 487 private static String findSrsName( Element element, String srsName ) 488 throws XMLParsingException { 489 Node elem = element; 490 while ( srsName == null && elem != null ) { 491 srsName = XMLTools.getNodeAsString( elem, "@srsName", nsContext, srsName ); 492 elem = elem.getParentNode(); 493 } 494 elem = element; 495 if ( srsName == null ) { 496 srsName = XMLTools.getNodeAsString( elem, "//@srsName", nsContext, srsName ); 497 } 498 return srsName; 499 } 500 501 /** 502 * parses a ring; a ring may is a gml:LinearRing or a gml:Ring 503 * 504 * @param crs 505 * @param parent 506 * parent of a gml:LinearRing or gml:Ring 507 * @return curves of a ring 508 * @throws XMLParsingException 509 * @throws InvalidGMLException 510 * @throws GeometryException 511 */ 512 private static Curve parseRing( CoordinateSystem crs, Element parent ) 513 throws XMLParsingException, InvalidGMLException, GeometryException { 514 String srsName = null; 515 if ( crs != null ) { 516 srsName = crs.getName(); 517 } 518 List<CurveSegment> curveMembers = null; 519 Element ring = (Element) XMLTools.getNode( parent, "gml:LinearRing", nsContext ); 520 if ( ring != null ) { 521 Position[] exteriorRing = createPositions( ring, srsName ); 522 curveMembers = new ArrayList<CurveSegment>(); 523 curveMembers.add( GeometryFactory.createCurveSegment( exteriorRing, crs ) ); 524 } else { 525 List<Node> members = XMLTools.getRequiredNodes( parent, "gml:Ring/gml:curveMember/child::*", nsContext ); 526 curveMembers = new ArrayList<CurveSegment>( members.size() ); 527 for ( Node node : members ) { 528 Curve curve = (Curve) wrap( (Element) node, srsName ); 529 CurveSegment[] tmp = curve.getCurveSegments(); 530 for ( int i = 0; i < tmp.length; i++ ) { 531 curveMembers.add( tmp[i] ); 532 } 533 } 534 } 535 CurveSegment[] cs = curveMembers.toArray( new CurveSegment[curveMembers.size()] ); 536 537 return GeometryFactory.createCurve( cs ); 538 } 539 540 /** 541 * Returns an instance of {@link MultiSurface} created from the passed 542 * <code>gml:MultiSurface</code> element. 543 * 544 * @param element 545 * <code>gml:MultiSurface</code> element 546 * @param srsName 547 * default SRS for the geometry 548 * @return MultiSurface 549 * @throws XMLParsingException 550 * @throws GeometryException 551 * @throws InvalidGMLException 552 * @throws UnknownCRSException 553 */ 554 protected static MultiSurface wrapMultiSurfaceAsMultiSurface( Element element, String srsName ) 555 throws XMLParsingException, GeometryException, InvalidGMLException, UnknownCRSException { 556 557 srsName = findSrsName( element, srsName ); 558 CoordinateSystem crs = null; 559 if ( srsName != null ) { 560 crs = getCRS( srsName ); 561 } 562 MultiSurface multiSurface = null; 563 try { 564 List<Surface> surfaceList = new ArrayList<Surface>(); 565 // gml:surfaceMember 566 List listSurfaceMember = XMLTools.getNodes( element, "gml:surfaceMember", nsContext ); 567 if ( listSurfaceMember != null ) { 568 for ( int i = 0; i < listSurfaceMember.size(); i++ ) { 569 Element surfaceMember = (Element) listSurfaceMember.get( i ); 570 Element surface = (Element) XMLTools.getNode( surfaceMember, "gml:Surface", nsContext ); 571 if ( surface != null ) { 572 surfaceList.add( wrapSurfaceAsSurface( surface, srsName ) ); 573 } else { 574 surface = (Element) XMLTools.getRequiredNode( surfaceMember, ".//gml:Polygon", nsContext ); 575 surfaceList.add( wrapPolygon( surface, srsName ) ); 576 } 577 } 578 } 579 580 Element surfaceMembers = (Element) XMLTools.getNode( element, "gml:surfaceMembers", nsContext ); 581 if ( surfaceMembers != null ) { 582 // gml:surfaceMembers 583 584 List listSurfaces = XMLTools.getNodes( surfaceMembers, "gml:Surface", nsContext ); 585 if ( listSurfaces != null ) { 586 for ( int i = 0; i < listSurfaces.size(); i++ ) { 587 Element surface = (Element) listSurfaces.get( i ); 588 surfaceList.add( wrapSurfaceAsSurface( surface, srsName ) ); 589 } 590 } 591 592 listSurfaces = XMLTools.getNodes( surfaceMembers, ".//gml:Polygon", nsContext ); 593 if ( listSurfaces != null ) { 594 for ( int i = 0; i < listSurfaces.size(); i++ ) { 595 Element surface = (Element) listSurfaces.get( i ); 596 surfaceList.add( wrapPolygon( surface, srsName ) ); 597 } 598 } 599 } 600 Surface[] surfaces = new Surface[surfaceList.size()]; 601 surfaces = surfaceList.toArray( surfaces ); 602 multiSurface = GeometryFactory.createMultiSurface( surfaces, crs ); 603 } catch ( XMLParsingException e ) { 604 LOG.logError( e.getMessage(), e ); 605 String msg = Messages.getMessage( "GEOM_MULTISURFACE_PARSING_ERROR" ); 606 throw new XMLParsingException( msg ); 607 } catch ( GeometryException e ) { 608 LOG.logError( e.getMessage(), e ); 609 String msg = Messages.getMessage( "GEOM_MULTISURFACE_FORMAT_ERROR" ); 610 throw new GeometryException( msg ); 611 } 612 return multiSurface; 613 } 614 615 /** 616 * Returns a {@link Point} instance created from the passed <code>gml:Point</code> element. 617 * 618 * @param element 619 * <code>gml:Point</code> element 620 * @param srsName 621 * default SRS for the geometry 622 * @return instance of Point 623 * @throws XMLParsingException 624 * @throws UnknownCRSException 625 */ 626 private static Point wrapPoint( Element element, String srsName ) 627 throws XMLParsingException, InvalidGMLException, UnknownCRSException { 628 629 srsName = findSrsName( element, srsName ); 630 CoordinateSystem crs = null; 631 if ( srsName != null ) { 632 crs = getCRS( srsName ); 633 } 634 635 Position[] bb = null; 636 List nl = XMLTools.getNodes( element, COORD, nsContext ); 637 if ( nl != null && nl.size() > 0 ) { 638 bb = new Position[1]; 639 bb[0] = createPositionFromCoord( (Element) nl.get( 0 ) ); 640 } else { 641 nl = XMLTools.getNodes( element, COORDINATES, nsContext ); 642 if ( nl != null && nl.size() > 0 ) { 643 bb = createPositionFromCoordinates( (Element) nl.get( 0 ) ); 644 } else { 645 nl = XMLTools.getNodes( element, POS, nsContext ); 646 bb = new Position[1]; 647 bb[0] = createPositionFromPos( (Element) nl.get( 0 ) ); 648 } 649 } 650 Point point = GeometryFactory.createPoint( bb[0], crs ); 651 return point; 652 } 653 654 /** 655 * Returns a {@link Curve} instance created from the passed <code>gml:LineString</code> 656 * element. 657 * 658 * @param element 659 * <code>gml:LineString</code> element 660 * @param srsName 661 * default SRS for the geometry 662 * @return instance of Curve 663 * @throws XMLParsingException 664 * @throws UnknownCRSException 665 */ 666 private static Curve wrapLineString( Element element, String srsName ) 667 throws XMLParsingException, GeometryException, InvalidGMLException, UnknownCRSException { 668 669 srsName = findSrsName( element, srsName ); 670 CoordinateSystem crs = null; 671 if ( srsName != null ) { 672 crs = getCRS( srsName ); 673 } 674 Position[] pos = createPositions( element, srsName ); 675 Curve curve = GeometryFactory.createCurve( pos, crs ); 676 return curve; 677 } 678 679 /** 680 * Returns a {@link Surface} instance created from the passed <code>gml:Polygon</code> 681 * element. 682 * 683 * @param element 684 * <code>gml:Polygon</code> element 685 * @param srsName 686 * default SRS for the geometry 687 * @return instance of Surface 688 * @throws XMLParsingException 689 * @throws UnknownCRSException 690 */ 691 private static Surface wrapPolygon( Element element, String srsName ) 692 throws XMLParsingException, GeometryException, InvalidGMLException, UnknownCRSException { 693 694 srsName = findSrsName( element, srsName ); 695 CoordinateSystem crs = null; 696 if ( srsName != null ) { 697 crs = getCRS( srsName ); 698 } 699 700 List nl = XMLTools.getNodes( element, CommonNamespaces.GML_PREFIX + ":outerBoundaryIs", nsContext ); 701 if ( nl == null || nl.size() == 0 ) { 702 nl = XMLTools.getRequiredNodes( element, CommonNamespaces.GML_PREFIX + ":exterior", nsContext ); 703 } 704 Element outs = (Element) nl.get( 0 ); 705 nl = XMLTools.getRequiredNodes( outs, CommonNamespaces.GML_PREFIX + ":LinearRing", nsContext ); 706 Element ring = (Element) nl.get( 0 ); 707 nl = XMLTools.getNodes( ring, COORDINATES, nsContext ); 708 Position[] outerRing = createPositions( ring, srsName ); 709 710 Position[][] innerRings = null; 711 List inns = XMLTools.getNodes( element, CommonNamespaces.GML_PREFIX + ":innerBoundaryIs", nsContext ); 712 if ( inns == null || inns.size() == 0 ) { 713 inns = XMLTools.getNodes( element, CommonNamespaces.GML_PREFIX + ":interior", nsContext ); 714 } 715 if ( inns != null && inns.size() > 0 ) { 716 innerRings = new Position[inns.size()][]; 717 for ( int i = 0; i < innerRings.length; i++ ) { 718 719 nl = XMLTools.getRequiredNodes( (Node) inns.get( i ), CommonNamespaces.GML_PREFIX + ":LinearRing", 720 nsContext ); 721 722 ring = (Element) nl.get( 0 ); 723 innerRings[i] = createPositions( ring, srsName ); 724 } 725 } 726 727 SurfaceInterpolation si = new SurfaceInterpolationImpl(); 728 Surface surface = GeometryFactory.createSurface( outerRing, innerRings, si, crs ); 729 return surface; 730 } 731 732 /** 733 * Returns a {@link MultiPoint} instance created from the passed <code>gml:MultiPoint</code> 734 * element. 735 * 736 * @param element 737 * <code>gml:MultiPoint</code> element 738 * @param srsName 739 * default SRS for the geometry 740 * @return instance of MultiPoint 741 * @throws XMLParsingException 742 * @throws UnknownCRSException 743 */ 744 private static MultiPoint wrapMultiPoint( Element element, String srsName ) 745 throws XMLParsingException, InvalidGMLException, UnknownCRSException { 746 747 srsName = findSrsName( element, srsName ); 748 CoordinateSystem crs = null; 749 if ( srsName != null ) { 750 crs = getCRS( srsName ); 751 } 752 753 List<Point> pointList = new ArrayList<Point>(); 754 List listPointMember = XMLTools.getNodes( element, "gml:pointMember", nsContext ); 755 if ( listPointMember != null ) { 756 for ( int i = 0; i < listPointMember.size(); i++ ) { 757 Element pointMember = (Element) listPointMember.get( i ); 758 Element point = (Element) XMLTools.getNode( pointMember, "gml:Point", nsContext ); 759 pointList.add( wrapPoint( point, srsName ) ); 760 } 761 } 762 763 Element pointMembers = (Element) XMLTools.getNode( element, "gml:pointMembers", nsContext ); 764 if ( pointMembers != null ) { 765 List pointElems = XMLTools.getNodes( pointMembers, "gml:Point", nsContext ); 766 for ( int j = 0; j < pointElems.size(); j++ ) { 767 pointList.add( wrapPoint( (Element) pointElems.get( j ), srsName ) ); 768 } 769 } 770 771 Point[] points = new Point[pointList.size()]; 772 return GeometryFactory.createMultiPoint( pointList.toArray( points ), crs ); 773 774 } 775 776 /** 777 * Returns a {@link MultiCurve} instance created from the passed 778 * <code>gml:MultiLineString</code> element. 779 * 780 * @param element 781 * <code>gml:MultiLineString</code> element 782 * @param srsName 783 * default SRS for the geometry 784 * @return instance of MultiCurve 785 * @throws XMLParsingException 786 * @throws UnknownCRSException 787 */ 788 private static MultiCurve wrapMultiLineString( Element element, String srsName ) 789 throws XMLParsingException, GeometryException, InvalidGMLException, UnknownCRSException { 790 791 srsName = findSrsName( element, srsName ); 792 CoordinateSystem crs = null; 793 if ( srsName != null ) { 794 crs = getCRS( srsName ); 795 } 796 797 ElementList el = XMLTools.getChildElements( "lineStringMember", CommonNamespaces.GMLNS, element ); 798 Curve[] curves = new Curve[el.getLength()]; 799 for ( int i = 0; i < curves.length; i++ ) { 800 curves[i] = wrapLineString( XMLTools.getFirstChildElement( el.item( i ) ), srsName ); 801 } 802 MultiCurve mp = GeometryFactory.createMultiCurve( curves, crs ); 803 return mp; 804 } 805 806 /** 807 * Returns a {@link MultiSurface} instance created from the passed <code>gml:MultiPolygon</code> 808 * element. 809 * 810 * @param element 811 * <code>gml:MultiPolygon</code> element 812 * @param srsName 813 * default SRS for the geometry 814 * @return instance of MultiCurve 815 * 816 * @throws XMLParsingException 817 * @throws UnknownCRSException 818 */ 819 private static MultiSurface wrapMultiPolygon( Element element, String srsName ) 820 throws XMLParsingException, GeometryException, InvalidGMLException, UnknownCRSException { 821 822 srsName = findSrsName( element, srsName ); 823 CoordinateSystem crs = null; 824 if ( srsName != null ) { 825 crs = getCRS( srsName ); 826 } 827 828 ElementList el = XMLTools.getChildElements( "polygonMember", CommonNamespaces.GMLNS, element ); 829 Surface[] surfaces = new Surface[el.getLength()]; 830 for ( int i = 0; i < surfaces.length; i++ ) { 831 surfaces[i] = wrapPolygon( XMLTools.getFirstChildElement( el.item( i ) ), srsName ); 832 } 833 return GeometryFactory.createMultiSurface( surfaces, crs ); 834 } 835 836 /** 837 * Returns a <code>Surface</code> created from the given <code>gml:Box</code> element. This 838 * method is useful because an Envelope that would normally be created from a Box isn't a 839 * geometry in context of ISO 19107. 840 * 841 * @param element 842 * <code>gml:Box</code> element 843 * @return instance of <code>Surface</code> 844 * @throws XMLParsingException 845 * @throws UnknownCRSException 846 */ 847 private static Surface wrapBoxAsSurface( Element element, String srsName ) 848 throws XMLParsingException, GeometryException, InvalidGMLException, UnknownCRSException { 849 Envelope env = wrapBox( element, srsName ); 850 return GeometryFactory.createSurface( env, env.getCoordinateSystem() ); 851 } 852 853 /** 854 * Returns an instance of {@link CompositeSurface} created from the passed 855 * <code>gml:CompositeSurface</code> element. 856 * 857 * TODO 858 * 859 * @param element 860 * @param srsName 861 * default SRS for the geometry 862 * @return CompositeSurface 863 * @throws GeometryException 864 */ 865 private static CompositeSurface wrapCompositeSurface( Element element, String srsName ) { 866 throw new UnsupportedOperationException( 867 "#wrapCompositeSurface(Element) is not implemented as yet. Work in Progress." ); 868 } 869 870 /** 871 * Extract the <gml:patches> node from a <gml:Surface> element. 872 * 873 * @param surface 874 * @return Element 875 * @throws XMLParsingException 876 */ 877 private static Element extractPatches( Element surface ) 878 throws XMLParsingException { 879 Element patches = null; 880 try { 881 patches = (Element) XMLTools.getRequiredNode( surface, "gml:patches", nsContext ); 882 } catch ( XMLParsingException e ) { 883 throw new XMLParsingException( "Error retrieving the patches element from the surface element." ); 884 } 885 return patches; 886 } 887 888 /** 889 * returns an instance of CS_CoordinateSystem corrsponding to the passed crs name 890 * 891 * @param name 892 * name of the crs 893 * 894 * @return CS_CoordinateSystem 895 * @throws UnknownCRSException 896 */ 897 private static CoordinateSystem getCRS( String name ) 898 throws UnknownCRSException { 899 900 if ( ( name != null ) && ( name.length() > 2 ) ) { 901 if ( name.startsWith( "http://www.opengis.net/gml/srs/" ) ) { 902 // as declared in the GML 2.1.1 specification 903 // http://www.opengis.net/gml/srs/epsg.xml#4326 904 int p = name.lastIndexOf( "/" ); 905 906 if ( p >= 0 ) { 907 name = name.substring( p, name.length() ); 908 p = name.indexOf( "." ); 909 910 String s1 = name.substring( 1, p ).toUpperCase(); 911 p = name.indexOf( "#" ); 912 913 String s2 = name.substring( p + 1, name.length() ); 914 name = s1 + ":" + s2; 915 } 916 } 917 } 918 919 CoordinateSystem crs = crsMap.get( name ); 920 if ( crs == null ) { 921 crs = CRSFactory.create( name ); 922 crsMap.put( name, crs ); 923 } 924 return crs; 925 } 926 927 private static Position createPositionFromCorner( Element corner ) 928 throws InvalidGMLException { 929 930 String tmp = XMLTools.getAttrValue( corner, null, "dimension", null ); 931 int dim = 0; 932 if ( tmp != null ) { 933 dim = Integer.parseInt( tmp ); 934 } 935 tmp = XMLTools.getStringValue( corner ); 936 double[] vals = StringTools.toArrayDouble( tmp, ", " ); 937 if ( dim != 0 ) { 938 if ( vals.length != dim ) { 939 throw new InvalidGMLException( "dimension must be equal to the number of coordinate values defined " 940 + "in pos element." ); 941 } 942 } else { 943 dim = vals.length; 944 } 945 946 Position pos = null; 947 if ( dim == 3 ) { 948 pos = GeometryFactory.createPosition( vals[0], vals[1], vals[2] ); 949 } else { 950 pos = GeometryFactory.createPosition( vals[0], vals[1] ); 951 } 952 953 return pos; 954 955 } 956 957 /** 958 * returns an instance of Position created from the passed coord 959 * 960 * @param element 961 * <coord> 962 * 963 * @return instance of <tt>Position</tt> 964 * 965 * @throws XMLParsingException 966 */ 967 private static Position createPositionFromCoord( Element element ) 968 throws XMLParsingException { 969 970 Position pos = null; 971 Element elem = XMLTools.getRequiredChildElement( "X", CommonNamespaces.GMLNS, element ); 972 double x = Double.parseDouble( XMLTools.getStringValue( elem ) ); 973 elem = XMLTools.getRequiredChildElement( "Y", CommonNamespaces.GMLNS, element ); 974 double y = Double.parseDouble( XMLTools.getStringValue( elem ) ); 975 elem = XMLTools.getChildElement( "Z", CommonNamespaces.GMLNS, element ); 976 977 if ( elem != null ) { 978 double z = Double.parseDouble( XMLTools.getStringValue( elem ) ); 979 pos = GeometryFactory.createPosition( new double[] { x, y, z } ); 980 } else { 981 pos = GeometryFactory.createPosition( new double[] { x, y } ); 982 } 983 984 return pos; 985 } 986 987 /** 988 * returns an array of Positions created from the passed coordinates 989 * 990 * @param element 991 * <coordinates> 992 * 993 * @return instance of <tt>Position[]</tt> 994 * 995 * @throws XMLParsingException 996 */ 997 private static Position[] createPositionFromCoordinates( Element element ) { 998 999 Position[] points = null; 1000 // fixing the failure coming from the usage of the xmltools.getAttrib method 1001 String ts = XMLTools.getAttrValue( element, null, "ts", " " ); 1002 1003 // not used because javas current decimal seperator will be used 1004 // String ds = XMLTools.getAttrValue( element, null, "decimal", "." ); 1005 String cs = XMLTools.getAttrValue( element, null, "cs", "," ); 1006 1007 String value = XMLTools.getStringValue( element ).trim(); 1008 1009 // first tokenizer, tokens the tuples 1010 StringTokenizer tuple = new StringTokenizer( value, ts ); 1011 points = new Position[tuple.countTokens()]; 1012 int i = 0; 1013 while ( tuple.hasMoreTokens() ) { 1014 String s = tuple.nextToken(); 1015 // second tokenizer, tokens the coordinates 1016 StringTokenizer coort = new StringTokenizer( s, cs ); 1017 double[] p = new double[coort.countTokens()]; 1018 1019 for ( int k = 0; k < p.length; k++ ) { 1020 s = coort.nextToken(); 1021 p[k] = Double.parseDouble( s ); 1022 } 1023 1024 points[i++] = GeometryFactory.createPosition( p ); 1025 } 1026 1027 return points; 1028 } 1029 1030 /** 1031 * creates a <tt>Point</tt> from the passed <pos> element containing a GML pos. 1032 * 1033 * @param element 1034 * @return created <tt>Point</tt> 1035 * @throws XMLParsingException 1036 * @throws InvalidGMLException 1037 */ 1038 private static Position createPositionFromPos( Element element ) 1039 throws InvalidGMLException { 1040 1041 String tmp = XMLTools.getAttrValue( element, null, "dimension", null ); 1042 int dim = 0; 1043 if ( tmp != null ) { 1044 dim = Integer.parseInt( tmp ); 1045 } 1046 tmp = XMLTools.getStringValue( element ); 1047 double[] vals = StringTools.toArrayDouble( tmp, "\t\n\r\f ," ); 1048 if ( vals != null ) { 1049 if ( dim != 0 ) { 1050 if ( vals.length != dim ) { 1051 throw new InvalidGMLException( "dimension must be equal to the number of " 1052 + "coordinate values defined in pos element." ); 1053 } 1054 } else { 1055 dim = vals.length; 1056 } 1057 } else { 1058 throw new InvalidGMLException( "The given element {" + element.getNamespaceURI() + "}" 1059 + element.getLocalName() 1060 + " does not contain any coordinates, this may not be!" ); 1061 } 1062 1063 Position pos = null; 1064 if ( dim == 3 ) { 1065 pos = GeometryFactory.createPosition( vals[0], vals[1], vals[2] ); 1066 } else { 1067 pos = GeometryFactory.createPosition( vals[0], vals[1] ); 1068 } 1069 1070 return pos; 1071 } 1072 1073 /** 1074 * 1075 * @param element 1076 * @return Position 1077 * @throws InvalidGMLException 1078 * @throws XMLParsingException 1079 */ 1080 private static Position[] createPositionFromPosList( Element element, String srsName ) 1081 throws InvalidGMLException, XMLParsingException { 1082 1083 Node elem = element; 1084 while ( srsName == null && elem != null ) { 1085 srsName = XMLTools.getNodeAsString( elem, "@srsName", nsContext, srsName ); 1086 elem = elem.getParentNode(); 1087 } 1088 1089 String srsDimension = XMLTools.getAttrValue( element, null, "srsDimension", null ); 1090 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 1091 XMLFragment doc = new XMLFragment( element ); 1092 System.out.println( doc.getAsPrettyString() ); 1093 } 1094 int dim = 0; 1095 if ( srsDimension != null ) { 1096 dim = Integer.parseInt( srsDimension ); 1097 } 1098 if ( dim == 0 ) { 1099 // TODO 1100 // determine dimension from CRS 1101 // default dimension set. 1102 dim = 2; 1103 1104 } 1105 1106 String axisLabels = XMLTools.getAttrValue( element, null, "gml:axisAbbrev", null ); 1107 1108 String uomLabels = XMLTools.getAttrValue( element, null, "uomLabels", null ); 1109 1110 if ( srsName == null ) { 1111 if ( srsDimension != null ) { 1112 throw new InvalidGMLException( 1113 "Attribute srsDimension cannot be defined unless attribute srsName has been defined." ); 1114 } 1115 if ( axisLabels != null ) { 1116 throw new InvalidGMLException( 1117 "Attribute axisLabels cannot be defined unless attribute srsName has been defined." ); 1118 } 1119 1120 } 1121 if ( axisLabels == null ) { 1122 if ( uomLabels != null ) { 1123 throw new InvalidGMLException( 1124 "Attribute uomLabels cannot be defined unless attribute axisLabels has been defined." ); 1125 } 1126 } 1127 String tmp = XMLTools.getStringValue( element ); 1128 double[] values = StringTools.toArrayDouble( tmp, "\t\n\r\f ," ); 1129 int size = values.length / dim; 1130 LOG.logDebug( "Number of points = ", size ); 1131 LOG.logDebug( "Size of the original array: ", values.length ); 1132 LOG.logDebug( "Dimension: ", dim ); 1133 1134 if ( values.length < 4 ) { 1135 throw new InvalidGMLException( "A point list must have minimum 2 coordinate tuples. Here only '" + size 1136 + "' are defined." ); 1137 } 1138 double positions[][] = new double[size][dim]; 1139 int a = 0, b = 0; 1140 for ( int i = 0; i < values.length; i++ ) { 1141 if ( b == dim ) { 1142 a++; 1143 b = 0; 1144 } 1145 positions[a][b] = values[i]; 1146 b++; 1147 } 1148 1149 Position[] position = new Position[positions.length]; 1150 for ( int i = 0; i < positions.length; i++ ) { 1151 double[] vals = positions[i]; 1152 if ( dim == 3 ) { 1153 position[i] = GeometryFactory.createPosition( vals[0], vals[1], vals[2] ); 1154 } else { 1155 position[i] = GeometryFactory.createPosition( vals[0], vals[1] ); 1156 } 1157 } 1158 1159 return position; 1160 1161 } 1162 1163 /** 1164 * creates an array of <tt>Position</tt>s from the <coordinates> or <pos> Elements located as 1165 * children under the passed parent element. 1166 * <p> 1167 * example:<br> 1168 * 1169 * <pre> 1170 * <gml:Box> 1171 * <gml:coordinates cs="," decimal="." ts=" ">0,0 4000,4000</gml:coordinates> 1172 * </gml:Box> 1173 * </pre> 1174 * 1175 * </p> 1176 * 1177 * @param parent 1178 * @param srsName 1179 * @return 1180 * @throws XMLParsingException 1181 * @throws InvalidGMLException 1182 */ 1183 private static Position[] createPositions( Element parent, String srsName ) 1184 throws XMLParsingException, InvalidGMLException { 1185 1186 List nl = XMLTools.getNodes( parent, COORDINATES, nsContext ); 1187 Position[] pos = null; 1188 if ( nl != null && nl.size() > 0 ) { 1189 pos = createPositionFromCoordinates( (Element) nl.get( 0 ) ); 1190 } else { 1191 nl = XMLTools.getNodes( parent, POS, nsContext ); 1192 if ( nl != null && nl.size() > 0 ) { 1193 pos = new Position[nl.size()]; 1194 for ( int i = 0; i < pos.length; i++ ) { 1195 pos[i] = createPositionFromPos( (Element) nl.get( i ) ); 1196 } 1197 } else { 1198 Element posList = (Element) XMLTools.getRequiredNode( parent, POSLIST, nsContext ); 1199 if ( posList != null ) { 1200 pos = createPositionFromPosList( posList, srsName ); 1201 } 1202 } 1203 } 1204 return pos; 1205 } 1206 1207 /** 1208 * Creates a GML representation from the passed <code>Geometry<code> 1209 * 1210 * @param geometry 1211 * @param target 1212 * @throws GeometryException 1213 */ 1214 public static PrintWriter export( Geometry geometry, OutputStream target ) 1215 throws GeometryException { 1216 1217 PrintWriter printwriter = new PrintWriter( target ); 1218 1219 if ( geometry instanceof SurfacePatch ) { 1220 geometry = new SurfaceImpl( (SurfacePatch) geometry ); 1221 } else if ( geometry instanceof LineString ) { 1222 geometry = new CurveImpl( (LineString) geometry ); 1223 } 1224 // create geometries from the wkb considering the geomerty typ 1225 if ( geometry instanceof Point ) { 1226 exportPoint( (Point) geometry, printwriter ); 1227 } else if ( geometry instanceof Curve ) { 1228 exportCurve( (Curve) geometry, printwriter ); 1229 } else if ( geometry instanceof Surface ) { 1230 exportSurface( (Surface) geometry, printwriter ); 1231 } else if ( geometry instanceof MultiPoint ) { 1232 exportMultiPoint( (MultiPoint) geometry, printwriter ); 1233 } else if ( geometry instanceof MultiCurve ) { 1234 exportMultiCurve( (MultiCurve) geometry, printwriter ); 1235 } else if ( geometry instanceof MultiSurface ) { 1236 exportMultiSurface( (MultiSurface) geometry, printwriter ); 1237 } 1238 printwriter.flush(); 1239 return printwriter; 1240 } 1241 1242 /** 1243 * Creates a GML representation from the passed <code>Geometry</code>. 1244 * 1245 * @param geometry 1246 * @return a string buffer containing the XML 1247 * @throws GeometryException 1248 */ 1249 public static StringBuffer export( Geometry geometry ) 1250 throws GeometryException { 1251 1252 ByteArrayOutputStream bos = new ByteArrayOutputStream( 5000 ); 1253 1254 export( geometry, bos ); 1255 1256 return new StringBuffer( new String( bos.toByteArray() ) ); 1257 } 1258 1259 /** 1260 * creates a GML representation from the passed <tt>Envelope</tt>. This method is required 1261 * because in ISO 19107 Envelops are no geometries. 1262 * 1263 * @param envelope 1264 * @return 1265 * @throws GeometryException 1266 */ 1267 public static StringBuffer exportAsBox( Envelope envelope ) { 1268 1269 StringBuffer sb = new StringBuffer( "<gml:Box xmlns:gml='http://www.opengis.net/gml'>" ); 1270 sb.append( "<gml:coordinates cs=\",\" decimal=\".\" ts=\" \">" ); 1271 sb.append( envelope.getMin().getX() ).append( ',' ); 1272 sb.append( envelope.getMin().getY() ); 1273 int dim = envelope.getMax().getCoordinateDimension(); 1274 if ( dim == 3 ) { 1275 sb.append( ',' ).append( envelope.getMin().getZ() ); 1276 } 1277 sb.append( ' ' ).append( envelope.getMax().getX() ); 1278 sb.append( ',' ).append( envelope.getMax().getY() ); 1279 if ( dim == 3 ) { 1280 sb.append( ',' ).append( envelope.getMax().getZ() ); 1281 } 1282 sb.append( "</gml:coordinates></gml:Box>" ); 1283 1284 return sb; 1285 } 1286 1287 /** 1288 * creates a GML representation from the passed <tt>Envelope</tt>. This method is required 1289 * because in ISO 19107 Envelops are no geometries. 1290 * 1291 * @param envelope 1292 * @return 1293 * @throws GeometryException 1294 */ 1295 public static StringBuffer exportAsEnvelope( Envelope envelope ) { 1296 1297 StringBuffer sb = new StringBuffer( "<gml:Envelope " ); 1298 sb.append( "xmlns:gml='http://www.opengis.net/gml'>" ); 1299 sb.append( "<gml:coordinates cs=\",\" decimal=\".\" ts=\" \">" ); 1300 sb.append( envelope.getMin().getX() ).append( ',' ); 1301 sb.append( envelope.getMin().getY() ); 1302 int dim = envelope.getMax().getCoordinateDimension(); 1303 if ( dim == 3 ) { 1304 sb.append( ',' ).append( envelope.getMin().getZ() ); 1305 } 1306 sb.append( ' ' ).append( envelope.getMax().getX() ); 1307 sb.append( ',' ).append( envelope.getMax().getY() ); 1308 if ( dim == 3 ) { 1309 sb.append( ',' ).append( envelope.getMax().getZ() ); 1310 } 1311 sb.append( "</gml:coordinates></gml:Envelope>" ); 1312 1313 return sb; 1314 } 1315 1316 /** 1317 * creates a GML expression of a point geometry 1318 * 1319 * @param point 1320 * point geometry 1321 * 1322 * @return 1323 */ 1324 private static void exportPoint( Point point, PrintWriter pw ) { 1325 1326 String crs = null; 1327 int dim = point.getCoordinateDimension(); 1328 if ( point.getCoordinateSystem() != null ) { 1329 crs = point.getCoordinateSystem().getIdentifier().replace( ' ', ':' ); 1330 dim = point.getCoordinateSystem().getDimension(); 1331 } 1332 String srs = null; 1333 if ( crs != null ) { 1334 srs = "<gml:Point srsName=\"" + crs + "\">"; 1335 } else { 1336 srs = "<gml:Point>"; 1337 } 1338 pw.println( srs ); 1339 1340 if ( dim != 0 ) { 1341 String dimension = "<gml:pos srsDimension=\"" + dim + "\">"; 1342 pw.print( dimension ); 1343 } else { 1344 pw.print( "<gml:pos>" ); 1345 } 1346 1347 String coordinates = point.getX() + " " + point.getY(); 1348 if ( dim == 3 ) { 1349 coordinates = coordinates + " " + point.getZ(); 1350 } 1351 pw.print( coordinates ); 1352 pw.println( "</gml:pos>" ); 1353 pw.print( "</gml:Point>" ); 1354 1355 } 1356 1357 /** 1358 * creates a GML expression of a curve geometry 1359 * 1360 * @param o 1361 * curve geometry 1362 * 1363 * @return 1364 * 1365 * @throws GeometryException 1366 */ 1367 private static void exportCurve( Curve o, PrintWriter pw ) 1368 throws GeometryException { 1369 1370 String crs = null; 1371 if ( o.getCoordinateSystem() != null ) { 1372 crs = o.getCoordinateSystem().getName().replace( ' ', ':' ); 1373 } 1374 String srs = null; 1375 if ( crs != null ) { 1376 srs = "<gml:Curve srsName=\"" + crs + "\">"; 1377 } else { 1378 srs = "<gml:Curve>"; 1379 } 1380 pw.println( srs ); 1381 pw.println( "<gml:segments>" ); 1382 1383 int curveSegments = o.getNumberOfCurveSegments(); 1384 for ( int i = 0; i < curveSegments; i++ ) { 1385 pw.print( "<gml:LineStringSegment>" ); 1386 CurveSegment segment = o.getCurveSegmentAt( i ); 1387 Position[] p = segment.getAsLineString().getPositions(); 1388 pw.print( "<gml:posList>" ); 1389 for ( int j = 0; j < ( p.length - 1 ); j++ ) { 1390 pw.print( p[j].getX() + " " + p[j].getY() ); 1391 if ( o.getCoordinateDimension() == 3 ) { 1392 pw.print( ' ' ); 1393 pw.print( p[j].getZ() ); 1394 pw.print( ' ' ); 1395 } else { 1396 pw.print( ' ' ); 1397 } 1398 } 1399 pw.print( p[p.length - 1].getX() + " " + p[p.length - 1].getY() ); 1400 if ( o.getCoordinateDimension() == 3 ) { 1401 pw.print( " " + p[p.length - 1].getZ() ); 1402 } 1403 pw.println( "</gml:posList>" ); 1404 pw.println( "</gml:LineStringSegment>" ); 1405 } 1406 pw.println( "</gml:segments>" ); 1407 pw.print( "</gml:Curve>" ); 1408 1409 } 1410 1411 /** 1412 * @param sur 1413 * @throws RemoteException 1414 * @throws GeometryException 1415 */ 1416 private static void exportSurface( Surface surface, PrintWriter pw ) 1417 throws GeometryException { 1418 1419 String crs = null; 1420 if ( surface.getCoordinateSystem() != null ) { 1421 crs = surface.getCoordinateSystem().getName().replace( ' ', ':' ); 1422 } 1423 String srs = null; 1424 if ( crs != null ) { 1425 srs = "<gml:Surface srsName='" + crs + "'>"; 1426 } else { 1427 srs = "<gml:Surface>"; 1428 } 1429 pw.println( srs ); 1430 int patches = surface.getNumberOfSurfacePatches(); 1431 pw.println( "<gml:patches>" ); 1432 for ( int i = 0; i < patches; i++ ) { 1433 pw.println( "<gml:PolygonPatch>" ); 1434 SurfacePatch patch = surface.getSurfacePatchAt( i ); 1435 printExteriorRing( surface, pw, patch ); 1436 printInteriorRing( surface, pw, patch ); 1437 pw.println( "</gml:PolygonPatch>" ); 1438 } 1439 pw.println( "</gml:patches>" ); 1440 pw.print( "</gml:Surface>" ); 1441 1442 } 1443 1444 /** 1445 * @param surface 1446 * @param pw 1447 * @param patch 1448 */ 1449 private static void printInteriorRing( Surface surface, PrintWriter pw, SurfacePatch patch ) { 1450 // interior rings 1451 Position[][] ip = patch.getInteriorRings(); 1452 if ( ip != null ) { 1453 for ( int j = 0; j < ip.length; j++ ) { 1454 pw.println( "<gml:interior>" ); 1455 pw.println( "<gml:LinearRing>" ); 1456 if ( surface.getCoordinateSystem() != null ) { 1457 printPositions( pw, ip[j], surface.getCoordinateDimension() ); 1458 } else { 1459 printPositions( pw, ip[j], 0 ); 1460 } 1461 pw.println( "</gml:LinearRing>" ); 1462 pw.println( "</gml:interior>" ); 1463 } 1464 } 1465 } 1466 1467 /** 1468 * @param surface 1469 * @param pw 1470 * @param patch 1471 */ 1472 private static void printExteriorRing( Surface surface, PrintWriter pw, SurfacePatch patch ) { 1473 // exterior ring 1474 pw.print( "<gml:exterior>" ); 1475 pw.print( "<gml:LinearRing>" ); 1476 if ( surface.getCoordinateSystem() != null ) { 1477 printPositions( pw, patch.getExteriorRing(), surface.getCoordinateDimension() ); 1478 } else { 1479 printPositions( pw, patch.getExteriorRing(), 0 ); 1480 } 1481 pw.print( "</gml:LinearRing>" ); 1482 pw.print( "</gml:exterior>" ); 1483 } 1484 1485 /** 1486 * TODO using this method for exporting Surfaces will change to output, so it must be tested 1487 * carefully 1488 * 1489 * @param pw 1490 * @param ring 1491 * @param coordinateDimension 1492 */ 1493 private static void printRing( PrintWriter pw, Ring ring, int coordinateDimension ) { 1494 pw.print( "<gml:Ring><gml:curveMember><gml:Curve><gml:segments>" ); 1495 CurveSegment[] cs = ring.getCurveSegments(); 1496 for ( int i = 0; i < cs.length; i++ ) { 1497 printCurveSegment( pw, cs[i], coordinateDimension ); 1498 } 1499 pw.print( "</gml:segments></gml:Curve></gml:curveMember></gml:Ring>" ); 1500 1501 } 1502 1503 /** 1504 * 1505 * @param pw 1506 * @param segment 1507 * @param coordinateDimension 1508 */ 1509 private static void printCurveSegment( PrintWriter pw, CurveSegment segment, int coordinateDimension ) { 1510 pw.print( "<gml:LineStringSegment>" ); 1511 printPositions( pw, segment.getPositions(), coordinateDimension ); 1512 pw.print( "</gml:LineStringSegment>" ); 1513 } 1514 1515 /** 1516 * 1517 * @param pw 1518 * @param p 1519 * @param coordinateDimension 1520 */ 1521 private static void printPositions( PrintWriter pw, Position[] p, int coordinateDimension ) { 1522 StringBuilder posList = new StringBuilder( "<gml:posList" ); 1523 1524 if ( coordinateDimension > 0 ) { 1525 posList.append( " srsDimension='" ).append( coordinateDimension ).append( "' " ); 1526 } 1527 posList.append( ">" ); 1528 // pw.print( "<gml:posList>" ); 1529 pw.print( posList ); 1530 1531 for ( int j = 0; j < ( p.length - 1 ); j++ ) { 1532 pw.print( p[j].getX() + " " + p[j].getY() ); 1533 if ( coordinateDimension == 3 ) { 1534 pw.print( " " + p[j].getZ() + " " ); 1535 } else { 1536 pw.print( ' ' ); 1537 } 1538 } 1539 pw.print( p[p.length - 1].getX() + " " + p[p.length - 1].getY() ); 1540 if ( coordinateDimension == 3 ) { 1541 pw.print( " " + p[p.length - 1].getZ() ); 1542 } 1543 pw.print( "</gml:posList>" ); 1544 } 1545 1546 /** 1547 * @param mp 1548 * @return 1549 * @throws RemoteException 1550 */ 1551 private static void exportMultiPoint( MultiPoint mp, PrintWriter pw ) { 1552 1553 String crs = null; 1554 if ( mp.getCoordinateSystem() != null ) { 1555 crs = mp.getCoordinateSystem().getName().replace( ' ', ':' ); 1556 } 1557 String srs = null; 1558 if ( crs != null ) { 1559 srs = "<gml:MultiPoint srsName=\"" + crs + "\">"; 1560 } else { 1561 srs = "<gml:MultiPoint>"; 1562 } 1563 pw.println( srs ); 1564 pw.println( "<gml:pointMembers>" ); 1565 for ( int i = 0; i < mp.getSize(); i++ ) { 1566 1567 pw.println( "<gml:Point>" ); 1568 pw.print( "<gml:pos>" ); 1569 pw.print( mp.getPointAt( i ).getX() + " " + mp.getPointAt( i ).getY() ); 1570 if ( mp.getPointAt( i ).getCoordinateDimension() == 3 ) { 1571 pw.print( " " + mp.getPointAt( i ).getZ() ); 1572 } 1573 pw.println( "</gml:pos>" ); 1574 pw.println( "</gml:Point>" ); 1575 } 1576 pw.println( "</gml:pointMembers>" ); 1577 pw.print( "</gml:MultiPoint>" ); 1578 1579 } 1580 1581 /** 1582 * @param multiCurve 1583 * @return 1584 * @throws RemoteException 1585 * @throws GeometryException 1586 */ 1587 private static void exportMultiCurve( MultiCurve multiCurve, PrintWriter pw ) 1588 throws GeometryException { 1589 1590 String crs = null; 1591 if ( multiCurve.getCoordinateSystem() != null ) { 1592 crs = multiCurve.getCoordinateSystem().getName().replace( ' ', ':' ); 1593 } 1594 String srs = null; 1595 if ( crs != null ) { 1596 srs = "<gml:MultiCurve srsName=\"" + crs + "\">"; 1597 } else { 1598 srs = "<gml:MultiCurve>"; 1599 } 1600 pw.println( srs ); 1601 1602 Curve[] curves = multiCurve.getAllCurves(); 1603 pw.println( "<gml:curveMembers>" ); 1604 for ( int i = 0; i < curves.length; i++ ) { 1605 Curve curve = curves[i]; 1606 pw.println( "<gml:Curve>" ); 1607 pw.println( "<gml:segments>" ); 1608 pw.println( "<gml:LineStringSegment>" ); 1609 int numberCurveSegments = curve.getNumberOfCurveSegments(); 1610 for ( int j = 0; j < numberCurveSegments; j++ ) { 1611 CurveSegment curveSegment = curve.getCurveSegmentAt( j ); 1612 Position[] p = curveSegment.getAsLineString().getPositions(); 1613 pw.print( "<gml:posList>" ); 1614 for ( int k = 0; k < ( p.length - 1 ); k++ ) { 1615 pw.print( p[k].getX() + " " + p[k].getY() ); 1616 if ( curve.getCoordinateDimension() == 3 ) { 1617 pw.print( " " + p[k].getZ() + " " ); 1618 } else { 1619 pw.print( " " ); 1620 } 1621 } 1622 pw.print( p[p.length - 1].getX() + " " + p[p.length - 1].getY() ); 1623 if ( curve.getCoordinateDimension() == 3 ) { 1624 pw.print( " " + p[p.length - 1].getZ() ); 1625 } 1626 pw.println( "</gml:posList>" ); 1627 } 1628 pw.println( "</gml:LineStringSegment>" ); 1629 pw.println( "</gml:segments>" ); 1630 pw.println( "</gml:Curve>" ); 1631 } 1632 pw.println( "</gml:curveMembers>" ); 1633 pw.print( "</gml:MultiCurve>" ); 1634 1635 } 1636 1637 /** 1638 * @param multiSurface 1639 * @return 1640 * @throws RemoteException 1641 * @throws GeometryException 1642 */ 1643 private static void exportMultiSurface( MultiSurface multiSurface, PrintWriter pw ) 1644 throws GeometryException { 1645 1646 String crs = null; 1647 if ( multiSurface.getCoordinateSystem() != null ) { 1648 crs = multiSurface.getCoordinateSystem().getName().replace( ' ', ':' ); 1649 } 1650 String srs = null; 1651 if ( crs != null ) { 1652 srs = "<gml:MultiSurface srsName=\"" + crs + "\">"; 1653 } else { 1654 srs = "<gml:MultiSurface>"; 1655 } 1656 pw.println( srs ); 1657 1658 Surface[] surfaces = multiSurface.getAllSurfaces(); 1659 1660 pw.println( "<gml:surfaceMembers>" ); 1661 for ( int i = 0; i < surfaces.length; i++ ) { 1662 Surface surface = surfaces[i]; 1663 exportSurface( surface, pw ); 1664 } 1665 pw.println( "</gml:surfaceMembers>" ); 1666 // substitution as requested in issue 1667 // http://wald.intevation.org/tracker/index.php?func=detail&aid=477&group_id=27&atid=212 1668 // can be removed if it was inserted correctly 1669 // pw.println( "<gml:surfaceMembers>" ); 1670 // for ( int i = 0; i < surfaces.length; i++ ) { 1671 // Surface surface = surfaces[i]; 1672 // pw.println( "<gml:Surface>" ); 1673 // pw.println( "<gml:patches>" ); 1674 // pw.println( "<gml:Polygon>" ); 1675 // int numberSurfaces = surface.getNumberOfSurfacePatches(); 1676 // for ( int j = 0; j < numberSurfaces; j++ ) { 1677 // SurfacePatch surfacePatch = surface.getSurfacePatchAt( j ); 1678 // printExteriorRing( surface, pw, surfacePatch ); 1679 // printInteriorRing( surface, pw, surfacePatch ); 1680 // } 1681 // pw.println( "</gml:Polygon>" ); 1682 // pw.println( "</gml:patches>" ); 1683 // pw.println( "</gml:Surface>" ); 1684 // } 1685 // pw.println( "</gml:surfaceMembers>" ); 1686 pw.print( "</gml:MultiSurface>" ); 1687 1688 } 1689 1690 /** 1691 * Converts the string representation of a GML geometry object to a corresponding 1692 * <code>Geometry</code>. Notice that GML Boxes will be converted to Surfaces because in ISO 1693 * 19107 Envelopes are no geometries. 1694 * 1695 * @param gml 1696 * @return corresponding geometry object 1697 * @throws GeometryException 1698 * @throws XMLParsingException 1699 * @deprecated this method cannot provide default SRS information, please use 1700 * {@link #wrap(String,String)} instead 1701 */ 1702 @Deprecated 1703 public static Geometry wrap( String gml ) 1704 throws GeometryException, XMLParsingException { 1705 return wrap( gml, null ); 1706 } 1707 1708 /** 1709 * Converts a GML geometry object to a corresponding <tt>Geometry</tt>. Notice that GML Boxes 1710 * will be converted to Surfaces because in ISO 19107 Envelops are no geometries. 1711 * <p> 1712 * Currently, the following conversions are supported: 1713 * <ul> 1714 * <li>GML Point -> Point 1715 * <li>GML MultiPoint -> MultiPoint 1716 * <li>GML LineString -> Curve 1717 * <li>GML MultiLineString -> MultiCurve 1718 * <li>GML Polygon -> Surface 1719 * <li>GML MultiPolygon -> MultiSurface 1720 * <li>GML Box -> Surface 1721 * <li>GML Curve -> Curve 1722 * <li>GML Surface -> Surface 1723 * <li>GML MultiCurve -> MultiCurve 1724 * <li>GML MultiSurface -> MultiSurface 1725 * </ul> 1726 * <p> 1727 * 1728 * @param gml 1729 * @return the corresponding <tt>Geometry</tt> 1730 * @throws GeometryException 1731 * if type unsupported or conversion failed 1732 * @deprecated this method cannot provide default SRS information, please use 1733 * {@link #wrap(Element,String)} instead 1734 */ 1735 @Deprecated 1736 public static Geometry wrap( Element gml ) 1737 throws GeometryException { 1738 return wrap( gml, null ); 1739 } 1740 1741 /** 1742 * returns a Envelope created from Box element 1743 * 1744 * @param element 1745 * <boundedBy> 1746 * 1747 * @return instance of <tt>Envelope</tt> 1748 * 1749 * @throws XMLParsingException 1750 * @throws InvalidGMLException 1751 * @throws UnknownCRSException 1752 * @deprecated this method cannot provide default SRS information, please use 1753 * {@link #wrapBox(Element,String)} instead 1754 */ 1755 @Deprecated 1756 public static Envelope wrapBox( Element element ) 1757 throws XMLParsingException, InvalidGMLException, UnknownCRSException { 1758 return wrapBox( element, null ); 1759 } 1760 1761 }