001    //$HeadURL: https://sushibar/svn/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $
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    
037    package org.deegree.io.mapinfoapi;
038    
039    import static java.lang.Double.parseDouble;
040    import static java.lang.Integer.parseInt;
041    import static org.deegree.model.spatialschema.GeometryFactory.createCurve;
042    import static org.deegree.model.spatialschema.GeometryFactory.createCurveSegment;
043    import static org.deegree.model.spatialschema.GeometryFactory.createMultiPoint;
044    import static org.deegree.model.spatialschema.GeometryFactory.createMultiSurface;
045    import static org.deegree.model.spatialschema.GeometryFactory.createPoint;
046    import static org.deegree.model.spatialschema.GeometryFactory.createPosition;
047    import static org.deegree.model.spatialschema.GeometryFactory.createSurface;
048    
049    import java.io.IOException;
050    import java.io.StreamTokenizer;
051    import java.util.HashMap;
052    import java.util.HashSet;
053    import java.util.LinkedList;
054    
055    import org.deegree.framework.log.ILogger;
056    import org.deegree.framework.log.LoggerFactory;
057    import org.deegree.framework.util.Pair;
058    import org.deegree.model.crs.CoordinateSystem;
059    import org.deegree.model.spatialschema.Curve;
060    import org.deegree.model.spatialschema.CurveSegment;
061    import org.deegree.model.spatialschema.GeometryException;
062    import org.deegree.model.spatialschema.MultiPoint;
063    import org.deegree.model.spatialschema.MultiSurface;
064    import org.deegree.model.spatialschema.Point;
065    import org.deegree.model.spatialschema.Position;
066    import org.deegree.model.spatialschema.Surface;
067    
068    /**
069     * <code>MIFGeometryParser</code>
070     *
071     * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
072     * @author last edited by: $Author:$
073     *
074     * @version $Revision:$, $Date:$
075     */
076    public class MIFGeometryParser {
077    
078        private static final ILogger LOG = LoggerFactory.getLogger( MIFGeometryParser.class );
079    
080        private StreamTokenizer mif;
081    
082        private CoordinateSystem crs;
083    
084        /**
085         *
086         */
087        public LinkedList<String> errors = new LinkedList<String>();
088    
089        /**
090         * @param mif
091         * @param crs
092         */
093        public MIFGeometryParser( StreamTokenizer mif, CoordinateSystem crs ) {
094            this.mif = mif;
095            this.crs = crs;
096        }
097    
098        private Position[] parsePositions( int cnt )
099                                throws IOException {
100            Position[] ps = new Position[cnt];
101            for ( int k = 0; k < cnt; ++k ) {
102                double x = parseDouble( mif.sval );
103                mif.nextToken();
104                double y = parseDouble( mif.sval );
105                mif.nextToken();
106    
107                ps[k] = createPosition( x, y );
108            }
109    
110            return ps;
111        }
112    
113        /**
114         * @return a deegree Point
115         * @throws IOException
116         */
117        public Point parsePoint()
118                                throws IOException {
119            LOG.logDebug( "Parsing point..." );
120            mif.nextToken();
121            double x = parseDouble( mif.sval );
122            mif.nextToken();
123            double y = parseDouble( mif.sval );
124            mif.nextToken();
125    
126            return createPoint( x, y, crs );
127        }
128    
129        /**
130         * @return a deegree multipoint
131         * @throws IOException
132         */
133        public MultiPoint parseMultipoint()
134                                throws IOException {
135            LOG.logDebug( "Parsing multipoint..." );
136            mif.nextToken();
137    
138            int cnt = parseInt( mif.sval );
139            mif.nextToken();
140            Point[] points = new Point[cnt];
141    
142            for ( int i = 0; i < cnt; ++i ) {
143                double x = parseDouble( mif.sval );
144                mif.nextToken();
145                double y = parseDouble( mif.sval );
146                mif.nextToken();
147    
148                points[i] = createPoint( x, y, crs );
149            }
150    
151            return createMultiPoint( points );
152        }
153    
154        /**
155         * @return a deegree Curve or null, if the line contained errors
156         * @throws IOException
157         */
158        public Curve parseLine()
159                                throws IOException {
160            LOG.logDebug( "Parsing line..." );
161            mif.nextToken();
162    
163            Position[] ps = parsePositions( 2 );
164    
165            try {
166                return createCurve( ps, crs );
167            } catch ( GeometryException e ) {
168                errors.add( e.getLocalizedMessage() );
169            }
170    
171            return null;
172        }
173    
174        /**
175         * @return a deegree Curve or null, if errors were found
176         * @throws IOException
177         */
178        public Curve parsePLine()
179                                throws IOException {
180            LOG.logDebug( "Parsing pline..." );
181            mif.nextToken();
182    
183            int cnt = 1;
184    
185            if ( mif.sval.equals( "multiple" ) ) {
186                mif.nextToken();
187                cnt = parseInt( mif.sval );
188                mif.nextToken();
189            }
190    
191            CurveSegment[] segs = new CurveSegment[cnt];
192    
193            for ( int i = 0; i < cnt; ++i ) {
194                int pcnt = Integer.parseInt( mif.sval );
195                mif.nextToken();
196    
197                Position[] ps = parsePositions( pcnt );
198    
199                try {
200                    segs[i] = createCurveSegment( ps, crs );
201                } catch ( GeometryException e ) {
202                    errors.add( e.getLocalizedMessage() );
203                }
204            }
205    
206            try {
207                return cnt > 1 ? createCurve( segs ) : createCurve( segs[0] );
208            } catch ( GeometryException e ) {
209                errors.add( e.getLocalizedMessage() );
210            }
211    
212            return null;
213        }
214    
215        /**
216         * Null will be returned if polygons are broken, for example the two-point-polygons (actual
217         * example exported from MapInfo!):
218         *
219         * <pre>
220         *             Region 1
221         *             2
222         *             2505127 5631765
223         *             2505127 5631765
224         * </pre>
225         *
226         * @return a deegree multi surface or null in case of errors
227         * @throws IOException
228         */
229        public MultiSurface parseRegion()
230                                throws IOException {
231            LOG.logDebug( "Parsing region..." );
232            mif.nextToken();
233    
234            int cnt = parseInt( mif.sval );
235            mif.nextToken();
236            HashSet<Surface> polygons = new HashSet<Surface>();
237    
238            // the mapping is used to extract the relevant rings later on
239            HashMap<Surface, Pair<Position[], Position[][]>> arrays = new HashMap<Surface, Pair<Position[], Position[][]>>();
240    
241            for ( int i = 0; i < cnt; ++i ) {
242    
243                int pcnt = parseInt( mif.sval );
244                mif.nextToken();
245    
246                Position[] ps = parsePositions( pcnt );
247    
248                try {
249                    Surface s = createSurface( ps, null, null, crs );
250                    arrays.put( s, new Pair<Position[], Position[][]>( ps, null ) );
251                    polygons.add( s );
252                } catch ( GeometryException e ) {
253                    errors.add( e.getLocalizedMessage() );
254                }
255            }
256    
257            // fixed point, should sort the polygons by size first
258            // the mapping is used here to extract the rings
259            fp: while ( true ) {
260                for ( Surface s : polygons ) {
261                    for ( Surface t : polygons ) {
262                        if ( s.contains( t ) ) {
263                            polygons.remove( t );
264                            polygons.remove( s );
265    
266                            Pair<Position[], Position[][]> spos = arrays.get( s );
267                            Pair<Position[], Position[][]> tpos = arrays.get( t );
268    
269                            arrays.remove( s );
270                            arrays.remove( t );
271    
272                            Position[] outer = spos.first;
273                            Position[][] inner = new Position[spos.second == null ? 1 : spos.second.length + 1][];
274                            if ( spos.second != null ) {
275                                for ( int i = 0; i < spos.second.length; ++i ) {
276                                    inner[i] = spos.second[i];
277                                }
278                            }
279                            inner[inner.length - 1] = tpos.first;
280    
281                            if ( tpos.second != null ) {
282                                LOG.logWarning( "Ignoring previously found inner rings. Is your data corrupt?" );
283                            }
284    
285                            Surface nsurface = null;
286                            try {
287                                nsurface = createSurface( outer, inner, null, crs );
288                            } catch ( GeometryException e ) {
289                                errors.add( e.getLocalizedMessage() );
290                            }
291    
292                            arrays.put( nsurface, new Pair<Position[], Position[][]>( outer, inner ) );
293    
294                            polygons.add( nsurface );
295    
296                            continue fp;
297                        }
298                    }
299                }
300                break;
301            }
302    
303            // can happen if polygons are broken, for example the two-point-polygons (actual example
304            // exported from MapInfo!):
305            // Region 1
306            // 2
307            // 2505127 5631765
308            // 2505127 5631765
309            if ( polygons.size() == 0 ) {
310                return null;
311            }
312    
313            MultiSurface ms = createMultiSurface( polygons.toArray( new Surface[polygons.size()] ) );
314    
315            return ms;
316        }
317    
318        /**
319         * Currently just skips over the tokens.
320         *
321         * @throws IOException
322         */
323        public void parseArc()
324                                throws IOException {
325            LOG.logDebug( "Parsing arc..." );
326            LOG.logWarning( "Arcs are not understood and will be ignored." );
327            mif.nextToken(); // x1, y1, x2, y2 coordinates
328            mif.nextToken();
329            mif.nextToken();
330            mif.nextToken();
331    
332            mif.nextToken(); // a, b
333            mif.nextToken();
334        }
335    
336        /**
337         * Currently just skips over the tokens.
338         *
339         * @throws IOException
340         */
341        public void parseRoundRect()
342                                throws IOException {
343            LOG.logDebug( "Parsing roundrect..." );
344    
345            LOG.logWarning( "Roundrects are not understood and will be ignored." );
346            mif.nextToken(); // x1, y1, x2, y2 coordinates
347            mif.nextToken();
348            mif.nextToken();
349            mif.nextToken();
350    
351            mif.nextToken(); // a
352        }
353    
354        /**
355         * Currently just skips over the tokens.
356         *
357         * @throws IOException
358         */
359        public void parseEllipse()
360                                throws IOException {
361            LOG.logDebug( "Parsing ellipse..." );
362            LOG.logWarning( "Ellipses are not understood and will be ignored." );
363            mif.nextToken(); // x1, y1, x2, y2 coordinates
364            mif.nextToken();
365            mif.nextToken();
366            mif.nextToken();
367            mif.nextToken();
368        }
369    
370        /**
371         * @return a deegree surface with 5 points
372         * @throws IOException
373         */
374        public Surface parseRect()
375                                throws IOException {
376            LOG.logDebug( "Parsing rect..." );
377    
378            mif.nextToken();
379            double x1 = Double.parseDouble( mif.sval );
380            mif.nextToken();
381            double y1 = Double.parseDouble( mif.sval );
382            mif.nextToken();
383            double x2 = Double.parseDouble( mif.sval );
384            mif.nextToken();
385            double y2 = Double.parseDouble( mif.sval );
386            mif.nextToken();
387    
388            Position[] ps = new Position[5];
389            ps[0] = createPosition( x1, y1 );
390            ps[1] = createPosition( x2, y1 );
391            ps[2] = createPosition( x2, y2 );
392            ps[3] = createPosition( x1, y2 );
393            ps[4] = createPosition( x1, y1 );
394            try {
395                return createSurface( ps, null, null, crs );
396            } catch ( GeometryException e ) {
397                errors.add( e.getLocalizedMessage() );
398            }
399    
400            return null;
401        }
402    
403    }