/*+-------------+----------------------------------------------------------* *| | |_|_|_|_| Fraunhofer-Institut fuer Graphische Datenverarbeitung * *|__|__|_|_|_|_| (Fraunhofer Institute for Computer Graphics) * *| | |_|_|_|_| * *|__|__|_|_|_|_| * *| __ | ___| * *| /_ /_ / _ | Fraunhoferstrasse 5 * *|/ / / /__/ | D-64283 Darmstadt, Germany * *+-------------+----------------------------------------------------------*/ package org.jdesktop.swingx.mapviewer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.geotools.geometry.GeneralDirectPosition; import org.geotools.referencing.CRS; import org.opengis.geometry.DirectPosition; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.cs.AxisDirection; import org.opengis.referencing.operation.MathTransform; import com.google.common.collect.MapMaker; /** * GeotoolsConverter * * @author Simon Templer */ public class GeotoolsConverter implements GeoConverter { private static final Log log = LogFactory.getLog(GeotoolsConverter.class); private static GeotoolsConverter INSTANCE; @SuppressWarnings("deprecation") private final ConcurrentMap<Integer, CoordinateReferenceSystem> crsMap = new MapMaker() .softValues().makeMap(); @SuppressWarnings("deprecation") private final ConcurrentMap<Long, MathTransform> transforms = new MapMaker().softValues() .makeMap(); /** * Get a GeotoolsConverter instance * * @return the converter instance */ public static GeoConverter getInstance() { if (INSTANCE == null) { INSTANCE = new GeotoolsConverter(); } return INSTANCE; } private GeotoolsConverter() { } private CoordinateReferenceSystem getCRS(int epsg) throws NoSuchAuthorityCodeException, FactoryException { CoordinateReferenceSystem r = crsMap.get(epsg); if (r == null) { r = CRS.decode("EPSG:" + epsg, true); crsMap.put(epsg, r); } return r; } private MathTransform getTransform(int srcEpsg, int targetEpsg, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS) throws FactoryException { long key = srcEpsg; key <<= Integer.SIZE; key |= targetEpsg; MathTransform r = transforms.get(key); if (r == null) { r = CRS.findMathTransform(sourceCRS, targetCRS, true); transforms.put(key, r); } return r; } /** * @see GeoConverter#convert(GeoPosition, int) */ @Override public GeoPosition convert(GeoPosition pos, int targetEpsg) throws IllegalGeoPositionException { if (targetEpsg == pos.getEpsgCode()) return new GeoPosition(pos.getX(), pos.getY(), targetEpsg); try { CoordinateReferenceSystem sourceCRS = getCRS(pos.getEpsgCode()); CoordinateReferenceSystem targetCRS = getCRS(targetEpsg); MathTransform math = getTransform(pos.getEpsgCode(), targetEpsg, sourceCRS, targetCRS); int dimension = sourceCRS.getCoordinateSystem().getDimension(); DirectPosition pt1; boolean flipSource = flipCRS(sourceCRS); switch (dimension) { case 2: pt1 = new GeneralDirectPosition((flipSource) ? (pos.getY()) : (pos.getX()), (flipSource) ? (pos.getX()) : (pos.getY())); break; case 3: pt1 = new GeneralDirectPosition((flipSource) ? (pos.getY()) : (pos.getX()), (flipSource) ? (pos.getX()) : (pos.getY()), 0); break; default: log.error("Unsupported dimension: " + dimension); throw new IllegalArgumentException("Unsupported dimension: " + dimension); } DirectPosition pt2 = math.transform(pt1, null); if (flipCRS(targetCRS)) return new GeoPosition(pt2.getOrdinate(1), pt2.getOrdinate(0), targetEpsg); else return new GeoPosition(pt2.getOrdinate(0), pt2.getOrdinate(1), targetEpsg); } catch (Exception e) { throw new IllegalGeoPositionException(e); } } /** * Tries to convert the given list of {@link GeoPosition} to the coordinate * reference system specified by the given target epsg code. * * @param positions a list containing {@link GeoPosition} to convert * @param epsg the epsg code of the target coordinate reference system * * @return the converted list of {@link GeoPosition} * @throws IllegalGeoPositionException if the given {@link GeoPosition} is * invalid or conversion failed */ public List<GeoPosition> convertAll(List<GeoPosition> positions, int epsg) throws IllegalGeoPositionException { List<GeoPosition> newPositions = new ArrayList<GeoPosition>(positions.size()); for (int i = 0; i < positions.size(); i++) { newPositions.add(this.convert(positions.get(i), epsg)); } return newPositions; } /** * This method checks if the the CoordinateSystem is in the way we expected, * or if we have to flip the coordinates. * * @param crs The CRS to be checked. * @return True, if we have to flip the coordinates */ private boolean flipCRS(CoordinateReferenceSystem crs) { if (crs.getCoordinateSystem().getDimension() == 2) { AxisDirection direction = crs.getCoordinateSystem().getAxis(0).getDirection(); if (direction.equals(AxisDirection.NORTH) || direction.equals(AxisDirection.UP)) { return true; } } return false; } }