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 }