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