/** * 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 = "
Triangle | \n" + " | Side 1 | \n" + " | Side 2 | \n" + " | Side 3 | \n" + " | Area\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] + " | \n" + " | " + twoDec(areas[i][0]) + " | \n" + " | " + twoDec(areas[i][1]) + " | \n" + " | " + twoDec(areas[i][2]) + " | \n" + " | " + twoDec(areas[i][3]) + "\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;
}
}