001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/model/spatialschema/WKTAdapter.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    package org.deegree.model.spatialschema;
037    
038    import java.util.ArrayList;
039    
040    import org.deegree.framework.util.StringTools;
041    import org.deegree.model.crs.CoordinateSystem;
042    
043    /**
044     * Adapter class for exporting deegree geometries to WKT and to wrap WKT code geometries to deegree geometries.
045     *
046     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
047     * @author last edited by: $Author: mschneider $
048     *
049     * @version $Revision: 18195 $
050     */
051    public class WKTAdapter {
052    
053        /**
054         *
055         *
056         * @param wkt
057         * @param crs
058         * @return the corresponding <tt>Geometry</tt>
059         * @throws GeometryException
060         *             if type unsupported or conversion failed
061         */
062        public static Geometry wrap( String wkt, CoordinateSystem crs )
063                                throws GeometryException {
064            if ( wkt == null || "".equals( wkt.trim() ) ) {
065                throw new NullPointerException( "No Well-Known-Text (WKT) to parse geometry from." );
066            }
067            Geometry geo = null;
068    
069            if ( wkt.startsWith( "POINT" ) ) {
070                geo = wrapPoint( wkt, crs );
071            } else if ( wkt.startsWith( "LINE" ) ) {
072                geo = wrapCurve( wkt, crs );
073            } else if ( wkt.startsWith( "POLY" ) ) {
074                geo = wrapSurface( wkt, crs );
075            } else if ( wkt.startsWith( "MULTIPOINT" ) ) {
076                geo = wrapMultiPoint( wkt, crs );
077            } else if ( wkt.startsWith( "MULTILINE" ) ) {
078                geo = wrapMultiCurve( wkt, crs );
079            } else if ( wkt.startsWith( "MULTIPOLY" ) ) {
080                geo = wrapMultiSurface( wkt, crs );
081            } else {
082                throw new GeometryException( "Not supported Well-Known-Text: " + wkt );
083            }
084    
085            return geo;
086        }
087    
088        /**
089         * @param geom
090         *            geometry
091         *
092         * @return the StingBuffer containing the exported geometry
093         * @throws GeometryException
094         */
095        public static StringBuffer export( Geometry geom )
096                                throws GeometryException {
097    
098            if ( geom == null ) {
099                throw new NullPointerException( "The Geometry is empty, cannot create wkt for it." );
100            }
101            StringBuffer sb = null;
102            if ( geom instanceof Point ) {
103                sb = export( (Point) geom );
104            } else if ( geom instanceof Curve ) {
105                sb = export( (Curve) geom );
106            } else if ( geom instanceof Surface ) {
107                sb = export( (Surface) geom );
108            } else if ( geom instanceof MultiPoint ) {
109                sb = export( (MultiPoint) geom );
110            } else if ( geom instanceof MultiCurve ) {
111                sb = export( (MultiCurve) geom );
112            } else if ( geom instanceof MultiSurface ) {
113                sb = export( (MultiSurface) geom );
114            } else if ( geom instanceof MultiGeometry ) {
115                sb = export( (MultiGeometry) geom );
116            }
117    
118            return sb;
119        }
120    
121        /**
122         * exports an Envelope as a BOX3D WKT string.
123         *
124         * @param envelope
125         * @return the StringBuffer containing the exported envelope
126         */
127        public static StringBuffer export( Envelope envelope ) {
128            if ( envelope == null ) {
129                throw new NullPointerException( "The envelope is empty, cannot create wkt for it." );
130            }
131            StringBuffer sb = new StringBuffer( 150 );
132            sb.append( "BOX3D(" );
133            int dim = envelope.getMin().getCoordinateDimension();
134            double[] d = envelope.getMin().getAsArray();
135            for ( int i = 0; i < dim - 1; i++ ) {
136                sb.append( Double.toString( d[i] ) ).append( " " );
137            }
138            sb.append( Double.toString( d[dim - 1] ) ).append( "," );
139            d = envelope.getMax().getAsArray();
140            for ( int i = 0; i < dim - 1; i++ ) {
141                sb.append( Double.toString( d[i] ) ).append( " " );
142            }
143            sb.append( Double.toString( d[dim - 1] ) );
144            sb.append( ") " );
145            return sb;
146        }
147    
148        /**
149         * @param point
150         *            point geometry
151         *
152         * @return the StringBuffer containing the exported point
153         */
154        private static StringBuffer export( Point point ) {
155    
156            StringBuffer sb = new StringBuffer( 50 );
157            sb.append( "POINT(" );
158            double[] points = point.getAsArray();
159            int dim = point.getCoordinateDimension();
160            for ( int i = 0; i < dim - 1; i++ ) {
161                sb.append( points[i] ).append( ' ' );
162            }
163            sb.append( points[dim - 1] );
164            sb.append( ") " );
165    
166            return sb;
167        }
168    
169        /**
170         *
171         * @param cur
172         *            curve geometry
173         *
174         * @return the StringBuffer containing the exported curve
175         *
176         * @throws GeometryException
177         */
178        private static StringBuffer export( Curve cur )
179                                throws GeometryException {
180    
181            LineString ls = cur.getAsLineString();
182    
183            StringBuffer sb = new StringBuffer( ls.getNumberOfPoints() * 30 );
184            sb.append( "LINESTRING(" );
185    
186            for ( int i = 0; i < ls.getNumberOfPoints() - 1; i++ ) {
187                Position pos = ls.getPositionAt( i );
188                double[] positions = pos.getAsArray();
189                int dim = pos.getCoordinateDimension();
190                for ( int j = 0; j < dim - 1; j++ ) {
191                    sb.append( positions[j] + " " );
192                }
193                sb.append( positions[dim - 1] + "," );
194            }
195            Position pos = ls.getPositionAt( ls.getNumberOfPoints() - 1 );
196            double[] tmp = pos.getAsArray();
197            int dim = pos.getCoordinateDimension();
198            for ( int j = 0; j < dim - 1; j++ ) {
199                sb.append( tmp[j] + " " );
200            }
201            sb.append( tmp[dim - 1] + ")" );
202    
203            return sb;
204        }
205    
206        /**
207         *
208         *
209         * @param sur
210         *
211         * @return the StringBuffer containing the exported surface
212         *
213         */
214        private static StringBuffer export( Surface sur ) {
215    
216            SurfaceBoundary subo = sur.getSurfaceBoundary();
217            Ring exter = subo.getExteriorRing();
218            Ring[] inter = subo.getInteriorRings();
219    
220            StringBuffer sb = new StringBuffer( 10000 );
221            sb.append( "POLYGON((" );
222            // exterior ring
223            Position[] pos = exter.getPositions();
224            int dim = pos[0].getCoordinateDimension();
225            for ( int i = 0; i < pos.length - 1; i++ ) {
226                double[] positions = pos[i].getAsArray();
227                for ( int j = 0; j < dim - 1; j++ ) {
228                    sb.append( positions[j] + " " );
229                }
230                sb.append( positions[dim - 1] + "," );
231            }
232            double[] positions = pos[pos.length - 1].getAsArray();
233            for ( int j = 0; j < dim - 1; j++ ) {
234                sb.append( positions[j] + " " );
235            }
236            sb.append( positions[dim - 1] + ")" );
237            // interior rings
238            if ( inter != null ) {
239                for ( int j = 0; j < inter.length; j++ ) {
240                    sb.append( ",(" );
241                    pos = inter[j].getPositions();
242                    for ( int i = 0; i < pos.length - 1; i++ ) {
243                        double[] intPos = pos[i].getAsArray();
244                        for ( int l = 0; l < dim - 1; l++ ) {
245                            sb.append( intPos[l] + " " );
246                        }
247                        sb.append( intPos[dim - 1] + "," );//
248                    }
249                    double[] intPos = pos[pos.length - 1].getAsArray();
250                    for ( int l = 0; l < dim - 1; l++ ) {
251                        sb.append( intPos[l] + " " );
252                    }
253                    sb.append( intPos[dim - 1] + ")" );
254                }
255            }
256            sb.append( ")" );
257    
258            return sb;
259        }
260    
261        /**
262         * @param mp
263         * @return the StringBuffer containing the exported multipoint
264         */
265        private static StringBuffer export( MultiPoint mp ) {
266    
267            StringBuffer sb = new StringBuffer( mp.getSize() * 30 );
268            sb.append( "MULTIPOINT(" );
269            int dim = mp.getPointAt( 0 ).getCoordinateDimension();
270            for ( int i = 0; i < mp.getSize() - 1; i++ ) {
271                Point pt = mp.getPointAt( i );
272                double[] points = pt.getAsArray();
273                for ( int j = 0; j < dim - 1; j++ ) {
274                    sb.append( points[j] + " " );
275                }
276                sb.append( points[dim - 1] );
277                sb.append( "," );
278            }
279            Point pt = mp.getPointAt( mp.getSize() - 1 );
280            double[] points = pt.getAsArray();
281            for ( int j = 0; j < dim - 1; j++ ) {
282                sb.append( points[j] + " " );
283            }
284            sb.append( points[dim - 1] + ")" );
285    
286            return sb;
287        }
288    
289        /**
290         *
291         *
292         * @param mc
293         *
294         * @return the StringBuffer containing the exported multi curve
295         *
296         * @throws GeometryException
297         */
298        private static StringBuffer export( MultiCurve mc )
299                                throws GeometryException {
300    
301            StringBuffer sb = new StringBuffer( 10000 );
302            sb.append( "MULTILINESTRING(" );
303    
304            for ( int i = 0; i < mc.getSize() - 1; i++ ) {
305                String s = export( mc.getCurveAt( i ) ).toString();
306                s = s.substring( 10, s.length() );
307                sb.append( s ).append( "," );
308            }
309            String s = export( mc.getCurveAt( mc.getSize() - 1 ) ).toString();
310            s = s.substring( 10, s.length() );
311            sb.append( s ).append( ")" );
312    
313            return sb;
314        }
315    
316        /**
317         *
318         *
319         * @param ms
320         *
321         * @return the StringBuffer containing the exported multi surface
322         *
323         */
324        private static StringBuffer export( MultiSurface ms ) {
325    
326            StringBuffer sb = new StringBuffer( 10000 );
327            sb.append( "MULTIPOLYGON(" );
328    
329            for ( int i = 0; i < ms.getSize() - 1; i++ ) {
330                String s = export( ms.getSurfaceAt( i ) ).toString();
331                s = s.substring( 7, s.length() );
332                sb.append( s ).append( "," );
333            }
334            String s = export( ms.getSurfaceAt( ms.getSize() - 1 ) ).toString();
335            s = s.substring( 7, s.length() );
336            sb.append( s ).append( ")" );
337    
338            return sb;
339        }
340    
341        private static StringBuffer export( MultiGeometry multi )
342                                throws GeometryException {
343            StringBuffer sb = new StringBuffer( 10000 );
344            sb.append( "GEOMETRYCOLLECTION(" );
345    
346            for ( int i = 0; i < multi.getSize() - 1; i++ ) {
347                StringBuffer memberWKT = export( multi.getObjectAt( i ) );
348                sb.append( memberWKT ).append( "," );
349            }
350    
351            StringBuffer memberWKT = export( multi.getObjectAt( multi.getSize() - 1 ) );
352            sb.append( memberWKT ).append( ")" );
353            return sb;
354        }
355    
356        /**
357         * creates a Point from a WKT.
358         *
359         * @param wkt
360         *            a Point WKT
361         * @param crs
362         * @return the point created from the given wkt
363         * @throws GeometryException
364         */
365        public static Point wrapPoint( String wkt, CoordinateSystem crs )
366                                throws GeometryException {
367            if ( wkt == null || "".equals( wkt.trim() ) ) {
368                throw new NullPointerException( "No Well-Known-Text (WKT) to parse point from." );
369            }
370            wkt = wkt.trim();
371            wkt = wkt.substring( 6, wkt.length() - 1 );
372            double[] tmp = createDoubles( wkt );// StringTools.toArrayDouble( wkt, " " );
373            Position pos = GeometryFactory.createPosition( tmp );
374            Point point = GeometryFactory.createPoint( pos, crs );
375    
376            return point;
377        }
378    
379        /**
380         * creates a Curve from a WKT.
381         *
382         * @param wkt
383         *            linestring a WKT
384         * @param crs
385         * @return the curve created from the given wkt.
386         * @throws GeometryException
387         */
388        public static Curve wrapCurve( String wkt, CoordinateSystem crs )
389                                throws GeometryException {
390            if ( wkt == null || "".equals( wkt.trim() ) ) {
391                throw new NullPointerException( "No Well-Known-Text (WKT) to parse curve from." );
392            }
393            wkt = wkt.trim();
394            wkt = wkt.substring( 11, wkt.length() - 1 );
395            String[] points = wkt.split( "," );// StringTools.toArray( wkt, ",", false );
396            Position[] pos = new Position[points.length];
397            for ( int i = 0; i < points.length; i++ ) {
398                double[] tmp = StringTools.toArrayDouble( points[i], " " );
399                pos[i] = GeometryFactory.createPosition( tmp );
400            }
401            Curve curve = GeometryFactory.createCurve( pos, crs );
402    
403            return curve;
404        }
405    
406        /**
407         * creates a Surface
408         *
409         * @param wkt
410         *            polygon WKT
411         * @param crs
412         * @return the Surface created from the given wkt.
413         * @throws GeometryException
414         */
415        public static Surface wrapSurface( String wkt, CoordinateSystem crs )
416                                throws GeometryException {
417            if ( wkt == null || "".equals( wkt.trim() ) ) {
418                throw new NullPointerException( "No Well-Known-Text (WKT) to parse surface from." );
419            }
420            wkt = wkt.trim();
421    
422            Position[] ext = null;
423            ArrayList<Position[]> inn = new ArrayList<Position[]>();
424            if ( wkt.indexOf( "((" ) > 0 ) {
425                wkt = wkt.substring( 9, wkt.length() - 1 );
426                int pos = wkt.indexOf( ")" );
427                String tmp = wkt.substring( 0, pos );
428                // external ring
429                String[] points = tmp.split( "," );// StringTools.toArray( tmp, ",", false );
430                ext = new Position[points.length];
431                for ( int i = 0; i < points.length; i++ ) {
432                    double[] temp = StringTools.toArrayDouble( points[i], " " );
433                    ext[i] = GeometryFactory.createPosition( temp );
434                }
435                if ( pos + 3 < wkt.length() ) {
436                    wkt = wkt.substring( pos + 3, wkt.length() );
437                    while ( wkt.indexOf( ")" ) > 0 ) {
438                        pos = wkt.indexOf( ")" );
439                        tmp = wkt.substring( 0, pos );
440                        // internal ring(s)
441                        points = tmp.split( "," );// StringTools.toArray( tmp, ",", false );
442                        Position[] intern = new Position[points.length];
443                        for ( int i = 0; i < points.length; i++ ) {
444                            double[] temp = StringTools.toArrayDouble( points[i], " " );
445                            intern[i] = GeometryFactory.createPosition( temp );
446                        }
447                        inn.add( intern );
448                        if ( pos + 3 < wkt.length() ) {
449                            wkt = wkt.substring( pos + 3, wkt.length() );
450                        } else {
451                            break;
452                        }
453                    }
454                }
455            }
456            Position[][] inner = null;
457            if ( inn.size() > 0 ) {
458                inner = inn.toArray( new Position[inn.size()][] );
459            }
460            Surface sur = GeometryFactory.createSurface( ext, inner, new SurfaceInterpolationImpl(), crs );
461    
462            return sur;
463        }
464    
465        /**
466         * creates a MultiPoint from a WKT
467         *
468         * @param wkt
469         *            multipoint WKT
470         * @param crs
471         * @return the Multipoint created from the given wkt.
472         */
473        public static MultiPoint wrapMultiPoint( String wkt, CoordinateSystem crs ) {
474            if ( wkt == null || "".equals( wkt.trim() ) ) {
475                throw new NullPointerException( "No Well-Known-Text (WKT) to parse multi point from." );
476            }
477            wkt = wkt.trim();
478            wkt = wkt.substring( 11, wkt.length() - 1 );
479            String[] coords = wkt.split( "," );// StringTools.toArray( wkt, ",", false );
480            Position[] pos = new Position[coords.length];
481            for ( int i = 0; i < coords.length; i++ ) {
482                double[] temp = StringTools.toArrayDouble( coords[i], " " );
483                pos[i] = GeometryFactory.createPosition( temp );
484            }
485    
486            Point[] points = new Point[pos.length];
487            for ( int i = 0; i < pos.length; i++ ) {
488                points[i] = GeometryFactory.createPoint( pos[i], crs );
489            }
490            MultiPoint mp = GeometryFactory.createMultiPoint( points );
491    
492            return mp;
493        }
494    
495        /**
496         * creates a MultiCurve from a WKT
497         *
498         * @param wkt
499         *            a WKT
500         * @param crs
501         * @return the multi curve created from the given wkt.
502         * @throws GeometryException
503         */
504        public static MultiCurve wrapMultiCurve( String wkt, CoordinateSystem crs )
505                                throws GeometryException {
506            if ( wkt == null || "".equals( wkt.trim() ) ) {
507                throw new NullPointerException( "No Well-Known-Text (WKT) to parse multi-curve from." );
508            }
509            ArrayList<Curve> crvs = new ArrayList<Curve>();
510    
511            wkt = wkt.trim();
512            int pos = wkt.indexOf( ")" );
513            String tmp = wkt.substring( 17, pos );
514            String[] coords = tmp.split( "," );// StringTools.toArray( tmp, ",", false );
515            Position[] posi = new Position[coords.length];
516            for ( int i = 0; i < coords.length; i++ ) {
517                double[] temp = StringTools.toArrayDouble( coords[i], " " );
518                posi[i] = GeometryFactory.createPosition( temp );
519            }
520            crvs.add( GeometryFactory.createCurve( posi, crs ) );
521            wkt = wkt.substring( pos + 3, wkt.length() - 1 );
522            while ( wkt.indexOf( ")" ) > 0 ) {
523                Position[] posi2 = new Position[coords.length];
524                pos = wkt.indexOf( ")" );
525                tmp = wkt.substring( 0, pos );
526                coords = tmp.split( "," );// StringTools.toArray( tmp, ",", false );
527                for ( int i = 0; i < coords.length; i++ ) {
528                    double[] temp = StringTools.toArrayDouble( coords[i], " " );
529                    posi2[i] = GeometryFactory.createPosition( temp );
530                }
531                crvs.add( GeometryFactory.createCurve( posi2, crs ) );
532                if ( pos + 3 < wkt.length() ) {
533                    wkt = wkt.substring( pos + 3, wkt.length() );
534                } else {
535                    break;
536                }
537            }
538    
539            Curve[] curves = crvs.toArray( new Curve[crvs.size()] );
540            MultiCurve mc = GeometryFactory.createMultiCurve( curves );
541    
542            return mc;
543        }
544    
545        /**
546         * creates a MultiSurface from a WKT
547         *
548         * @param wkt
549         *            a WKT
550         * @param crs
551         * @return the multi surface created from the given wkt.
552         * @throws GeometryException
553         */
554        public static MultiSurface wrapMultiSurface( String wkt, CoordinateSystem crs )
555                                throws GeometryException {
556            if ( wkt == null || "".equals( wkt.trim() ) ) {
557                throw new NullPointerException( "No Well-Known-Text (WKT) to parse multi-surface from." );
558            }
559            ArrayList<Surface> srfcs = new ArrayList<Surface>();
560    
561            wkt = wkt.substring( 13 );
562            // for each polygon
563            while ( wkt.indexOf( "((" ) > -1 ) {
564                Position[] ext = null;
565                ArrayList<Position[]> inn = new ArrayList<Position[]>();
566                int pos1 = wkt.indexOf( "))" );
567                String tmp = wkt.substring( 2, pos1 + 1 );
568                // exterior ring
569                int pos = tmp.indexOf( ")" );
570                String tmp2 = tmp.substring( 0, pos );
571                String[] points = tmp2.split( "," );// StringTools.toArray( tmp2, ",", false );
572                ext = new Position[points.length];
573                for ( int i = 0; i < points.length; i++ ) {
574                    double[] temp = StringTools.toArrayDouble( points[i], " " );
575                    ext[i] = GeometryFactory.createPosition( temp );
576                }
577                if ( pos + 3 < tmp.length() ) {
578                    tmp = tmp.substring( pos + 3, tmp.length() );
579                    // for each inner ring
580                    while ( tmp.indexOf( ")" ) > 0 ) {
581                        pos = tmp.indexOf( ")" );
582                        tmp2 = tmp.substring( 0, pos );
583                        points = tmp2.split( "," );// StringTools.toArray( tmp2, ",", false );
584                        Position[] intern = new Position[points.length];
585                        for ( int i = 0; i < points.length; i++ ) {
586                            double[] temp = StringTools.toArrayDouble( points[i], " " );
587                            intern[i] = GeometryFactory.createPosition( temp );
588                        }
589                        inn.add( intern );
590                        if ( pos + 3 < tmp.length() ) {
591                            tmp = tmp.substring( pos + 3, tmp.length() );
592                        } else {
593                            break;
594                        }
595                    }
596                }
597                Position[][] inner = null;
598                if ( inn.size() > 0 ) {
599                    inner = inn.toArray( new Position[inn.size()][] );
600                }
601                Surface sur = GeometryFactory.createSurface( ext, inner, new SurfaceInterpolationImpl(), crs );
602                srfcs.add( sur );
603                wkt = wkt.substring( pos1 + 3 );
604            }
605            Surface[] surfaces = srfcs.toArray( new Surface[srfcs.size()] );
606            MultiSurface ms = GeometryFactory.createMultiSurface( surfaces );
607    
608            return ms;
609        }
610    
611        private static double[] createDoubles( String toSeparate )
612                                throws GeometryException {
613            if ( toSeparate == null || "".equals( toSeparate.trim() ) ) {
614                throw new NullPointerException( "The given wkt geometry does not contain coordinates." );
615            }
616            String delimiter = " ";
617            String[] doubs = toSeparate.split( delimiter );
618            int cnt = 0;
619            for ( int i = 0; i < doubs.length; i++ ) {
620                if ( doubs[i] != null && !"".equals( doubs[i] ) ) {
621                    cnt++;
622                }
623            }
624            double[] result = null;
625            if ( doubs != null ) {
626                result = new double[cnt];
627                cnt = 0;
628                for ( int i = 0; i < doubs.length; ++i ) {
629                    String d = doubs[i];
630                    if ( d != null && !"".equals( d ) ) {
631                        try {
632                            result[cnt++] = Double.valueOf( d );
633                        } catch ( NumberFormatException e ) {
634                            throw new GeometryException( "The given WKT is not valid at position: " + i + ". Message: "
635                                                         + e.getLocalizedMessage() );
636                        }
637                    }
638                }
639            } else {
640                throw new NullPointerException( "The given wkt geometry does not contain coordinates." );
641            }
642    
643            return result;
644        }
645    }