/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.util; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.factory.Hints; import org.geotools.util.Converter; import org.geotools.util.ConverterFactory; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.MultiPoint; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; /** * Converter factory performing conversions among JTS geometries * of different types. * * - single type geometries (Point, LineString, Polygon) are converted to multi types * (MultiPoint, LineString, MultiPolygon) containing 1 geometry element. * - GeometryCollection(s) are converted to multi types, converting each element to the * permitted type (Point, LineString or Polygon). * * @author m.bartolomeoli * * * * * @source $URL$ */ public class GeometryTypeConverterFactory implements ConverterFactory { private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(GeometryTypeConverterFactory.class); static GeometryFactory gFac=new GeometryFactory(); public Converter createConverter(Class source, Class target, Hints hints) { // we can convert geometric types if(Geometry.class.isAssignableFrom(source) && Geometry.class.isAssignableFrom(target)) { return new Converter() { /** * Converts all the geometries of the given GeometryCollection to a specified * simple type. * @param * @param gc * @param target * @return * @throws Exception */ public List convertAll(GeometryCollection gc,Class target) throws Exception { List result=new ArrayList(); for(int count=0;count nothing to do if(target.isAssignableFrom(source.getClass())) return source; if(source instanceof Geometry) { Geometry sourceGeometry=(Geometry)source; Geometry destGeometry = null; // multi types: for each one we // try the followings: // - if source is we create a multi with just 1 element // - if source is a GeometryCollection, we try to convert each element to // - else we firtsly convert the geometry to a and then we create a multi with the obtained element if(MultiPoint.class.isAssignableFrom(target)) { Point[] points; // NC - Empty Geometry Support if (sourceGeometry.isEmpty()) points = new Point[0]; else if(source instanceof Point) points=new Point[] {(Point)source}; else if(source instanceof GeometryCollection) points=this.convertAll((GeometryCollection)source,Point.class).toArray(new Point[] {}); else points=new Point[] {(Point)this.convert(source,Point.class)}; destGeometry = gFac.createMultiPoint(points); } else if(MultiLineString.class.isAssignableFrom(target)) { LineString[] lineStrings; // NC - Empty Geometry Support if (sourceGeometry.isEmpty()) lineStrings = new LineString[0]; else if(source instanceof LineString) lineStrings=new LineString[] {(LineString)source}; else if(source instanceof GeometryCollection) lineStrings=this.convertAll((GeometryCollection)source,LineString.class).toArray(new LineString[] {}); else lineStrings=new LineString[] {(LineString)this.convert(source,LineString.class)}; destGeometry = gFac.createMultiLineString(lineStrings); } else if(MultiPolygon.class.isAssignableFrom(target)) { Polygon[] polygons; // NC - Empty Geometry Support if (sourceGeometry.isEmpty()) polygons = new Polygon[0]; else if(source instanceof Polygon) polygons=new Polygon[] {(Polygon)source}; else if(source instanceof GeometryCollection) polygons=this.convertAll((GeometryCollection)source,Polygon.class).toArray(new Polygon[] {}); else polygons=new Polygon[] {(Polygon)this.convert(source,Polygon.class)}; destGeometry = gFac.createMultiPolygon(polygons); } // target is a geometrycollection: we add the source to // a new geometrycollection else if(GeometryCollection.class.isAssignableFrom(target)) { // NC - Empty Geometry Support if (sourceGeometry.isEmpty()) destGeometry = gFac .createGeometryCollection(new Geometry[0]); else destGeometry = gFac.createGeometryCollection(new Geometry[] {(Geometry)source}); } // target is a point: we return the centroid of any complex geometry else if(Point.class.isAssignableFrom(target)) { // NC - Empty Geometry Support if (sourceGeometry.isEmpty()) destGeometry = gFac.createPoint((Coordinate) null); else if(source instanceof MultiPoint && sourceGeometry.getNumGeometries()==1) destGeometry = (Geometry) ((MultiPoint)source).getGeometryN(0).clone(); else { if(LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Converting Geometry "+source.toString()+" to Point. This could be unsafe"); destGeometry = ((Geometry)source).getCentroid(); } } // target is a linestring: we return the linestring connecting all the geometry coordinates else if(LineString.class.isAssignableFrom(target)) { // NC - Empty Geometry Support if (sourceGeometry.isEmpty()) destGeometry = gFac.createLineString(new Coordinate[0]); else if(source instanceof MultiLineString && sourceGeometry.getNumGeometries()==1) destGeometry = (Geometry) ((MultiLineString)source).getGeometryN(0).clone(); else { if(LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Converting Geometry "+source.toString()+" to LineString. This could be unsafe"); destGeometry = gFac.createLineString(getLineStringCoordinates(((Geometry)source).getCoordinates())); } } // target is a polygon: we return a polygon connecting all the coordinates of the given geometry else if(Polygon.class.isAssignableFrom(target)) { // NC - Empty Geometry Support if (sourceGeometry.isEmpty()) destGeometry = gFac.createLineString(new Coordinate[0]); else if(source instanceof MultiPolygon && sourceGeometry.getNumGeometries()==1) destGeometry = (Geometry) ((MultiPolygon)source).getGeometryN(0).clone(); else { if(LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Converting Geometry "+source.toString()+" to Polygon. This could be unsafe"); Coordinate[] coords=getPolygonCoordinates(((Geometry)source).getCoordinates()); destGeometry = gFac.createPolygon(gFac.createLinearRing(coords), new LinearRing[] {}); } } // NC - added cloning above for cases where an existing geometry is used // for purpose for changing user data - we don't want any side effects // NC-added, copy userdata if (destGeometry != null) { Map newUserData = new HashMap(); // copy if anything is already in destination data if (destGeometry.getUserData() instanceof Map) { newUserData.putAll((Map) destGeometry.getUserData()); } else if (destGeometry.getUserData() instanceof CoordinateReferenceSystem) { newUserData.put(CoordinateReferenceSystem.class, destGeometry.getUserData()); } // overwrite with source if (sourceGeometry.getUserData() instanceof Map) { newUserData.putAll((Map) sourceGeometry.getUserData()); } else if (sourceGeometry.getUserData() instanceof CoordinateReferenceSystem) { newUserData.put(CoordinateReferenceSystem.class, sourceGeometry.getUserData()); } destGeometry.setUserData(newUserData); } return destGeometry; } return null; } @SuppressWarnings("unchecked") private T[] arrayCopy(T[] original,int length) { Class arrayType = original.getClass().getComponentType(); T[] copy = (T[])java.lang.reflect.Array.newInstance(arrayType, length); System.arraycopy(original, 0, copy, 0, original.length