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 }