http://www.perlmonks.org?node_id=1069219


in reply to Data visualisation.

Alright, an update on the strategy I proposed earlier. The calculation is quite simple, no need for trigonometry, simple application of the Pythagorean theorem. Real code is less than 20 lines.

First a careful analysis of the problem:

Let the coordinates of A be (0, 0) and B (0, 633). C is 257 someunits +(let's say meters, we don't care) from A and 390 m from B. Distance A-C: sqrt (x² + y²) = 257 <=> x² + y² = 257² + (1) Distance B-C: sqrt (x² + (633 - y)²) = 390 <=> x² + (633 - y)² = 390 +² (2) Substrating 2 from 1: y² - (633 - y)² = 257² - 390² <=> (y + a - y)(y - a + y) = 257² - 390² <=> a (2 y - a) = 257² - 390² <=> y = (257² - 390²) / 2a + a/2 Similarly: x² + y² = 257² <=> x = +/- sqrt ( 257² - y²)
When calculating the coordinates of C, we just have to chose one value pair among the two possible ones. Once we have done that, we can repeat the process, calculate the two possible values with respect to A and B, and then check with C which one make sense (the one where the distance to C will be closest to the original distance to C). Now, the point is that is that check is also a way to validate in part the data.

And it turns out that the data provided is unusable, because is is not consistent.

This is the test program I originally wrote:

use strict; use warnings; my %coordinates; $coordinates{A} = [0,0]; $coordinates{B} = [0,633]; $coordinates{C} = find_coord(257, 390, undef); $coordinates{D} = find_coord(91, 661, 228); print "@{$coordinates{D}} \n"; sub find_coord { my ($a, $b, $c) = @_; my $sq_dist_dif = $a*$a - $b*$b; my $y = $sq_dist_dif/(633*2) + 633/2; my $x = sqrt ($a*$a - $y*$y); return [$x, $y] unless defined $c; my $dist_2_c_1 = distance ([$x, $y], $coordinates{C}, $c); my $dist_2_c_2 = distance ([-$x, $y], $coordinates{C}, $c); $dist_2_c_1 < $dist_2_c_2 ? [$x, $y, $dist_2_c_1] : [-$x, $y, $dis +t_2_c_2]; } sub distance { return abs (sqrt (($_[0][0] - $_[1][0])**2 + ($_[0][1] - $_[1][1]) +**2) - $_[2]); }
The distances to C did not make any sense compared to the rest. I tried to plot the distances on a piece of paper and found that I was going into a dead end as soon as I tried to plot D. The input data simply does not work.

So I tried to produce my own data and just plotted six points on a piece of paper, and measured their distance (in millimeters) to A, B and C. I updated my program to record these changes and got the following program:

use strict; use warnings; use Data::Dumper; my %coordinates; $coordinates{A} = [0,0]; $coordinates{B} = [0,90]; while (<DATA>) { my ($site, $dA, $dB, $dC) = /(\w):\s+(\d+)\s+(\d+)\s+(\d+)/; $coordinates{$site} = find_coord ($dA, $dB, $dC); } print Dumper \%coordinates; sub find_coord { my ($a, $b, $c) = @_; my $sq_dist_dif = $a*$a - $b*$b; my $y = $sq_dist_dif/(90*2) + 90/2; my $x = sqrt ($a*$a - $y*$y); return [$x, $y] unless $c; my $dist_2_c_1 = distance ([$x, $y], $coordinates{C}, $c); my $dist_2_c_2 = distance ([-$x, $y], $coordinates{C}, $c); $dist_2_c_1 < $dist_2_c_2 ? [$x, $y, $dist_2_c_1] : [-$x, $y, $dis +t_2_c_2]; } sub distance { return abs (sqrt (($_[0][0] - $_[1][0])**2 + ($_[0][1] - $_[1][1]) +**2) - $_[2]); } __DATA__ C: 64 76 0 D: 28 70 74 E: 120 62 68 F: 68 52 93 G: 53 125 64
For each point, the program displays the calculated x and y coordinates and the deviation between the input C distance and the calculated C distance. This is the output:
$ perl coordinates2.pl $VAR1 = { 'F' => [ '-39.0540935398867', '55.6666666666667', '1.33876031467558' ], 'A' => [ 0, 0 ], 'D' => [ '-17.1497975368678', '22.1333333333333', '2.41895858461325' ], 'C' => [ '53.1402755816047', '35.6666666666667' ], 'G' => [ '46.0712491690859', '-26.2', '1.73078144969754' ], 'E' => [ '60.4799895486306', '103.644444444444', '0.372872345124534' ], 'B' => [ 0, 90 ] };
As it can be seen, the deviation on C is every time small enough, compared to the other values, to show that the calculations are most probably correct.

Just in case you wished to know, these are the original coordinates I used to plot on my points:

A 0 0 B O 90 C 55 35 D -20 20 E 60 114 F 64 55 G 45 -29