src/ 0000777 0000000 0000000 00000000000 14573074321 006545 5 ustar src/uk/ 0000777 0000000 0000000 00000000000 14573074157 007173 5 ustar src/uk/co/ 0000777 0000000 0000000 00000000000 14573074222 007565 5 ustar src/uk/co/mccombe/ 0000777 0000000 0000000 00000000000 14573074317 011177 5 ustar src/uk/co/mccombe/mapping/ 0000777 0000000 0000000 00000000000 14573074252 012630 5 ustar src/uk/co/mccombe/mapping/AustrianM28.java 0000777 0000000 0000000 00000003175 14573074222 015556 0 ustar /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package uk.co.mccombe.mapping; /** * * @author Mike */ public class AustrianM28 extends BMN { public AustrianM28(Position p, Ellipsoid e, Datum d){ super(p, e, d); zonename = "M28"; } public AustrianM28(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } public static AustrianM28 makePoint(String gridRef, Ellipsoid e, Datum d)throws GridFormatException { String arg = gridRef.toUpperCase().trim(); java.util.regex.Matcher matcher = pattern.matcher(arg); if (matcher.find()) { String zoneNumber = matcher.group(1); String eastingNum = matcher.group(2); String northingNum = matcher.group(3); try { double xCoord = Double.parseDouble(eastingNum); double yCoord = Double.parseDouble(northingNum); ENPair pa = new ENPair(xCoord, yCoord); return new AustrianM28(pa, e, d); } catch (NumberFormatException ee) { throw new GridFormatException("Illegal BMN format"); } } throw new GridFormatException("Invalid BMN grid reference"); } @Override public double e0() { return 150000.0 ; } @Override public double lamda0() { return Math.toRadians(10.0 + 1.0/3.0); } private static final String validationRegex1 = "(M28)?\\s*(\\d+\\.?\\d*)\\s*(\\d+\\.?\\d*)$"; private static final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(validationRegex1); } src/uk/co/mccombe/mapping/AustrianM31.java 0000777 0000000 0000000 00000003175 14573074221 015547 0 ustar /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package uk.co.mccombe.mapping; /** * * @author Mike */ public class AustrianM31 extends BMN { public AustrianM31(Position p, Ellipsoid e, Datum d){ super(p, e, d); zonename = "M31"; } public AustrianM31(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } public static AustrianM31 makePoint(String gridRef, Ellipsoid e, Datum d)throws GridFormatException { String arg = gridRef.toUpperCase().trim(); java.util.regex.Matcher matcher = pattern.matcher(arg); if (matcher.find()) { String zoneNumber = matcher.group(1); String eastingNum = matcher.group(2); String northingNum = matcher.group(3); try { double xCoord = Double.parseDouble(eastingNum); double yCoord = Double.parseDouble(northingNum); ENPair pa = new ENPair(xCoord, yCoord); return new AustrianM31(pa, e, d); } catch (NumberFormatException ee) { throw new GridFormatException("Illegal BMN format"); } } throw new GridFormatException("Invalid BMN grid reference"); } @Override public double e0() { return 450000.0 ; } @Override public double lamda0() { return Math.toRadians(13.0 + 1.0/3.0); } private static final String validationRegex1 = "(M31)?\\s*(\\d+\\.?\\d*)\\s*(\\d+\\.?\\d*)$"; private static final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(validationRegex1); } src/uk/co/mccombe/mapping/AustrianM34.java 0000777 0000000 0000000 00000003176 14573074221 015553 0 ustar /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package uk.co.mccombe.mapping; /** * * @author Mike */ public class AustrianM34 extends BMN { public AustrianM34(Position p, Ellipsoid e, Datum d){ super(p, e, d); zonename = "M34"; } public AustrianM34(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } public static AustrianM34 makePoint(String gridRef, Ellipsoid e, Datum d)throws GridFormatException { String arg = gridRef.toUpperCase().trim(); java.util.regex.Matcher matcher = pattern.matcher(arg); if (matcher.find()) { String zoneNumber = matcher.group(1); String eastingNum = matcher.group(2); String northingNum = matcher.group(3); try { double xCoord = Double.parseDouble(eastingNum); double yCoord = Double.parseDouble(northingNum); ENPair pa = new ENPair(xCoord, yCoord); return new AustrianM34(pa, e, d); } catch (NumberFormatException ee) { throw new GridFormatException("Illegal BMN format"); } } throw new GridFormatException("Invalid BMN grid reference"); } @Override public double e0() { return 750000.0 ; } @Override public double lamda0() { return Math.toRadians(16.0 + 1.0/3.0); } private static final String validationRegex1 = "(M34)?\\s*(\\d+\\.?\\d*)\\s*(\\d+\\.?\\d*)$"; private static final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(validationRegex1); } src/uk/co/mccombe/mapping/BMN.java 0000777 0000000 0000000 00000004201 14573074222 014104 0 ustar /* */ package uk.co.mccombe.mapping; /** * Abstract base class for the Austrian BMN (Bundesmeldnetz) coordinate system * * @author Mike */ public abstract class BMN extends TransverseMercator { public BMN(Position p, Ellipsoid e, Datum d){ super(p, e, d); } public BMN(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } @Override public Datum defaultDatum() { return Datum.MGI; } @Override public Ellipsoid defaultEllipsoid() { return Ellipsoid.BESSEL;} /** * Provide a String representation of this UTM point in UTM coordinates * @return A UTM coordinate String */ public String toString() { ENPair pa = toEN(); return String.format("%s %8.0f %8.0f", zonename, pa.east(), pa.north()); } /** * The scale factor on the Central Meridian. Generally, Transverse Mercator * projections increasingly exaggerate distances further from the central * meridian. It is usual to reduce the scale factor at the central meridian * to compensate for this effect and optimise the scale over the area of interest. * @return the value of the ScaleFactor at the central meridian. */ @Override public double f0() { return 1.0000 ; } /** * n0() defines the "false northing" distance of the projection. False origins * are usually used with TM projections to ensure that easting and northing * distances are always positive over the area of interest. n0() is used as an * offset to the grid so that the "true origin" appears to have a northing value * equal to n0(). * * @return The false northing distance (double) */ @Override public double n0() { return -5000000.0; } /** * phi0() defines the latitude of the true origin of the projection. * * Note, however, that many Transverse Mercator projections employ a * false origin. See n0() and e0() . * * * @return The latitude of the true origin (radians) */ public double phi0() { return 0; } //Latitude of true origin ; protected String zonename = "XXX" ; } src/uk/co/mccombe/mapping/CoordinateSystem.java 0000777 0000000 0000000 00000010653 14573074222 016774 0 ustar /* * CoordinateSystem.java * * Created on 05 July 2005, 17:17 * */ package uk.co.mccombe.mapping; /** * Abstract base class for coordinate systems in general. * * Each instance of CoordinateSystem contains a Position and references to the * Ellipsoid and Datum from which the coordinates are derived. The position itself is * independent of Ellipsoid and Datum. * @author Mike McCombe */ public abstract class CoordinateSystem { /** * Creates a new instance of CoordinateSystem using the default Ellipsoid and Datum */ protected CoordinateSystem() { } /** *
Create a new instance of CoordinateSystem for a specific Position, Ellipsoid and Datum
* @param pos Position of the point in this CoordinateSystem * @param e Ellipsoid to be used in this CoordinateSystem * @param d Datum for this instance of CopordinateSystem */ public CoordinateSystem(Position pos, Ellipsoid e, Datum d) { locus = pos; sph = e; ref = d; } /** * Get the Latitude and Longitude for this point. Note the result is referred to the current datum and ellipsoid * @return LatLong object containing latitude and longitude */ public LatLong toLatLong() { return locus.toLatLong(sph, ref); } /** * Return a String containing values of Latitude and Longitude.referred to the current Ellipsoid and Datum * @return String containing Latitude and Longitude in degrees. North or East are represented by positive values, South or West are negative. */ public String toLatLongString() { LatLong geog = locus.toLatLong(sph, ref); String res = String.format(java.util.Locale.UK, "%10.6f %11.6f", geog.lat(), geog.lon()); return res; } /** * Get the Datum used by this point * @return The Datum associated with this point */ public Datum getDatum() { return ref; } /** * Get the Ellipsoid used by this point * @return Ellipsoid */ public Ellipsoid getEllipsoid() { return sph; } /** *Get the name of this CoordinateSystem. By default, this method returns the short name of the
* class. For example, an instance of mccombe.mapping.IrishGrid
returns the name "IrishGrid".
Implementers of sub-classes of CoordinateSystem are encouraged to override this method if a * more descriptive name is needed
* @return The name of the CoordinateSystem */ public String getName() { String fullName = getClass().getName(); int i = fullName.lastIndexOf("."); String name = fullName.substring(i + 1); return name; } /** * Get the Position of this point * @return The Position of this point */ public Position getPosition() { return locus; } /** * Get the "absolute" cartesian coordinates for this location. These are based on the WGS-84 datum and coordinate system. * @return XYZ object containing the cartesian coordinates for this point. */ public XYZ getWGS84() { return locus.coords(Datum.WGS_1984); } /** * The default Ellipsoid used by instances of this CoordinateSystem * * For example, a CoordinateSystem of type OSGB has the AirySphere as its default Ellipsoid * @return The Ellipsoid used as the deafult for this CoordinateSystem */ public abstract Ellipsoid defaultEllipsoid(); /** * Get the defaul Datum for an instance of CoordinateSystem. * * For example, instances of OSGB usually use the OSGB 1936 datum. * @return The default Datum used by this instance of CoordinateSystem */ public abstract Datum defaultDatum(); /** * Provide a String representing the position in a correct format for the * CoordinateSystem * @return String */ public abstract String toString(); /* * Parse a String for a double value using the current locale */ protected static double parseDouble(String s) throws java.text.ParseException { java.text.NumberFormat nf = java.text.NumberFormat.getInstance(); return nf.parse(s.trim()).doubleValue(); } /** * The Position of this Coordinate */ protected Position locus; /** * The Ellipsoid for this point */ protected Ellipsoid sph; /** * The Datum for this point */ protected Datum ref; } src/uk/co/mccombe/mapping/Datum.java 0000777 0000000 0000000 00000020166 14573074222 014552 0 ustar /* * Datum.java * * Created on 13 July 2005, 13:13 * */ package uk.co.mccombe.mapping; /** *Datum is the base class for a coordinate system datum. Sub-classes * need to define values for the seven Helmert parameters needed to translate to the * Datum FROM WGS-84
* *An extensive list of Helmert parameters can be found at http://earth-info.nga.mil/GandG/coordsys/datums/helmert.html * Units are *
*s - ppm * rx, ry, rz - seconds of arc. * tx, ty, tz - metres **
* This class also defines a set of static final member instances for common Datums *
* @author Mike McCombe */ public class Datum { /** * Create an instance of Datum using Helmert coefficients in abstract methods */ protected Datum(String name, double tx, double ty, double tz, double rotx, double roty, double rotz, double scale){ datumName = name ; t = new XYZ(-tx, -ty, -tz); rx = -rotx*R ; ry = -roty*R ; rz = -rotz*R ; s = -scale*1.0e-6 ; rot.set(0,0, 1+s); rot.set(0,1, -rz); rot.set(0,2, ry); rot.set(1,0, rz); rot.set(1,1, 1+s); rot.set(1,2, -rx); rot.set(2,0, -ry); rot.set(2,1, rx); rot.set(2,2, 1+s); rin = rot.inverse(); } /** * Converts XYZ coordinates from WGS-84 to this datum using Helmert Transformation * @param from XYZ Coordinates referred to WGS-84 * * @return XYZ Coordinates referred to this datum */ public XYZ fromWGS84(XYZ from){ Vector f = new Vector(from); Vector r = rot.times(f); Vector q = r.plus(t); return new XYZ(q.get(0), q.get(1), q.get(2)) ; } /** * Convert XYZ Coordinates referred to this datum to WGS-84 * @param to XYZ Coordinates to convert * @return XYZ Coordinates referred to WGS-84 */ public XYZ toWGS84(XYZ to){ Vector temp = new Vector(to); Vector q = temp.minus(t); Vector r = rin.times(q); return new XYZ(r.get(0), r.get(1), r.get(2)) ; } /** * Get X translation * @return X translation */ public double tx() { return t.x() ;} /** * Get Y translation * @return Y translation */ public double ty() { return t.y();} /** * Get Z translation * @return Z Translation */ public double tz() {return t.z();} /** * Get rotation about X * @return X rotation */ public double rx() { return rx ;} /** * Get Y rotation * @return Y rotation */ public double ry() { return ry ;} /** * Get Z rotation * @return Z rotation */ public double rz() { return rz ;} /** * Get scale factor adjustment * @return Scale factor adjustment (ppm) */ public double s() { return s ;} /** * Get name of Datum * @return Datum name */ @Override public String toString() { return datumName;} /** * The European (1950) Datum */ public static final Datum ED_1950 = new Datum("European Datum 1950 (Western Europe)", -87.0, -96.0, -120.0, 0.0, 0.0, 0.0, 0.0); /** * The Ireland (1965) Datum */ public static final Datum IRELAND_1965 = new Datum("Ireland 1965", 482.53, -130.596, 564.557, -1.042, -0.214, -0.631, 8.15) ; /** * The French NTF Datum (used in IGN/Lambert projections) */ public static final Datum NTF = new Datum("NTF Datum France (IGN)", -168.0, -60.0, 320.0, 0.0, 0.0, 0.0, 0.0); /** * The OSGB (1936) Datum - used as the Datum for UK Ordnance Survey mapping */ public static final Datum OSGB_1936 = new Datum("Ordnance Survey of Great Britain 1936", 446.448, -125.157, 542.06, 0.150, 0.2470, 0.8421, -20.49); /** * The WGS (1984) Datum */ public static final Datum WGS_1984 = new Datum("WGS-84", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); /** * The Australian (1984) Geodetic Datum */ public static final Datum AUG_7 = new Datum("Australian Geodetic 1984", -116.0, -50.47, 141.69, 0.23, 0.39, 0.344, 0.0983); public static final Datum MGI = new Datum("MGI Datum (Austria)", 577.3,90.1, 463.9, 5.137, 1.474, 5.297, 2.42); //"Official NATO values // public static final Datum MGI = new Datum("MGI Datum (Austria)", 575 ,93, 466, 5.1, 1.6, 5.2, 2.5); //GEO values - see http://homepage.ntlworld.com/anton.helm/bmn_mgi.html public static final Datum MGI_SLOV = new Datum("MGI Datum (Slovenia)", 426.9,142.6,460.1,4.91,4.49,-12.42,17.1); //From OPC - see https://epsg.io/3912-3915 /** * The New Zealand 1949 Datum */ public static final Datum NZGD_1949 = new Datum("New Zealand 1949",59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993); /** * The New Zealand 2000 Datum */ public static final Datum NZGD_2000 = new Datum("New Zealand 2000",0.0,0.0,0.0,0.0,0.0,0.0,0.0); private Matrix rot = new Matrix(); private Matrix rin = new Matrix(); private XYZ t ; private double rx = 0.0 ; private double ry = 0.0 ; private double rz = 0.0 ; private double s = 0.0 ; private String datumName = "" ; private static final double R = 4.848136811095360E-06 ; //Seconds of arc to Radians private class Matrix { Matrix(){ } void set(int ix, int iy, double val){ store[ix][iy] = val ; } double get(int ix, int iy){ return store[ix][iy] ; } Vector times(Vector v){ Vector res = new Vector() ; for(int i=0 ; i<3 ; i++){ double tot = 0.0 ; for(int j=0 ; j<3 ; j++){ tot += store[i][j]*v.v[j] ; } res.set(i, tot); } return res ; } Matrix times(Matrix m){ Matrix res = new Matrix() ; for(int i=0 ; i<3 ; i++){ for(int j=0 ; j<3 ; j++){ double tot = 0.0 ; for(int k=0 ; k<3 ; k++){ tot += store[i][k]*m.store[k][j] ; } res.store[i][j] = tot; } } return res ; } Matrix inverse(){ double d = det(); Matrix res = new Matrix(); for(int i=0 ; i<3 ; i++){ for (int j=0 ; j<3 ; j++){ res.store[j][i] = cofactor(i, j)/d; } } return res ; } double det() { double res = 0.0 ; for (int j=0 ; j<3 ; j++){ res += store[0][j]*cofactor(0,j); } return res ; } double cofactor(int row, int col){ int r1 = ptr[row][0]; int r2 = ptr[row][1]; int c1 = ptr[col][0]; int c2 = ptr[col][1]; double det = store[r1][c1]*store[r2][c2] - store[r1][c2]*store[r2][c1]; double sign = 1.0 ; if(row!=col){ sign = Math.pow(-1.0,(row-col)); } return sign * det ; } private final int[][] ptr = {{1,2},{0,2},{0,1}}; private double[][] store = {{ 0,0,0},{0,0,0},{0,0,0}}; } private class Vector { Vector(){ } Vector(XYZ p){ v[0] = p.x(); v[1] = p.y(); v[2] = p.z(); } void set(int ix, double val){ v[ix] = val ; } double get(int ix) { return v[ix]; } Vector minus(Vector a){ Vector y = new Vector(); for(int ix = 0 ; ix<3 ; ix++){ y.v[ix] = v[ix] - a.v[ix]; } return y ; } Vector minus(XYZ xyz){ Vector p = new Vector(xyz); return minus(p); } Vector plus(Vector a){ Vector y = new Vector(); for(int ix = 0 ; ix<3 ; ix++){ y.v[ix] = v[ix] + a.v[ix]; } return y ; } Vector plus(XYZ xyz){ Vector p = new Vector(xyz); return plus(p); } private double[] v = { 0,0,0}; } } src/uk/co/mccombe/mapping/Ellipsoid.java 0000777 0000000 0000000 00000007126 14573074222 015425 0 ustar /* * Ellipsoid.java * * Created on 05 July 2005, 18:07 * */ package uk.co.mccombe.mapping; /** * Ellipsoid is the base class used to describe the shape * of the earth's surface. It is a biaxial * ellipsoid, slightly flattened at the poles. * * @author Mike McCombe */ public class Ellipsoid { /** * Create an Ellipsoid with specified major and minor exes. * @param name Defines the name of this Ellipsoid * @param major Major axis (m) * * @param minor Minor axis (m) */ protected Ellipsoid(String name, double major, double minor) { majoraxis = major; minoraxis = minor; majsq = majoraxis * majoraxis; minsq = minoraxis * minoraxis; eccsq = (majsq - minsq) / majsq; //eccentricity ^ 2 ecc4 = eccsq * eccsq; ecc6 = eccsq * ecc4; ecc2sq = (majsq - minsq) / minsq; //second eccentricity ^2 ellipsoidName = name; } /** * Major Axis (m) of the spheroid * @return The major axis of the Ellipsoid */ public double majoraxis() { return majoraxis; } /** * Minor axis (m) of the spheroid * @return The minor axis (m) of the Ellipsoid */ public double minoraxis() { return minoraxis; } /** * The eccentricity squared for this Ellipsoid. * @return the eccentricity squared ( i.e. (a^2 - b^2)/(a^2) */ protected double eccsq() { return eccsq; } /** * Provide a String identifying this Ellipsoid * @return The name of this Ellipsoid */ @Override public String toString() { return ellipsoidName; } /** * The Airy Sphere 1830 - "best fit" Ellipsoid for Great Britain */ public static final Ellipsoid AIRY = new Ellipsoid("Airy Sphere 1830", 6377563.396, 6356256.910); /** * The Clarke (1880) Ellipsoid. Used in France with the NTF Datum and * Lambert Conformal Conical (LCC) projection */ public static final Ellipsoid CLARKE = new Ellipsoid("Clarke 1880", 6378249.200, 6356515.000); /** * The Hayford (1909) Ellipsoid. Typically used with he European 1950 (ED50) Datum */ public static final Ellipsoid HAYFORD = new Ellipsoid("Hayford 1909", 6378388.000, 6356911.946); /** * The GRS80 Ellipsoid - "Best fit" ellipsoid for the whole Earth. Defined for Global * Positioning System (GPS) and used with the WGS84 Datum. */ public static final Ellipsoid GRS80 = new Ellipsoid("GRS80", 6378137.0000, 6356752.3141); /** * The "Modified Airy" ellipsoid. The "best fit" Ellipsoid for Ireland and used with the Irish Grid. */ public static final Ellipsoid MODIFIED_AIRY = new Ellipsoid("Airy 1830 Modified", 6377340.189, 6356034.447); /** * The Bessel 1841 Ellipsoid. Used with the Austrian Grid */ public static final Ellipsoid BESSEL = new Ellipsoid("Bessel 1841", 6377397.155, 6356078.962818); /** * The Bessel 1841 Ellipsoid. Used with the Austrian Grid */ public static final Ellipsoid INTERNATIONAL = new Ellipsoid("International 1924", 6378388, 6356911.9461); private double majoraxis = 0.0; //The majoraxis of this Ellipsoid private double minoraxis = 0.0; //The minoraxis of this Ellipsoid private double majsq = majoraxis * majoraxis; private double minsq = minoraxis * minoraxis; private double eccsq = (majsq - minsq) / majsq; //eccentricity ^ 2 private double ecc4 = eccsq * eccsq; private double ecc6 = eccsq * ecc4; private double ecc2sq = (majsq - minsq) / minsq; //second eccentricity ^2 private String ellipsoidName = ""; } src/uk/co/mccombe/mapping/ENPair.java 0000777 0000000 0000000 00000002153 14573074221 014611 0 ustar /* * ENPair.java * * Created on 05 July 2005, 16:56 * */ package uk.co.mccombe.mapping; /** * An ENPair represents a 2-dimensional coordinate pair used to define position on * a map in terms of "easting" and "northing" distances. * @author Mike McCombe */ public class ENPair { /** Creates a new instance of ENPair */ public ENPair() { } /** * Create an ENPair from two double values * @param east Easting distance (m) * @param north Northing distance (m) */ public ENPair(double east, double north){ x = east ; y = north ; } /** * Provide a String representation of the ENPair * @return A String showing Easting and Northing distances */ public String toString() { return String.format("%9.0f %9.0f",x,y);} /** * Access the Easting distance * @return the Easting distance(m) */ public double east() { return x ; } /** * Access the Northing distance * @return the Northing distance (m) */ public double north() { return y ; } private double x = 0.0 ; private double y = 0.0 ; } src/uk/co/mccombe/mapping/GridFormatException.java 0000777 0000000 0000000 00000001032 14573074222 017404 0 ustar package uk.co.mccombe.mapping ; /** * An exception thrown when conversion from grid reference is impossible */ public class GridFormatException extends Exception { /** * Create an exception with the specified message * @param s text * */ public GridFormatException(String s) { super(); val = new String(s) ; } /** * Convert Exception to a String * * @return - the message */ public String toString() { return "GridFormatException -- " + val ; } private String val ; } src/uk/co/mccombe/mapping/IrishGrid.java 0000777 0000000 0000000 00000014637 14573074222 015372 0 ustar /* * IrishGrid.java * * * Created on 24 August 2005, 18:12 * */ package uk.co.mccombe.mapping; /** * Implementation of the Irish Grid. Note that this is used throughout the island of Ireland, * North and South and that the OSGB grid is not applicable. * * * For a complete description of the Irish Grid, see http://www.osni.gov.uk/2.1_the_irish_grid.pdf * @author Mike McCombe */ public class IrishGrid extends TransverseMercator { /** * Create a new IrishGrid point for a specific Position, Ellipsoid and Datum. * @param p Position * @param e Ellipsoid to use with this instance * @param d Datum to use */ public IrishGrid(Position p, Ellipsoid e, Datum d) { super(p, e, d); } /** * Create a new IrishGrid point for a specific pair of Eastings and Northings, Ellipsoid and Datum. * @param point ENPair containing the easting and northing values * @param e Ellipsoid to use with this instance * @param d Datum to use */ public IrishGrid(ENPair point, Ellipsoid e, Datum d) { super(point, e, d); } /** * Create a new IrishGrid point for a specific pair of Eastings and Northings. Default values of Ellipsoid * and Datum are used. * @param point ENPair containing the easting and northing values */ public IrishGrid(ENPair point) { this(point, Ellipsoid.MODIFIED_AIRY, Datum.IRELAND_1965); } /** * Factory method to create a new IrishGrid point using a String containing * a grid reference. * @param gridref A valid Irish grid reference String (e.g. R 212 712) * @param e Ellipsoid to use * @param d Datum to use * @return A new IrishGrid point for the specified point, Ellipsoid and Datum * @throws uk.co.mccombe.mapping.GridFormatException In case of syntax error in he grid reference */ public static IrishGrid makePoint(String gridref, Ellipsoid e, Datum d) throws GridFormatException { ENPair point = getEN(gridref); return new IrishGrid(point, e, d); } private static ENPair getEN(String gridRef) throws GridFormatException { String target = gridRef.toUpperCase().trim(); String eastDigits = ""; String northDigits = ""; String gridLetter = ""; java.util.regex.Matcher match = pattern.matcher(target); if (match.matches()) { int n = match.groupCount(); gridLetter = match.group(1); if (match.group(3) == null) { String digits = match.group(2); int m = digits.length(); if (m % 2 != 0) { throw new GridFormatException("Invalid grid format - odd no. of digits"); } eastDigits = digits.substring(0, m / 2); northDigits = digits.substring(m / 2); } else { eastDigits = match.group(2); northDigits = match.group(3); if (eastDigits.length() != northDigits.length()) { throw new GridFormatException("Invalid grid format - easting and northing must have same no. of digits"); } } } else { throw new GridFormatException("Invalid grid reference format"); } try { double e = Double.parseDouble(justify(eastDigits)); double n = Double.parseDouble(justify(northDigits)); if (gridLetter.length() == 1) { int k = gridLetters.indexOf(gridLetter); int kn = k / 5; int ke = k % 5; e += ke * 100000; n += kn * 100000; } return new ENPair(e, n); } catch (NumberFormatException exc) { throw new GridFormatException("Invalid grid format - incorrect digits"); } } private static String justify(String s) { String padding = "00000"; int i = s.length(); if (i < 5) { int n = 5 - i; return s + padding.substring(0, n); } else if (i > 5) { return s.substring(0, 5) + "." + s.substring(5); } return s; } /** * Defines the default Datum for this system * @return Datum.Ireland_1965 */ public Datum defaultDatum() { return Datum.IRELAND_1965; } /** * Define the default Ellipsoid for this system * @return Ellipsoid.MODIFIED_AIRY */ public Ellipsoid defaultEllipsoid() { return Ellipsoid.MODIFIED_AIRY; } /** * Provide a String representation for this IrishGrid * @return A 10-figure Irish grid reference, with grid letter (e.g. R 21235 71262) */ public String toString() { ENPair en = this.toEN(); int e = (int) Math.round(en.east()); int n = (int) Math.round(en.north()); int j = e / 100000; int k = n / 100000; int m = 5 * k + j; String sq = gridLetters.substring(m, m + 1); j = e % 100000; k = n % 100000; return String.format("%s %05d %05d", sq, j, k); } /** * The central meridian * @return The central meridian (degrees) */ public double lamda0() { return Math.toRadians(-8.0); } /** * False Eastimg (metres) * @return False easting value (metres) */ public double e0() { return 200000.0; } /** * Define false northing * @return False northing value (metres) */ public double n0() { return 250000.0; } /** * Define latitude of true origin * @return Latitude of true origin (degrees) */ public double phi0() { return Math.toRadians(53.5); } /** * Define scale factor * @return Scale factor at central meridian */ public double f0() { return 1.000035; } private static final String gridLetters = "VWXYZQRSTULMNOPFGHJKABCDE"; private static final String regex = "([A-HJ-Z])\\p{javaWhitespace}*([0-9]+)\\p{javaWhitespace}*([0-9]+)??"; private static final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(regex); protected static boolean validateEN(ENPair p) { double x = p.east(); double y = p.north(); return (x >= MIN_E && x < MAX_E && y >= MIN_N && y < MAX_N); } private static final double MAX_E = 500000.0; private static final double MIN_E = 0.0; private static final double MAX_N = 500000.0; private static final double MIN_N = 0.0; } src/uk/co/mccombe/mapping/Lambert.java 0000777 0000000 0000000 00000025402 14573074222 015064 0 ustar /* * Lambert.java * * Created on 05 July 2005, 22:15 */ package uk.co.mccombe.mapping; /** *An abstract base class for implementations of the Lambert Conformal Conic Projection
*A Lambert projection maps points on the ellipsoid onto a cone which touches the ellipsoid * at two parallels of latitude. For countries with a large east-west extent, it provides smaller * variations in grid convergence than the more common TransverseMercator projection - but over * a limited range of latitude. IGN, France's national mapping agency, adopted the Lambert * Conformal Conic projection but had to divide mainland France into three zones of latitude, * with a fourth zone for the island of Corsica. These are implemented in this package as * subclasses of Lambert (see {@link uk.co.mccombe.mapping.LambertI LambertI}, * {@link uk.co.mccombe.mapping.LambertII LambertII}, * {@link uk.co.mccombe.mapping.LambertIII LambertIII}, * {@link uk.co.mccombe.mapping.LambertIV LambertIV}). To overcome the obvious inconvenience of * having the country divided into four distinct coordinate zones, a fifth set of Lambert Conformal Conical * projection coefficients {@link uk.co.mccombe.mapping.LambertIIExtended LambertIIExtended} was produced to * provide a nationwide coordinate system but with greater degrees of distortion. Ironically, * the Lambert Conical projections have not been well-supported by handheld GPS equipment and * many French maps (such as the 1:25000 Blue Series) are now over-printed with a UTM grid.
*In 1996, IGN introduced a new coordinate system known as {@link uk.co.mccombe.mapping.Lambert93 Lambert 93} *
* @author Mike McCombe * @see ETRS89 Lambert Conformal Conic Coordinate Reference System * @see Systemes de Projection (in French) */ public abstract class Lambert extends uk.co.mccombe.mapping.Projection { /** * Creates a new instance of Lambert based on Position, Ellipsoid and Datum * @param p Position of this point * @param e The Ellipsoid to use * @param d The Datum associated with this instance */ public Lambert(Position p, Ellipsoid e, Datum d){ super(p, e, d); LatLong geog = p.toLatLong(e, d); double qL = q(phiL()); double qU = q(phiU()); double qB = q(phiB()); double wL = w(phiL()); double wU = w(phiU()); double sp0 = Math.log(wU*Math.cos(phiL())/(wL*Math.cos(phiU())))/(qU-qL); double a = sph.majoraxis(); double k = (a*Math.cos(phiL())*Math.exp(qL*sp0))/(wL*sp0); //Mapping radius at equator double r0 = k / Math.exp(qB*sp0); double q = q(Math.toRadians(geog.lat())); double r = k / Math.exp(q*sp0); gamma = (lamda0() - Math.toRadians(geog.lon()))*sp0 ; east = e0() - r*Math.sin(gamma); north = r0 + n0() - r*Math.cos(gamma); double sp = Math.sin(Math.toRadians(geog.lat())); scaleFactor = Math.sqrt(1 - sph.eccsq()*sp*sp)*r*sp0/(a*Math.cos(Math.toRadians(geog.lat()))); } /** * Create a new Lambert object based on Easting and Northing distances * @param en Easting and Northing values * @param sphere The Ellipsoid to use * @param datum the Datum to use */ public Lambert(ENPair en, Ellipsoid sphere, Datum datum) { sph = sphere ; ref = datum ; double xCoord = en.east() ; double yCoord = en.north() ; double qL = q(phiL()); double qU = q(phiU()); double qB = q(phiB()); double wL = w(phiL()); double wU = w(phiU()); double sp0 = Math.log(wU*Math.cos(phiL())/(wL*Math.cos(phiU())))/(qU-qL); double a = sph.majoraxis(); double k = (a*Math.cos(phiL())*Math.exp(qL*sp0))/(wL*sp0); //Mapping radius at equator double r0 = k / Math.exp(qB*sp0); double rdash = r0 - yCoord + n0() ; double edash = e0() - xCoord ; double r = Math.sqrt(edash*edash + rdash*rdash); double q = Math.log(k/r)/sp0 ; gamma = Math.atan(edash/rdash); double lamda = lamda0() - gamma/sp0 ; double sp = (Math.exp(2*q) - 1.0)/(Math.exp(2*q)+1); double corr = 1.0 ; double e = Math.sqrt(sph.eccsq()); while (Math.abs(corr) > LIMIT){ double f1 = (Math.log((1+sp)/(1-sp)) - e*Math.log((1+e*sp)/(1-e*sp)))/2.0 - q ; double f2 = 1/(1-sp*sp) - sph.eccsq()/(1-sph.eccsq()*sp*sp); corr = -f1/f2 ; sp += corr ; } double lat = Math.toDegrees(Math.asin(sp)); double lon = Math.toDegrees(lamda); scaleFactor = Math.sqrt(1 - sph.eccsq()*sp*sp)*r*sp0/(a*Math.cos(Math.asin(sp))); locus = new Position(new LatLong(lat,lon), 0.0, sphere, datum); } /** * Parse Lambert coordinates into easting and northing distances * @param gridref A pair of Lambert coordinates (e.g. "X=435.212 Y=217.306"), specified in km. * @throws uk.co.mccombe.mapping.GridFormatException Invalid coordinate format results in a GridFormatException being thrown * @return Easting and Northing distances (m) */ protected static ENPair getEN(String gridref) throws GridFormatException { double xCoord = 0.0 ; double yCoord = 0.0 ; boolean gotX = false ; boolean gotY = false ; try { String regex = "[ \t=]+"; String[] parts = gridref.split(regex); int n = parts.length ; switch (n) { case 2 : { xCoord = parseDouble(parts[0]); yCoord = parseDouble(parts[1]); break ; } case 4 : { for(int i=0 ; i<4 ; i+=2){ if(parts[i].equalsIgnoreCase("X")){ xCoord = parseDouble(parts[i+1]); gotX = true ; } else if(parts[i].equalsIgnoreCase("Y")){ yCoord = parseDouble(parts[i+1]); gotY = true ; } } if(gotX && gotY) break ; } default : { throw new GridFormatException("Invalid Lambert Coordinate String"); } } } catch (java.util.regex.PatternSyntaxException e){ throw new GridFormatException("Invalid Lambert Coordinate String"); } catch (NumberFormatException e){ throw new GridFormatException("Invalid Lambert Coordinate String"); } catch (java.text.ParseException e){ throw new GridFormatException("Invalid Lambert Coordinate String"); } return new ENPair(xCoord*1000.0, yCoord*1000.0); } /** * Provide easting and northing distances * @return Easting and Northing distances (in metres) */ public ENPair toEN() { calcCoords(); return new ENPair(east,north); } /** * Provide a String representation in Lambert coordinates. * These are of the form "X=eeee.eee Y=nnnn.nnn" where eeee.eee and nnnn.nnn are the easting and northing * distances in km. * @return The coordinate String */ public String toString(){ calcCoords(); String res = String.format("X = %11.3f Y = %11.3f", east/1000.0, north/1000.0); return res ; } /** * Initialise coordinates for this Position */ protected void calcCoords() { LatLong geog = locus.toLatLong(sph, ref); double qL = q(phiL()); double qU = q(phiU()); double qB = q(phiB()); double wL = w(phiL()); double wU = w(phiU()); double sp0 = Math.log(wU*Math.cos(phiL())/(wL*Math.cos(phiU())))/(qU-qL); double a = sph.majoraxis(); double k = (a*Math.cos(phiL())*Math.exp(qL*sp0))/(wL*sp0); //Mapping radius at equator double r0 = k / Math.exp(qB*sp0); double q = q(Math.toRadians(geog.lat())); double r = k / Math.exp(q*sp0); gamma = (lamda0() - Math.toRadians(geog.lon()))*sp0 ; east = e0() - r*Math.sin(gamma); north = r0 + n0() - r*Math.cos(gamma); double sp = Math.sin(Math.toRadians(geog.lat())); scaleFactor = Math.sqrt(1 - sph.eccsq()*sp*sp)*r*sp0/(a*Math.cos(Math.toRadians(geog.lat()))); } /** * Calculate grid convergence * @return Grid convergence (degrees) */ public double gridConvergence(){ this.calcCoords(); return Math.toDegrees(gamma) ; } /** * Define the default datum for this coordinate system * @return default datum */ public uk.co.mccombe.mapping.Datum defaultDatum() { return Datum.NTF ; } /** * Define the default Ellipsoid for this coordinate system * @return default Ellipsoid */ public uk.co.mccombe.mapping.Ellipsoid defaultEllipsoid() { return Ellipsoid.CLARKE ; } private double q(double lat) { double e = Math.sqrt(sph.eccsq()); double sp = Math.sin(lat); double res = (Math.log((1+sp)/(1-sp)) - e*Math.log((1+e*sp)/(1-e*sp)))/2.0 ; return res ; } private double w(double lat){ double e = Math.sqrt(sph.eccsq()); double sp = Math.sin(lat); double res = Math.sqrt(1 - sph.eccsq()*sp*sp); return res ; } //Define abstract methods for projection constants /** * Define Upper standard parallel for this conical projection * @return Upper Standard Parallel (radians) */ protected abstract double phiU() ; //Upper parallel /** * Define lower standard parallel for this projection * @return Lower Standard Parallel (radians) */ protected abstract double phiL() ; //Lower parallel /** * Define latitude of false origin * @return Latitude of false origin (radians) */ protected abstract double phiB() ; //Latitude of false origin /** * Define longitude of grid origin * @return Longitude of grid origin (radians) */ protected abstract double lamda0() ;//Longitude of grid origin /** * Define false easting value * @return False easting (m) */ protected abstract double e0() ; //False easting /** * Define false northing * @return False northing distance (m) */ protected abstract double n0() ; //False northing // Local variables private double scaleFactor = 1.0 ; //Scale factor private double gamma = 0.0 ; //Grid convergence private double east = 0.0 ; //Easting value private double north = 0.0 ; //Northing value private static final double LIMIT = 1.0E-7 ; //Convergence limit } src/uk/co/mccombe/mapping/Lambert93.java 0000777 0000000 0000000 00000006404 14573074222 015241 0 ustar /* * Lambert93.java * * Created on 24 October 2006, 22:49 * */ package uk.co.mccombe.mapping; /** * A non-abstract class implementing the Lambert Conformal Conical (LCC) projection * for the French Lambert-93 system. Unlike previous French LCC implementations, this one * uses GRS80/WGS84 ellipsoid and datum by default. * * @author Mike McCombe */ public class Lambert93 extends Lambert{ /** * Create an instance of Lambert93 from Position, Ellipsoid and Datum * @param p the position of this point * @param e The Ellipsoid to use * @param d The datum to be used */ public Lambert93(Position p, Ellipsoid e, Datum d){ super(p, e, d); } /** * Create an instance of Lambert93 from easting and northing distances, Ellipsoid and Datum * @param en Easting and Northing distances * @param e Ellipsoid to use * @param d Datum to use */ public Lambert93(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } /** * Static factory method to create an instance of Lambert93 from a grid reference String * @param gridref A grid reference of the form "X=... Y=..." where the values are easting and * northing distances in km. * @param e Ellipsoid to use in conversions * @param d Datum to use in conversions * @throws uk.co.mccombe.mapping.GridFormatException thrown in case of format error in the grid reference * @return A new LambertI instance */ public static Lambert93 makePoint(String gridref, Ellipsoid e, Datum d)throws GridFormatException { ENPair en = getEN(gridref); return new Lambert93(en, e, d); } /** * Define default Datum for this system * @return the default Datum (Datum.WGS_1984) */ public uk.co.mccombe.mapping.Datum defaultDatum() { return Datum.WGS_1984 ; } /** * Define the default Ellipsoid for this system * @return the default Ellipsoid (Ellipsoid.GRS80) */ public uk.co.mccombe.mapping.Ellipsoid defaultEllipsoid() { return Ellipsoid.GRS80 ; } // Projection constants /** * Define Upper standard parallel for this conical projection * @return Upper Standard Parallel (radians) */ protected double phiU() { return Math.toRadians(49.0);} //Upper parallel /** * Define lower standard parallel for this projection * @return Lower Standard Parallel (radians) */ protected double phiL() { return Math.toRadians(44.0);} //Lower parallel /** * Define latitude of false origin * @return Latitude of false origin (radians) */ protected double phiB() { return Math.toRadians(46.5);} //Latitude of false grid origin /** * Define longitude of grid origin * @return Longitude of grid origin (radians) */ protected double lamda0() { return Math.toRadians(3.0);}//Longitude grid origin /** * Define false easting value * @return False easting (m) */ protected double e0() { return 700000.0;} //False easting /** * Define false northing * @return False northing distance (m) */ protected double n0() { return 6600000.0 ;} //False northing } src/uk/co/mccombe/mapping/LambertI.java 0000777 0000000 0000000 00000006164 14573074222 015201 0 ustar /* * LambertI.java * * Created on 19 July 2005, 09:30 * */ package uk.co.mccombe.mapping; /** * A non-abstract class implementing the Lambert Conformal Conical projection * for Zone 1 (Northern France between latitudes 48.15 and 51.3 degrees N) * @author Mike McCombe */ public class LambertI extends Lambert { /** * Create an instance of LambertI from Position, Ellipsoid and Datum * @param p the position of this point * @param e The Ellipsoid to use * @param d The datum to be used */ public LambertI(Position p, Ellipsoid e, Datum d){ super(p, e, d); } /** * Create an instance of LambertI from easting and northing distances, Ellipsoid and Datum * @param en Easting and Northing distances * @param e Ellipsoid to use * @param d Datum to use */ public LambertI(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } /** * Static factory method to create an instance of LambertI from a grid reference String * @param gridref A grid reference of the form "X=... Y=..." where the values are easting and * northing distances in km. French convention sometimes includes the zone number as the first * digit of the Y (northing) coordinate (e.g. "Y=1210.98" denoting a northing distance of 210.98km * in zone 1). If present, this is ignored. * @param e Ellipsoid to use in conversions * @param d Datum to use in conversions * @throws uk.co.mccombe.mapping.GridFormatException thrown in case of format error in the grid reference * @return A new LambertI instance */ public static LambertI makePoint(String gridref, Ellipsoid e, Datum d)throws GridFormatException { ENPair en = getEN(gridref); double y = en.north(); if(y>=1000000.0 && y<2000000.0) { y -=1000000.0; double x = en.east(); en = new ENPair(x,y); } return new LambertI(en, e, d); } // Projection constants /** * Define Upper standard parallel for this conical projection * @return Upper Standard Parallel (radians) */ protected double phiU() { return Math.toRadians(50.39591167);} //Upper parallel /** * Define lower standard parallel for this projection * @return Lower Standard Parallel (radians) */ protected double phiL() { return Math.toRadians(48.59852278);} //Lower parallel /** * Define latitude of false origin * @return Latitude of false origin (radians) */ protected double phiB() { return Math.toRadians(49.5);} //Latitude of false grid origin /** * Define longitude of grid origin * @return Longitude of grid origin (radians) */ protected double lamda0() { return Math.toRadians(2.337229167);} //Longitude grid origin /** * Define false easting value * @return False easting (m) */ protected double e0() { return 600000 ;} //False easting /** * Define false northing * @return False northing distance (m) */ protected double n0() { return 200000 ;} //False northing } src/uk/co/mccombe/mapping/LambertII.java 0000777 0000000 0000000 00000006206 14573074222 015307 0 ustar /* * LambertII.java * * Created on 19 July 2005, 09:23 * */ package uk.co.mccombe.mapping; /** * A non-abstract class implementing the Lambert Conformal Conical projection * for Zone 2 (Central France between latitudes 45.45 and 48.15 degrees N) * @author Mike McCombe */ public class LambertII extends Lambert { /** * Create an instance of LambertII from Position, Ellipsoid and Datum * @param p the position of this point * @param e The Ellipsoid to use * @param d The datum to be used */ public LambertII(Position p, Ellipsoid e, Datum d){ super(p, e, d); } /** * Create an instance of LambertII from easting and northing distances, Ellipsoid and Datum * @param en Easting and Northing distances * @param e Ellipsoid to use * @param d Datum to use */ public LambertII(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } /** * Static factory method to create an instance of LambertII from a grid reference String * @param gridref A grid reference of the form "X=... Y=..." where the values are easting and * northing distances in km. French convention sometimes includes the zone number as the first * digit of the Y (northing) coordinate (e.g. "Y=3210.98" denoting a northing distance of 210.98km * in zone 3). If present, this is ignored. * @param e Ellipsoid to use in conversions * @param d Datum to use in conversions * @throws uk.co.mccombe.mapping.GridFormatException thrown in case of format error in the grid reference * @return A new LambertI instance */ public static LambertII makePoint(String gridref, Ellipsoid e, Datum d)throws GridFormatException { ENPair en = getEN(gridref); double y = en.north(); if(y>=2000000.0 && y<3000000.0) { y -=2000000.0 ; double x = en.east(); en = new ENPair(x,y); } return new LambertII(en, e, d); } // Projection constants /** * Define Upper standard parallel for this conical projection * @return Upper Standard Parallel (radians) */ protected double phiU() { return Math.toRadians(47.69601444);} //Upper parallel /** * Define lower standard parallel for this projection * @return Lower Standard Parallel (radians) */ protected double phiL() { return Math.toRadians(45.89891889);} //Lower parallel /** * Define latitude of false origin * @return Latitude of false origin (radians) */ protected double phiB() { return Math.toRadians(46.8);} //Latitude of false grid origin /** * Define longitude of grid origin * @return Longitude of grid origin (radians) */ protected double lamda0() { return Math.toRadians(2.337229167);} //Longitude grid origin /** * Define false easting value * @return False easting (m) */ protected double e0() { return 600000 ;} //False easting /** * Define false northing * @return False northing distance (m) */ protected double n0() { return 200000 ;} //False northing } src/uk/co/mccombe/mapping/LambertIIExtended.java 0000777 0000000 0000000 00000005434 14573074222 016772 0 ustar /* * LambertIIExtended.java * * Created on 15 July 2005, 18:50 * */ package uk.co.mccombe.mapping; /** * A non-abstract class implementing the Lambert Conformal Conical projection * for Zone 2-extended (all of mainland France and Corsica) * @author Mike McCombe */ public class LambertIIExtended extends Lambert { /** * Create an instance of LambertIIExtended from Position, Ellipsoid and Datum * @param p the position of this point * @param e The Ellipsoid to use * @param d The datum to be used */ public LambertIIExtended(Position p, Ellipsoid e, Datum d){ super(p, e, d); } /** * Create an instance of LambertIIExtended from easting and northing distances, Ellipsoid and Datum * @param en Easting and Northing distances * @param e Ellipsoid to use * @param d Datum to use */ public LambertIIExtended(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } /** * Static factory method to create an instance of LambertII from a grid reference String * @param gridref A grid reference of the form "X=... Y=..." where the values are easting and * northing distances in km. * @param e Ellipsoid to use in conversions * @param d Datum to use in conversions * @throws uk.co.mccombe.mapping.GridFormatException thrown in case of format error in the grid reference * @return A new LambertI instance */ public static LambertIIExtended makePoint(String gridref, Ellipsoid e, Datum d)throws GridFormatException { ENPair en = getEN(gridref); return new LambertIIExtended(en, e, d); } // Projection constants /** * Define Upper standard parallel for this conical projection * @return Upper Standard Parallel (radians) */ protected double phiU() { return Math.toRadians(47.69601444);} //Upper parallel /** * Define lower standard parallel for this projection * @return Lower Standard Parallel (radians) */ protected double phiL() { return Math.toRadians(45.89891889);} //Lower parallel /** * Define latitude of false origin * @return Latitude of false origin (radians) */ protected double phiB() { return Math.toRadians(46.8);} //Latitude of false grid origin /** * Define longitude of grid origin * @return Longitude of grid origin (radians) */ protected double lamda0() { return Math.toRadians(2.337229167);} //Longitude grid origin /** * Define false easting value * @return False easting (m) */ protected double e0() { return 600000 ;} //False easting /** * Define false northing * @return False northing distance (m) */ protected double n0() { return 2200000 ;} //False northing } src/uk/co/mccombe/mapping/LambertIII.java 0000777 0000000 0000000 00000006206 14573074222 015420 0 ustar /* * LambertIII.java * * Created on 19 July 2005, 09:44 * */ package uk.co.mccombe.mapping; /** * A non-abstract class implementing the Lambert Conformal Conical projection * for Zone 3 (Southern France between latitudes 42.3 and 45.45 degrees N) * * @author Mike McCombe */ public class LambertIII extends Lambert { /** * Create an instance of LambertIII from Position, Ellipsoid and Datum * @param p the position of this point * @param e The Ellipsoid to use * @param d The datum to be used */ public LambertIII(Position p, Ellipsoid e, Datum d){ super(p, e, d); } /** * Create an instance of LambertIII from easting and northing distances, Ellipsoid and Datum * @param en Easting and Northing distances * @param e Ellipsoid to use * @param d Datum to use */ public LambertIII(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } /** * Static factory method to create an instance of LambertIII from a grid reference String * @param gridref A grid reference of the form "X=... Y=..." where the values are easting and * northing distances in km. French convention sometimes includes the zone number as the first * digit of the Y (northing) coordinate (e.g. "Y=2210.98" denoting a northing distance of 210.98km * in zone 2). If present, this is ignored. * @param e Ellipsoid to use in conversions * @param d Datum to use in conversions * @throws uk.co.mccombe.mapping.GridFormatException thrown in case of format error in the grid reference * @return A new LambertI instance */ public static LambertIII makePoint(String gridref, Ellipsoid e, Datum d)throws GridFormatException { ENPair en = getEN(gridref); double y = en.north(); if(y>=3000000.0 && y<4000000.0) { y -=3000000.0 ; double x = en.east(); en = new ENPair(x,y); } return new LambertIII(en, e, d); } // Projection constants /** * Define Upper standard parallel for this conical projection * @return Upper Standard Parallel (radians) */ protected double phiU() { return Math.toRadians(44.99609389);} //Upper parallel /** * Define lower standard parallel for this projection * @return Lower Standard Parallel (radians) */ protected double phiL() { return Math.toRadians(43.19929139);} //Lower parallel /** * Define latitude of false origin * @return Latitude of false origin (radians) */ protected double phiB() { return Math.toRadians(44.1);} //Latitude of false grid origin /** * Define longitude of grid origin * @return Longitude of grid origin (radians) */ protected double lamda0() { return Math.toRadians(2.337229167);} //Longitude grid origin /** * Define false easting value * @return False easting (m) */ protected double e0() { return 600000 ;} //False easting /** * Define false northing * @return False northing distance (m) */ protected double n0() { return 200000 ;} //False northing } src/uk/co/mccombe/mapping/LambertIV.java 0000777 0000000 0000000 00000006117 14573074222 015325 0 ustar /* * LambertIV.java * * Created on 19 July 2005, 09:50 * */ package uk.co.mccombe.mapping; /** * A non-abstract class implementing the Lambert Conformal Conical projection * for Zone 4 (Corsica) * @author Mike McCombe */ public class LambertIV extends Lambert { /** * Create an instance of LambertIV from Position, Ellipsoid and Datum * @param p the position of this point * @param e The Ellipsoid to use * @param d The datum to be used */ public LambertIV(Position p, Ellipsoid e, Datum d){ super(p, e, d); } /** * Create an instance of LambertIV from easting and northing distances, Ellipsoid and Datum * @param en Easting and Northing distances * @param e Ellipsoid to use * @param d Datum to use */ public LambertIV(ENPair en, Ellipsoid e, Datum d){ super(en, e, d); } /** * Static factory method to create an instance of LambertIV from a grid reference String * @param gridref A grid reference of the form "X=... Y=..." where the values are easting and * northing distances in km. French convention sometimes includes the zone number as the first * digit of the Y (northing) coordinate (e.g. "Y=4210.98" denoting a northing distance of 210.98km * in zone 4). If present, this is ignored. * @param e Ellipsoid to use in conversions * @param d Datum to use in conversions * @throws uk.co.mccombe.mapping.GridFormatException thrown in case of format error in the grid reference * @return A new LambertI instance */ public static LambertIV makePoint(String gridref, Ellipsoid e, Datum d)throws GridFormatException { ENPair en = getEN(gridref); double y = en.north(); if(y>=4000000.0 && y<5000000.0) { y -=4000000.0 ; double x = en.east(); en = new ENPair(x,y); } return new LambertIV(en, e, d); } // Projection constants /** * Define Upper standard parallel for this conical projection * @return Upper Standard Parallel (radians) */ protected double phiU() { return Math.toRadians(42.76766333);} //Upper parallel /** * Define lower standard parallel for this projection * @return Lower Standard Parallel (radians) */ protected double phiL() { return Math.toRadians(41.56038778);} //Lower parallel /** * Define latitude of false origin * @return Latitude of false origin (radians) */ protected double phiB() { return Math.toRadians(42.165);} //Latitude of false grid origin /** * Define longitude of grid origin * @return Longitude of grid origin (radians) */ protected double lamda0() { return Math.toRadians(2.337229167);} //Longitude grid origin /** * Define false easting value * @return False easting (m) */ protected double e0() { return 234.358 ;} //False easting /** * Define false northing * @return False northing distance (m) */ protected double n0() { return 185861.369 ;} //False northing } src/uk/co/mccombe/mapping/LatLong.java 0000777 0000000 0000000 00000011156 14573074222 015037 0 ustar /* * LatLong.java * * Created on 05 July 2005, 16:24 * */ package uk.co.mccombe.mapping; /** * A simple immutable wrapper class for Latitude and Longitude values * @author Mike McCombe */ public class LatLong { /** Creates a new instance of LatLong */ public LatLong() { } /** * Create LatLong instance from specified values of Lat and Lon. * @param lat Latitude (degrees) * @param lon Longitude (degrees) */ public LatLong(double lat, double lon) { y = lat ; x = lon ; } /** * A static method to turn values of degrees, minutes and seconds into a latitude value. * @param ns "N" or "S". Points south of the equator have negative values of latitude. * @param deg Degrees. Value must not exceed 90. * @param min Minutes - zero or positive, less than 60. * @param sec Seconds - zero or positive real value less than 60.0 * @throws uk.co.mccombe.mapping.LatLongFormatException if the degrees/minutes/seconds values do not correspond to legal latitudes between * 0 and 90.0 or if ns is neither "N" nor "S" * @return value in the range -90.0 to +90.0 */ public static double latDMS(String ns, int deg, int min, double sec) throws LatLongFormatException { if(ns.length()!=1 || legalNS.indexOf(ns.toUpperCase())<0) throw new LatLongFormatException(String.format("Invalid N/S specifier <%s>",ns)); double sign = 1.0 ; if(legalNS.indexOf(ns.toUpperCase())>0) sign = -1.0 ; if ( deg>90 || deg <0) throw new LatLongFormatException(String.format("Invalid degrees value <%d>",deg)); if ( min>59 || min <0) throw new LatLongFormatException(String.format("Invalid minutes value <%d>",min)); if (sec>=60 || sec <0) throw new LatLongFormatException(String.format("Invalid seconds value <%d>",sec)); double result = sign*((double)deg + (double)min/60.0 + sec/3600.0); return result ; } /** * A static method to turn values of degrees, minutes and seconds into a longitude value. * @param ew "E" or "W". Points west of the reference meridian have negative values of longitude. * @param deg Degrees. Value must not exceed 180. * @param min Minutes - zero or positive, less than 60. * @param sec Seconds - zero or positive real value less than 60.0 * @throws uk.co.mccombe.mapping.LatLongFormatException if the degrees/minutes/seconds values do not correspond to legal longitudes between * 0 and 180.0 or if ew is neither "E" nor "W" * @return value in the range -180.0 to +180.0 */ public static double lonDMS(String ew, int deg, int min, double sec) throws LatLongFormatException { if(ew.length()!=1 || legalEW.indexOf(ew.toUpperCase())<0) throw new LatLongFormatException(String.format("Invalid E/W specifier <%s>",ew)); double sign = 1.0 ; if(legalEW.indexOf(ew.toUpperCase())>0) sign = -1.0 ; if (deg>180 || deg <0) throw new LatLongFormatException(String.format("Invalid degrees value <%d>",deg)); if ( min>59 || min <0) throw new LatLongFormatException(String.format("Invalid minutes value <%d>",min)); if (sec>=60 || sec <0) throw new LatLongFormatException(String.format("Invalid seconds value <%f>",sec)); if (deg==180 && (min!=0 || sec!=0)) throw new LatLongFormatException(String.format("Invalid minutes and seconds values <%d %f>",min,sec)); double result = sign*((double)deg + (double)min/60.0 + sec/3600.0); return result ; } /** * Get the latitude component * @return Latitude (degrees) */ public double lat() { return y ; } /** * Get the longitude component * @return Longitude (degrees) */ public double lon() { return x ; } /** * Provide a String representing this latitude and longitude. * @return The String representation of the coordinates (in Lat/Lon format) */ public String toString() { return toDMS(lat(), "NS") + " " + toDMS(lon(), "EW"); } public static String toDMS(double v, String signs) { double v1 = Math.abs(v) ; double s = Math.round(v1*36000.0) ; double sec = s % 600 ; s = Math.round((s-sec)/600.0) ; sec = sec / 10.0 ; double min = s % 60 ; double deg = Math.round((s-min)/60) ; String sign = signs.substring(0, 1) ; if(v<0) sign = signs.substring(1, 2); return String.format(java.util.Locale.UK,"%3.0f %s %2.0f\' %4.1f\"", deg, sign, min, sec); } private double x = 0.0 ; private double y = 0.0 ; private static final String legalNS = "NS"; private static final String legalEW = "EW"; } src/uk/co/mccombe/mapping/LatLongFormatException.java 0000777 0000000 0000000 00000001432 14573074222 020063 0 ustar /* * LatLongFormatException.java * * Created on 02 November 2007, 17:11 * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ package uk.co.mccombe.mapping; /** * An exception class for errors in Latitude and Longitude formats * @author Mike */ public class LatLongFormatException extends java.lang.Exception { /** * Creates a new instance ofLatLongFormatException
without detail message.
*/
public LatLongFormatException() {
}
/**
* Constructs an instance of LatLongFormatException
with the specified detail message.
* @param msg the detail message.
*/
public LatLongFormatException(String msg) {
super(msg);
}
}
src/uk/co/mccombe/mapping/MappingToolkit.java 0000777 0000000 0000000 00000026610 14573101251 016432 0 ustar package uk.co.mccombe.mapping;
import java.lang.reflect.*;
/**
* MappingToolkit provides access to standard features of the mapping package by name.
* It is particularly useful in a GUI environment where the user needs to be able to
* select from lists of CoordinateSystems, Datums and Ellipsoids
*
* @author Mike McCombe
*/
public class MappingToolkit {
/**
* Construct a new MappingToolkit
*/
public MappingToolkit() {
LatLong latlon = new LatLong(52.0, -2.0);
ENPair en = new ENPair(100000.0, 100000.0);
Spherical sph = new Spherical(latlon, Ellipsoid.GRS80, Datum.WGS_1984);
MapEntry sp = new MapEntry(sph, "52.375, -2.70916");
coordmap.put(sp.getName(), sp);
MapEntry p1 = new MapEntry(new OSGB(en, Ellipsoid.AIRY, Datum.OSGB_1936), "ST 430969");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new LambertIIExtended(en, Ellipsoid.CLARKE, Datum.NTF), "X=455.23 Y = 2302.1");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new LambertI(en, Ellipsoid.CLARKE, Datum.NTF), "X=455.23 Y = 1102.1");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new LambertII(en, Ellipsoid.CLARKE, Datum.NTF), "X=455.23 Y = 2302.1");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new LambertIII(en, Ellipsoid.CLARKE, Datum.NTF), "X=936.7 Y = 3102.5");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new LambertIV(en, Ellipsoid.CLARKE, Datum.NTF), "X=455.23 Y = 2302.1");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new Lambert93(en, Ellipsoid.GRS80, Datum.WGS_1984), "X=455.23 Y = 2302.1");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new IrishGrid(en, Ellipsoid.MODIFIED_AIRY, Datum.IRELAND_1965), "M730196");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new NZMG(en, Ellipsoid.INTERNATIONAL, Datum.NZGD_1949), "2487100 mE 6751049 mN");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new NZTM2000(en, Ellipsoid.GRS80, Datum.NZGD_2000), "2487100 mE 6751049 mN");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new UTM(en, 1, Ellipsoid.GRS80, Datum.WGS_1984), "32T 406946 5383757");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new AustrianM28(en, Ellipsoid.BESSEL, Datum.MGI), "M28 486697 83757");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new AustrianM31(en, Ellipsoid.BESSEL, Datum.MGI), "M31 486697 83757");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new AustrianM34(en, Ellipsoid.BESSEL, Datum.MGI), "M34 486697 83757");
coordmap.put(p1.getName(), p1);
p1 = new MapEntry(new SloveneGrid(en, Ellipsoid.BESSEL, Datum.MGI_SLOV), "486697 83757");
coordmap.put(p1.getName(), p1);
}
/**
* Provide the default Ellipsoid for the named CoordinateSystem class
* @param classname The name of the CoordinateSystem
* @return the defaultEllipsoid() for the class
* @throws java.lang.IllegalArgumentException if the CoordinateSystem cannot be found
*/
public Ellipsoid defaultEllipsoid(String classname) throws IllegalArgumentException {
MapEntry m = coordmap.get(classname);
if (m == null) {
throw new IllegalArgumentException(String.format("No such CoordinateSystem: %s", classname));
}
CoordinateSystem c = m.getCoordinateSystem();
return c.defaultEllipsoid();
}
/**
* Provide the default Datum for the specified CoordinateSystem
* @param classname A String containing the name of a CoordinateSystem
* @return the defaultDatum()
* @throws java.lang.IllegalArgumentException if the CoordinateSystem cannot be found.
*/
public Datum defaultDatum(String classname) throws IllegalArgumentException {
MapEntry m = coordmap.get(classname);
if (m == null) {
throw new IllegalArgumentException(String.format("No such CoordinateSystem: %s", classname));
}
CoordinateSystem c = m.getCoordinateSystem();
return c.defaultDatum();
}
/**
* Make a CoordinateSystem instance from a grid reference
* @param name - the name of the CoordinateSystem to make
* @param args - the argument list for the class's makePoint() method
* @return A new CoordinateSystem instanceof the specified type
* @throws java.lang.NoSuchMethodException
* @throws uk.co.mccombe.mapping.GridFormatException
* @throws java.lang.IllegalAccessException
* @throws java.lang.IllegalArgumentException
* @throws java.lang.reflect.InvocationTargetException
* @throws java.lang.InstantiationException
*/
public CoordinateSystem makeCoordinateSystem(String name, Object... args) throws NoSuchMethodException, GridFormatException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
CoordinateSystem p = coordmap.get(name).getCoordinateSystem();
// Class c = p.getClass();
Class extends CoordinateSystem> c = p.getClass();
Class>[] classes = new Class>[args.length];
for (int i = 0; i < args.length; i++) {
classes[i] = unwrap(args[i].getClass());
}
if (args.length == 0) {
throw new NoSuchMethodException("Default constructor");
}
if (args[0] instanceof String) {
Method make = c.getMethod("makePoint", classes);
CoordinateSystem point = (CoordinateSystem) make.invoke(null, args);
return point;
} else {
Constructor> con = c.getConstructor(classes);
CoordinateSystem point = (Projection) con.newInstance(args);
return point;
}
}
/**
* Create an alphabetically ordered list of CoordinateSystem names
* @return The list of names
*/
public java.util.Vector* Class OSGB provides handling for the Ordnance Survey of Great Britain * coordinate system. *
** OSGB is a conventional Transverse Mercator coordinate system in which a standard * sphere (the "Airy 1830 sphere") is projected onto a plane. Several other well-known * coordinate systems operate in the same way (e.g. the Irish Grid and UTM) but with * origins and spheroids chosen to be most suitable to the area of use. The OSGB grid is * applicable only to Great Britain (i.e. England, Scotland and Wales but NOT Northern Ireland * or the Republic of Ireland, or the Channel Islands). *
** For more information about OSGB and the manipulation of Transverse Mercator coordinate systems * you could try:- *
* "A guide to coordinate systems in Great Britain" - Ordnance Survey of Great Britain * "GDA Technical Manual" at www.anzlic.org.au ** * @author Mike McCombe * * Simplified and tidied 21-Oct-2007 */ public class OSGB extends uk.co.mccombe.mapping.TransverseMercator { /** * Create a new OSGB point based on a grid reference. This is the preferred method of obtaining a * new OSGB object from a grid reference and for translating a grid reference into a Position. For example *
* * try { * OSGB point = OSGB.makePoint("ST755619", Ellipsoid.AIRY, Datum.OSGB_1936); * Position here = point.getPosition(); * ... * } * catch(GridFormatException e){ * //Handle exception * ... * } * ** @param osReference A String containg a valid grid reference. This consists of a two-letter * grid square (e.g. "ST") followed by 1-5 digits of easting and the same number of digits * of northing. Whitespace may appear between the grid-letters and easting and between * easting and northing values. * @param e The Ellipsoid used in conjunction with this point. This is almost always the * Airy (1830) sphere. * @param d The Datum to use in conjunction with this point. This is almost always the * OSGB (1936) Datum. * @return A new OSGB object * @throws uk.co.mccombe.mapping.GridFormatException A GridFormatException is thrown whenever the grid reference provided has invalid * syntax. */ public static OSGB makePoint(String osReference, Ellipsoid e, Datum d) throws GridFormatException { ENPair point = getEN(osReference) ; return new OSGB(point, e, d); } /** * Create a new OSGB object from easting and northing distances * @param p Easting and Northing distances (m) * @param e Ellipsoid used by this point * @param d Datum used for this point. */ public OSGB(ENPair p, Ellipsoid e, Datum d){ super(p, e, d); } /** * Create a new OSGB object using Easting and Northing distances. The Ellispoid and Datum * are the Airy Sphere and OSGB (1936) Datum. * @param p The easting and northing distances (m) */ public OSGB(ENPair p){ this(p, Ellipsoid.AIRY, Datum.OSGB_1936); } /** * Create a new OSGB object for a specific Position, Ellipsoid and Datum. * @param p the Position of this point. * @param e The Ellipsoid to use (normally Ellipsoid.AIRY) * @param d The Datum to use (normally Datum.OSGB_1936) */ public OSGB(Position p, Ellipsoid e, Datum d) { super(p, e, d); } /** * Define the defaultDatum for this CoordinateSystem * @return Datum.OSGB_1936 */ public uk.co.mccombe.mapping.Datum defaultDatum() { return Datum.OSGB_1936; } /** * Define the default Ellipsoid for this CoordinateSystem * @return Ellipsoid.AIRY */ public uk.co.mccombe.mapping.Ellipsoid defaultEllipsoid() { return Ellipsoid.AIRY; } /** * Provide a String representation for this point. * @return 10-figure (1m) grid reference, with grid square */ public String toString() { ENPair p = toEN() ; return osRef(p); } /** Convert Easting and Northing distances in metres into OS grid ref * * @return OS Grid Reference (String) * @param easting (m) * @param northing (m) */ private static String osRef(ENPair point) { double easting = point.east(); double northing = point.north(); if(!validateEN(point)) { return "" ; } // returns 10 digit reference for given easting and northing in km. // eg SO 12345 67890 long e = 1000000 + Math.round(easting) ; long n = Math.round(northing) + 500000 ; long i = e / 500000 ; long j = n / 500000 ; String l = "" ; l += t1.charAt((int)(i + 1 + j * 5)-1) ; e = e % 500000 ; n = n % 500000 ; i = e / 100000 ; j = n / 100000 ; l += t1.charAt( (int)(j * 5 + i + 1)-1) ; e = e % 100000 ; n = n % 100000 ; String ec = "" ; ec += (100000 + e); String nc = "" ; nc += (100000 + n); l += " " + ec.substring(1) + " " + nc.substring(1) ; return l ; } /** Convert OS grid reference to easting and northing values * * @param os Grid Reference (String) * @exception GridFormatException on bad OS Grid Reference * @return Pair containing the easting (x) and northing(y) distances in metres */ private static ENPair getEN(String os) throws GridFormatException { double units = 1.0 ; String northPart, eastPart, gridSquare ; String arg = os.toUpperCase().trim(); java.util.regex.Matcher matcher = pattern.matcher(arg); java.util.regex.Matcher matcher2 = altPattern.matcher(arg); if(matcher.find()) { gridSquare = matcher.group(1); String gridOffset = matcher.group(2); int offsetLength = gridOffset.length(); if((offsetLength % 2) != 0) throw new GridFormatException("Invalid OS Grid Reference - odd number of digits"); eastPart = gridOffset.substring(0,offsetLength/2); northPart = gridOffset.substring(offsetLength/2); units = Math.pow(10.0,5-offsetLength/2); } else if(matcher2.find()) { gridSquare = matcher2.group(1); eastPart = matcher2.group(2); northPart = matcher2.group(3); if(eastPart.length()!= northPart.length()) throw new GridFormatException("Invalid OS Grid Reference - easting & northing have different lengths"); units = Math.pow(10.0,5-eastPart.length()); } else throw new GridFormatException("Invalid OS grid reference"); String firstLetter = gridSquare.substring(0,1); String secondLetter = gridSquare.substring(1,2); int i1 = (gridLetters.indexOf(firstLetter)) % 5 ; int j1 = 4 - (gridLetters.indexOf(firstLetter)) / 5 ; int i2 = (gridLetters.indexOf(secondLetter)) % 5 ; int j2 = 4 - (gridLetters.indexOf(secondLetter)) / 5 ; double eastSquare = (i1-2) * 500000.0 + i2 * 100000.0 ; double northSquare = (j1 - 1)* 500000.0 + j2 * 100000.0 ; try { double ev = Double.parseDouble(eastPart) * units + eastSquare; double nv = Double.parseDouble(northPart) * units + northSquare; return new ENPair(ev,nv); } catch (NumberFormatException bad) { throw new GridFormatException("Invalid OS Grid Reference - bad digits"); } } private static final String t1 = "VWXYZQRSTULMNOPFGHJKABCDE" ; private static final String validationRegex1 = "([HJNOST][A-HJ-Z])\\s*((\\d\\d)+)$"; private static final String validationRegex2 = "([HJNOST][A-HJ-Z])\\s*(\\d+)\\s+(\\d+)$"; private static final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(validationRegex1); private static final java.util.regex.Pattern altPattern = java.util.regex.Pattern.compile(validationRegex2); private static final String gridLetters = "ABCDEFGHJKLMNOPQRSTUVWXYZ" ; /** * Define the scale factor on the central meridian * @return scale factor (0.9996012717) */ public double f0() { return 0.9996012717 ; } /** * Define latitude of true origin * @return Latitude (degrees) of the true origin (49.0) */ public double phi0() { return Math.toRadians(49.0); } /** * Define the false northing value * @return False Northing distance (-100km) */ public double n0() { return -100000.0 ; } /** * Define false easting value * @return false easting value (400km) */ public double e0() { return 400000.0 ; } /** * Define value of central meridian (degrees) * @return central meridian (2.0 W) */ public double lamda0() { return Math.toRadians(-2.0); } /** * Check that ENPair lies within the permitted range * @param p * @return true if OK ; */ protected static boolean validateEN(ENPair p){ double x = p.east(); double y = p.north(); return (x>=MIN_E && x