    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    }