Revision 16072 trunk/libraries/libTopology/src/org/gvsig/fmap/core/FGeometryUtil.java

View differences:

FGeometryUtil.java
55 55

  
56 56
import org.gvsig.jts.JtsUtil;
57 57

  
58
import com.iver.cit.gvsig.fmap.core.FArc2D;
59
import com.iver.cit.gvsig.fmap.core.FCircle2D;
60
import com.iver.cit.gvsig.fmap.core.FEllipse2D;
58 61
import com.iver.cit.gvsig.fmap.core.FGeometry;
59 62
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
60 63
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
61 64
import com.iver.cit.gvsig.fmap.core.FMultipoint3D;
62 65
import com.iver.cit.gvsig.fmap.core.FNullGeometry;
66
import com.iver.cit.gvsig.fmap.core.FPoint2D;
67
import com.iver.cit.gvsig.fmap.core.FPoint3D;
68
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
69
import com.iver.cit.gvsig.fmap.core.FPolygon3D;
70
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
71
import com.iver.cit.gvsig.fmap.core.FPolyline3D;
63 72
import com.iver.cit.gvsig.fmap.core.FShape;
73
import com.iver.cit.gvsig.fmap.core.FSpline2D;
64 74
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
65 75
import com.iver.cit.gvsig.fmap.core.IGeometry;
66 76
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
67 77
import com.iver.cit.gvsig.fmap.core.gt2.FLiteShape;
78
import com.vividsolutions.jts.algorithm.CGAlgorithms;
79
import com.vividsolutions.jts.algorithms.SnapCGAlgorithms;
80
import com.vividsolutions.jts.geom.Coordinate;
81
import com.vividsolutions.jts.geom.Envelope;
68 82
import com.vividsolutions.jts.geom.Geometry;
83
import com.vividsolutions.jts.geom.LinearRing;
84
import com.vividsolutions.jts.geom.MultiPolygon;
85
import com.vividsolutions.jts.geom.Polygon;
69 86

  
70 87
/**
71 88
 * Utility methods to work with FMap geometries.
......
91 108
		
92 109
	}
93 110
	
111
	public static boolean isClosed(Shape shape){
112
		return isClosed(shape, 0d);
113
	}
94 114
	
115
	
95 116
	public static boolean snapEquals2D(Point2D a, Point2D b, double snapTolerance){
96 117
		return a.distance(b) <= snapTolerance;
97 118
	}
......
195 216
		return solution;
196 217
	}
197 218
	
219
	
220
	
221
	/**
222
	 * Returns the dimension (0, 1, 2) of the specified
223
	 * geometry type.
224
	 * 
225
	 * @param shapeType
226
	 * @return
227
	 */
228
	public static int getDimensions(int shapeType){
229
		switch(shapeType){
230
		case FShape.ARC:
231
		case FShape.LINE:
232
			return 1;
233
			
234
		case FShape.CIRCLE:
235
		case FShape.ELLIPSE:
236
		case FShape.POLYGON:
237
		case FShape.MULTI:
238
			return 2;
239
			
240
		case FShape.MULTIPOINT:
241
		case FShape.POINT:
242
		case FShape.TEXT:
243
			return 0;
244
		default:
245
			return -1;
246
		}
247
	}
248
	
249
	
250
	/**
251
	 * Returns the dimension (0, 1, 2, -1 for NULL geometries)
252
	 * of the given geometry.
253
	 * 
254
	 * @param shape
255
	 * @return
256
	 */
257
	
258
	public static int getDimensions(IGeometry geometry){
259
		if(geometry instanceof FGeometry){
260
			FGeometry fgeo = (FGeometry)geometry;
261
			FShape fshape = (FShape) fgeo.getInternalShape();
262
			return getXyDimensions(fshape);
263
			
264
		}else if(geometry instanceof FGeometryCollection){
265
			FGeometryCollection fgeo = (FGeometryCollection)geometry;
266
			IGeometry[] geoms = fgeo.getGeometries();
267
			int dimension = -1;
268
			for(int i = 0; i < geoms.length; i++){
269
				IGeometry igeo = geoms[i];
270
				int igeoDimension = getDimensions(igeo);
271
				if(igeoDimension > dimension)
272
					dimension = igeoDimension;
273
				
274
			}
275
			return dimension;
276
			
277
		}else if(geometry instanceof FMultiPoint2D){
278
			return 0;
279
		}else if(geometry instanceof FMultipoint3D){
280
			return 0;
281
		}else if(geometry instanceof FNullGeometry){
282
			return -1;
283
		}else{
284
			return -1;
285
		}
286
	}
287
	
288
	/**
289
	 * Returns the dimension (0, 1, 2, -1 for NULL geometries)
290
	 * of the given shape.
291
	 * 
292
	 * @param shape
293
	 * @return
294
	 */
295
	public static int getXyDimensions(FShape shape){
296
		if(shape instanceof FArc2D){
297
			return 1;
298
		}else if(shape instanceof FCircle2D){
299
			return 2;
300
		}else if(shape instanceof FEllipse2D){
301
			return 2;
302
		}else if(shape instanceof FPoint2D){
303
			return 0;
304
		}else if(shape instanceof FPoint3D){
305
			return 0;
306
		}else if(shape instanceof FPolygon2D){
307
			return 2;
308
		}else if(shape instanceof FPolygon3D){
309
			return 2;
310
		}else if(shape instanceof FPolyline2D){
311
			return 1;
312
		}else if (shape instanceof FPolyline3D){
313
			return 1;
314
		}else if(shape instanceof FSpline2D){
315
			return 1;
316
		}else if(shape instanceof FLiteShape ){
317
			FLiteShape liteShape = (FLiteShape)shape;
318
			Geometry jtsGeo = liteShape.getGeometry();
319
			return jtsGeo.getDimension();
320
		}else{
321
			return -1;
322
		}
323
	}
324
	
325
	//TODO Solicitar que este metodo se ponga en FConverter sustituyendo
326
	//al viejo
327
	//TODO Movemos esto a JtsUtil en vez de en esta clase????
328
	
329
	/*
330
	 * Justificacion: libTopology constituye un sistema de control de calidad geometrica de los
331
	 * datos. FConverter deber?a asumir que los datos le llegan adecuadamente, y si no es as?,
332
	 * lanzar excepciones.
333
	 * 
334
	 * La responsabilidad de detectar que un dato (FShape) no es apropiado para pasar a poligono
335
	 * deberia tenerla libTopology (TopologyRule), y en caso de que as? se detecte, tratar el dato
336
	 * de forma previa a llamar a FConverter.
337
	 * 
338
	 * 
339
	 * */
340
	
341
	public static MultiPolygon toJtsPolygon(FShape shp){
342
		
343
		ArrayList<LinearRing> shells = new ArrayList<LinearRing>();
344
		ArrayList<LinearRing> holes = new ArrayList<LinearRing>();
345
	    
346
		List<Point2D[]> shpPoints = ShapePointExtractor.extractPoints(shp);
347
		for(int i = 0; i < shpPoints.size(); i++){
348
			Point2D[] partPoints = shpPoints.get(i);
349
			Coordinate[] coords = JtsUtil.getPoint2DAsCoordinates(partPoints);
350
			try {
351
				LinearRing ring = JtsUtil.geomFactory.createLinearRing(coords);
352
				
353
				//TODO REPORTAR ESTO EN FMAP, CREO QUE EST? MAL PORQUE LO HACE AL REV?S.
354
				//EL TEMA EST? EN QUE JTS HACE LAS COSAS AL REVES QUE EL FORMATO SHP
355
				if (CGAlgorithms.isCCW(coords)) {
356
					shells.add(ring);
357
				} else {
358
					holes.add(ring);
359
				}
360
			} catch (Exception e) {
361
				/*
362
				 * Leer la cabecera del metodo: FConverter no deber?a hacer estos tratamientos
363
				boolean same = true;
364
				for (int j = 0; i < coords.length - 1 && same; j++) {
365
					if (coords[i].x != coords[i+1].x || coords[i].y != coords[i+1].y) 
366
						same = false;
367
				}
368
				if (same)
369
					return JtsUtil.geomFactory.createPoint(coords[0]);
370
				*/
371
				
372
				/*
373
				 * caso cuando es una l?nea de 3 puntos, no creo un LinearRing, sino
374
				 * una linea
375
				 */
376
				/*
377
				if (coords.length > 1 && coords.length <= 3)
378
					// return geomFactory.createLineString(points);
379
					return JtsUtil.geomFactory.createMultiLineString(new LineString[] {JtsUtil.geomFactory.createLineString(coords)});
380
				*/
381
				System.err.println("Caught Topology exception in GMLLinearRingHandler");
382
				return null;
383
			}
384
		}//for
385
		
386
		//At this point, we have a collection of shells and a collection of holes
387
		//Now we have to find for each shell its holes
388
		ArrayList<List<LinearRing>> holesForShells = new ArrayList<List<LinearRing>>(shells.size());
389
		for (int i = 0; i < shells.size(); i++) {
390
			holesForShells.add(new ArrayList<LinearRing>());
391
		}
392

  
393
		
394
		/*
395
		 * Now, for each hole we look for the minimal shell that contains it.
396
		 * We look for minimal because many shells could contain the same hole. 
397
		 * */
398
		for (int i = 0; i < holes.size(); i++) {//for each hole
399
			LinearRing testHole = holes.get(i);
400
			LinearRing minShell = null;
401
			Envelope minEnv = null;
402
			Envelope testEnv = testHole.getEnvelopeInternal();
403
			Coordinate testPt = testHole.getCoordinateN(0);
404
			LinearRing tryRing = null;		
405
			
406
			for (int j = 0; j < shells.size(); j++) {//for each shell
407
				tryRing = (LinearRing) shells.get(j);
408
				Envelope tryEnv = tryRing.getEnvelopeInternal();
409
				boolean isContained = false;
410
				Coordinate[] coordList = tryRing.getCoordinates();
411
				
412
				//if testpoint is in ring, or test point is a shell point, is contained
413
				if (tryEnv.contains(testEnv) &&
414
						(SnapCGAlgorithms.isPointInRing(testPt, coordList) ||
415
						JtsUtil.pointInList(testPt, coordList))) {
416
					isContained = true;
417
				}
418

  
419
				// check if this new containing ring is smaller than the current minimum ring
420
				if (isContained) {
421
					if ((minShell == null) || minEnv.contains(tryEnv)) {
422
						minShell = tryRing;
423
						minEnv = minShell.getEnvelopeInternal();
424
					}
425
				}
426
			}//for shells
427
			
428
			//At this point, minShell is the shell that contains a testHole
429
			//if minShell is null, we have a SHELL which points were digitized in the
430
			//wrong order
431

  
432
			if (minShell == null) {
433
				
434
				/*
435
				 * TODO
436
				 * Si las clases de FMap incluyesen en su semantica la diferencia
437
				 * entre un shell y un hole, no deberiamos hacer esta suposicion.
438
				 * 
439
				 *  Pero como java.awt.geom.Shape no hace esta distincion,
440
				 *  tenemos que hacerla.
441
				 * 
442
				 * 
443
				 * */
444
				LinearRing reversed = JtsUtil.reverse(testHole);
445
				shells.add(reversed);
446
				holesForShells.add(new ArrayList<LinearRing>());
447
			} else {
448
				((ArrayList<LinearRing>) holesForShells.get(shells.indexOf(minShell))).add(testHole);
449
			}
450
		}//for each hole
451

  
452
		Polygon[] polygons = new Polygon[shells.size()];
453
		for (int i = 0; i < shells.size(); i++) {
454
			polygons[i] = JtsUtil.geomFactory.createPolygon((LinearRing) shells.get(i),
455
					(LinearRing[]) ((ArrayList<LinearRing>) holesForShells.get(i)).toArray(new LinearRing[0]));
456
		}
457
		return JtsUtil.geomFactory.createMultiPolygon(polygons);
458

  
459
	}
460
	
461
	public static Point2D[] getCoordinatesAsPoint2D(Coordinate[] coords){
462
		Point2D[] solution = new Point2D[coords.length];
463
		for(int i = 0; i < coords.length; i++){
464
			solution[i] = new Point2D.Double(coords[i].x, coords[i].y);
465
		}
466
		return solution;
467
	}
468

  
469

  
470
	public static IGeometry createFPolygon(Point2D[] points) {
471
		GeneralPathX gpx = new GeneralPathX();
472
		gpx.moveTo(points[0].getX(), points[0].getY());
473
		for (int i = 1; i < points.length; i++) {
474
			gpx.lineTo(points[i].getX(), points[i].getY());
475
		}
476
		if(! isClosed(gpx)){
477
			gpx.closePath();
478
		}
479
		return ShapeFactory.createPolygon2D(gpx);
480
	}
481
	
198 482
}

Also available in: Unified diff