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 }