/** * Land Survey Triangulator * @author Robert John Morton * @version 18 March 2010 */ /* Type the latitudes and longutudes of the plot's boundary points in the array latlng[][] below in the same format as you see the old ones there already. Divide the plot into convenient triangles. Put the index numbers of the 3 points of each triangle in each row of the array triangles[][] below. Save this file. Open a file browser window containing this file (if it is not already open from when you accessed this file to edit it). Toggle the appro- priate button to make the browser display the full directory path. Mark and copy the path from the address field of the file browser. Open a terminal window. Enter the command: cd [then paste the path into the terminal command line] Press (Enter). Enter the command: javac triangulator.java When the program has finished compiling, enter the command: java triangulator The output will be found in the file triangulator.htm You can cut & past the contents of this file into the any html document. */ import java.io.*; import java.text.DecimalFormat; class triangulator{ private static Writer tf; //for output file private static final int triangles[][] = { // RELEVANT TRIANGLES {0, 1, 7}, // ABH {1, 4, 7}, // BEH {1, 2, 4}, // BCE {2, 3, 4}, // CDE {4, 6, 7}, // EGH {4, 5, 6} // EFG }; private static final double π = 3.14159265358979323846264338327950288, latlng[][] = { // REFERENCE POINTS {19, 53, 47.19, 43, 32, 28.18}, // A 0 {19, 53, 47.81, 43, 32, 29.24}, // B 1 {19, 53, 48.27, 43, 32, 29.65}, // C 2 {19, 53, 48.95, 43, 32, 29.78}, // D 3 {19, 53, 48.29, 43, 32, 31.61}, // E 4 {19, 53, 44.84, 43, 32, 30.39}, // F 5 {19, 53, 46.22, 43, 32, 29.93}, // G 6 {19, 53, 46.84, 43, 32, 29.41}, // H 7 }, GH[] = {1114, 1118, 1120, 1121, 1120, 1114, 1117, 1117}; //Ground height at each point private static double R, //Earth radius at the mean latitude of the site H, //mean height of plot above sea level metres φm, //mean latitude of site in degrees φ, //latitude λ, //longitude Δφ, //latitude precision in metres equiv to .01" of arc Δλ, //longitude precision in metres equiv to .01" of arc areas[][] = new double[triangles.length][4]; //side-lengths and areas of the triangles private static final String L[] = {"ABH","BEH","BCE","CDE","EGH","EFG"}, //names of the triangles TH = "\n\n" //table heading + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "
TriangleSide 1Side 2Side 3Area\n\n"; public static void main(String args[]) throws IOException { String bd = "/home/rob/projects/projects_int/landshare/purchase/Itamar/survey/triangulator.htm"; earthRadius(); //compute the Earth's radius + mean height at the site sidesAndAreas(); //compute lengths of sides of all triangles tf = new FileWriter(bd); //open output file double A = 0; tf.write(TH); //print side lengths and area of each triangle for(int i = 0; i < triangles.length; i++) { A += areas[i][3]; tf.write("
" + L[i] + "" + twoDec(areas[i][0]) + "" + twoDec(areas[i][1]) + "" + twoDec(areas[i][2]) + "" + twoDec(areas[i][3]) + "\n\n"); } tf.write("
\n\n"); tf.write("

Total Area = " + twoDec(A) + " square metres.\n"); double b = A - 5000.30; // error in square metres String s = "+"; if(b < 0) {s = "-"; b = -b;} tf.write("
Error: " + s + twoDec(b) + " square metres.\n"); tf.write("
Equivalent to a square of side " + twoDec(Math.sqrt(b)) + " metres.\n"); tf.write("
Earth radius at mean site latitude = " + twoDec(R) + " metres.\n"); tf.write("
This radius includes the mean elevation\n"); tf.write("
of the site above sea level: " + twoDec(H) + " metres.\n\n"); tf.write("

Within this site and its viscinity:"); tf.write("
0.01 second of latitude = " + twoDec(Δφ * 100) + " cm.\n"); tf.write("
0.01 second of longitude = " + twoDec(Δλ * 100) + " cm.\n\n"); tf.close(); } /* computes the side-lengths and area of each triangle of the triangulated plot */ private static void sidesAndAreas(){ //side-lengths & areas of triangles for(int i = 0; i < 6; i++) { //for each of the triangles of plot toRads(triangles[i][0]); double φ1 = φ; //latitude of first point in radians double λ1 = λ; //longitude of first point in radians toRads(triangles[i][1]); double φ2 = φ; //latitude of second point in radians double λ2 = λ; //longitude of second point in radians toRads(triangles[i][2]); double φ3 = φ; //latitude of third point in radians double λ3 = λ; //longitude of third point in radians double a = side(φ1, λ1, φ2, λ2); //length of first side double b = side(φ2, λ2, φ3, λ3); //length of second side double c = side(φ3, λ3, φ1, λ1); //length of third side double A = heron(a, b, c); //area of the triangle //store side lengths and area of this triangle in array areas[i][0] = a; areas[i][1] = b; areas[i][2] = c; areas[i][3] = A; } } /* accesses the lattitude and longitude of a point n in the latlng[][] array (in degrees:minutes:seconds), converts them to radians, stores them respectively in the doubles φ (latitude) and λ (longitude) */ private static void toRads(int n) { //n = index number of point φ = Math.toRadians(latlng[n][0] + latlng[n][1] / 60 //latitude of point n in radians + latlng[n][2] / 3600); λ = Math.toRadians(latlng[n][3] + latlng[n][4] / 60 //longitude of point n in radians + latlng[n][5] / 3600); } /* This formula is only an approximation when applied to the Earth, because the Earth is not a perfect sphere. There are small errors, typically of the order of 0.1% (assuming the geometric mean radius is used, because of this slight ellipticity of the planet. A more accurate method, which takes into account the Earth's ellipticity, is given by Vincenty's formulae. */ private static double side(double φ1, double λ1, double φ2, double λ2){ return R * invhav(havsin(φ1 - φ2) + Math.cos(φ1) * Math.cos(φ2) * havsin(λ1 - λ2)); } private static double havsin(double θ){ //computes the haversine of θ double x = Math.sin(θ/2); return x * x; } private static double invhav(double θ){ // compute inverse haversine of θ return 2 * Math.asin(Math.sqrt(θ)); } /* The method invented by Heron (or Hero) of Alexandria to compute the area of a general plane triangle from the lengths of its sides */ private static double heron(double a, double b, double c){ double s = (a + b + c) / 2; //semi-circumference of the triangle return Math.sqrt(s * (s - a) * (s - b) * (s - c)); } /* called only once at the beginning to establish the radius of the Earth at the mid-latitude of the plot */ private static void earthRadius(){ double //equitorial radius [using ellipsoid GRS80/WGS84(NAD83)] re = 6378137.000, //polar radius 6356752.31414034724399572718485825958879 rp = 6356752.314; φm = 0; //sum the latitudes of all the points that mark the site for(int i = 0; i < latlng.length; i++) { toRads(i); φm += φ; } φm /= latlng.length; //mean latitude of the site double sd = Math.sin(φm), //sine of the mean latitude of the site re2 = re * re, rp2 = rp * rp, //squared values sd2 = sd * sd; //sum the heights of all the points that mark the site for(int i = 0; i < GH.length; i++) H += GH[i]; H /= GH.length; //mean height of the site R = H + re * Math.sqrt(1 + sd2 * (rp2 - re2) / re2); /* Measurement precision at this site: 360 * 60 * 60 * 100 | */ Δφ = 2*π*R / (129600000); //0.01 second of latitude in metres Δλ = Δφ * Math.cos(φm); //0.01 second of longitude in metres } /* accepts a double and returns it as a string truncated or padded to two decimal places */ private static String twoDec(double d){ d += .005; //round to 2 decimal places String s = "" + d; int x = s.indexOf('.'); int y = s.length(); if(x == -1) s += ".00"; else if(x == (y - 1)) s += "00"; else if(x == (y - 2)) s += "0"; else s = s.substring(0, x + 3); return s; } }