package jeql.std.geom; import java.util.HashMap; import java.util.Map; import org.osgeo.proj4j.CRSFactory; import org.osgeo.proj4j.CoordinateReferenceSystem; import org.osgeo.proj4j.CoordinateTransform; import org.osgeo.proj4j.CoordinateTransformFactory; import org.osgeo.proj4j.ProjCoordinate; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateFilter; import com.vividsolutions.jts.geom.Geometry; public class CRSFunction { public static double DMStoDD(String dmsStr) { String dms = dmsStr.trim(); // Non-numeric substrings are assumed to be separators (including blanks) String[] comp = dms.split("[^0-9-.]+"); if (comp.length <= 0) return 0.0; double dd = Double.parseDouble(comp[0]); int sgn = dd < 0 ? -1 : 1; if (comp.length >= 2) dd += sgn * Double.parseDouble(comp[1])/60; if (comp.length >= 3) dd += sgn * Double.parseDouble(comp[2])/3600; return dd; } /* public static String DDtoDMS(double dd, String degreeSym, String minSym, String secSym) { } */ public static String projectionName(String projSpec) { return createCRS(projSpec).toString(); } public static String proj4Description(String projSpec) { try { CoordinateReferenceSystem crs = createCRS(projSpec); if (crs == null) return null; return crs.getParameterString(); } catch (UnsupportedOperationException e) { return null; // e.getMessage(); } } /** * Transforms from one projection to another. * * @param g * @param projSpec1 * @param projSpec2 * @return */ public static Geometry transform(Geometry g, String projSpec1, String projSpec2) { Geometry g2 = (Geometry) g.clone(); // TODO: cache this as well g2.apply(new CoordinateTransformFilter( getCRS(projSpec1), getCRS(projSpec2) )); return g2; } /** * Transforms from lon/lat in decimal degrees to a project coordinate system. * * @param g * @param projSpec * @return */ public static Geometry project(Geometry g, String projSpec) { Geometry g2 = (Geometry) g.clone(); CoordinateReferenceSystem crs = getCRS(projSpec); CoordinateReferenceSystem geo = crs.createGeographic(); // TODO: cache this as well g2.apply(new CoordinateTransformFilter( geo, crs )); return g2; } /** * Transforms from a projected coordinate system to lon/lat in decimal degrees. * * @param g * @param projSpec * @return */ public static Geometry inverseProject(Geometry g, String projSpec) { Geometry g2 = (Geometry) g.clone(); CoordinateReferenceSystem crs = getCRS(projSpec); CoordinateReferenceSystem geo = crs.createGeographic(); // TODO: cache this as well g2.apply(new CoordinateTransformFilter( crs, geo )); return g2; } private static Map projCache = new HashMap(); private static CRSFactory crsFactory = new CRSFactory(); private static CoordinateReferenceSystem getCRS(String projStr) { CoordinateReferenceSystem proj = (CoordinateReferenceSystem) projCache.get(projStr); if (proj == null) { proj = createCRS(projStr); projCache.put(projStr, proj); } if (proj == null) throw new IllegalArgumentException("Can't create CRS for '" + projStr + "'"); return proj; } private static CoordinateReferenceSystem createCRS(String projStr) { // TODO: split argsc into array if (projStr.indexOf('=') >= 0) { return crsFactory.createFromParameters("Anon", projStr); } return crsFactory.createFromName(projStr); } private static class CoordinateTransformFilter implements CoordinateFilter { private CoordinateReferenceSystem src; private CoordinateReferenceSystem dest; private ProjCoordinate srcPt = new ProjCoordinate(); private ProjCoordinate destPt = new ProjCoordinate(); private CoordinateTransform transform = null; public CoordinateTransformFilter(CoordinateReferenceSystem src, CoordinateReferenceSystem dest) { this.src = src; this.dest = dest; CoordinateTransformFactory ctf = new CoordinateTransformFactory(); transform = ctf.createTransform(src, dest); } public void filter(Coordinate coord) { srcPt.x = coord.x; srcPt.y = coord.y; transform.transform(srcPt, destPt); coord.x = destPt.x; coord.y = destPt.y; } } }