in reply to Re: Lat/Lon to V&H conversion
in thread Lat/Lon to V&H conversion

UPDATE - I installed Geo::Coordinates::VandH::XS on my test/development box and put together a quick little test program. After I modified the code to explicitly call Geo::Coordinates::VandH::XS::toVH, the test program worked. Except it gave the wrong answer. The curious thing is, it gave the exact same wrong answer as my converted-over-from-C program.

All this leads me to think that there's a flaw in the original code somewhere since there's no way I could have made a mistake...unless, or course, I did make a mistake. So, just to make sure, here's my converted code...

#! /usr/bin/perl # Program Name: ll2vh-openmap.pl use strict; use warnings; use diagnostics; # Get Latitude and Longitude my $in1 = $ARGV[0]; my $in2 = $ARGV[1]; my $lat = $in1; my $lon = $in2; # Load appropriate packages use Math::Trig; # Trigonometric functions # Declare constants # Polynomial constants my $k1 = .99435487; my $k2 = .00336523; my $k3 = -.00065596; my $k4 = .00005606; my $k5 = -.00000188; # PI in various forms my $pi = 3.14159; my $m_pi_2 = $pi/2.0; # spherical coordinates of eastern reference point # $ex^2 + $ey^2 + EZ^2 = 1 my $ex = .40426992; my $ey = .68210848; my $ez = .60933887; # spherical coordinates of western reference point # WX^2 + WY^2 + WZ^2 = 1 my $wx = .65517646; my $wy = .37733790; my $wz = .65449210; # spherical coordinates of V-H coordinate system # PX^2 + PY^2 + PZ^2 = 1 my $px = -0.555977821730048699; my $py = -0.345728488161089920; my $pz = 0.755883902605524030; # Rotation by 76 degrees my $rot = deg2rad(76.597497064); my $rotc = cos($rot); my $rots = sin($rot); my $radians = deg2rad($pi/180); my $degrees = rad2deg(180/$pi); # Orthogonal translation values my $transv = 6363.235; my $transh = 2250.700; # Radius of Earth in sqrt(0.1)-mile units, minus 0.3 percent my $radius = 12481.103; my $k9 = $radius*$rotc; my $k10 = $radius*$rots; # Variables my ($e, $w, $x, $y, $z) = 0; my ($ht, $vt, $h, $v) = 0; my $cos_lat1 = 0; # Main program $lat = deg2rad($lat); $lon = deg2rad($lon); # Translate east by 52 degrees # my $lon1 = $lon + deg2rad(52.0); # Convert latitude to geocentric latitude using Horner's rule # my $latsq = $lat*$lat; my $lat1 = $lat*($k1 + ($k2 + ($k3 + ($k4 + $k5*$latsq)*$latsq)*$latsq +)*$latsq); # x, y, and z are the spherical coordinates corresponding to lat, lon. + # $cos_lat1 = cos($lat1); $x = $cos_lat1*sin($lon1*-1); $y = $cos_lat1*cos($lon1*-1); $z = sin($lat1); # e and w are the cosine of the angular distance (radians) between our +- # point and the east and west centers. # $e = $ex*$x + $ey*$y + $ez*$z; $w = $wx*$x + $wy*$y + $wz*$z; if ($e > 1.0) { $e = 1.0; } if ($w > 1.0) { $w = 1.0; } $e = $m_pi_2 - atan($e/sqrt(1 - $e*$e)); $w = $m_pi_2 - atan($w/sqrt(1 - $w*$w)); # e and w are now in radians. # $ht = ($e*$e - $w*$w + .16)/.8; $vt = sqrt(abs($e*$e - $ht*$ht)); if (($px*$x + $py*$y + $pz*$z) < 0) { $vt = $vt * -1; } # rotate and translate to get final v and h. # $v = $transv + $k9*$ht - $k10*$vt; $h = $transh + $k10*$ht + $k9*$vt; print "V = $v\tLatitude = $in1\nH = $h\tLongitude = $in2\n\n";
And here's my test program for your module...

#! /usr/bin/perl # Program Name: ll2vh.pl my $lat= $ARGV[0]; my $lon= $ARGV[1]; use Geo::Coordinates::VandH::XS; my( $v, $h ) = Geo::Coordinates::VandH::XS::toVH( $lat, $lon ); print "V = $v\tLatitude = $lat\nH = $h\tLongitude = $lon\n\n";
I tested both programs against the output of this test program for Geo::Coordinates::VandH.
#! /usr/bin/perl # Program Name: vh2ll.pl my $v= $ARGV[0]; my $h= $ARGV[1]; use Geo::Coordinates::VandH; $blah=new Geo::Coordinates::VandH; ($lat,$lon) = $blah->vh2ll($v,$h); print "V = $v\tLatitude = $lat\nH = $h\tLongitude = $lon\n\n";
My test run looks like this

jcoxen@jcoxen vandh>./vh2ll.pl 7350 5909
V = 7350 Latitude = 40.423792190582
H = 5909 Longitude = 104.791265047498

jcoxen@jcoxen vandh>./ll2vh.pl 40.423792190582 104.791265047498
V = -9500.26569570891 Latitude = 40.423792190582
H = 17778.1669205222 Longitude = 104.791265047498

jcoxen@jcoxen vandh>./ll2vh-openmap.pl 40.423792190582 104.791265047498
V = -9500.25261315459 Latitude = 40.423792190582
H = 17778.1566122488 Longitude = 104.791265047498

Any ideas or suggestions? I'm still going over the code to see if I messed up somewhere but so far, I haven't found it. Geo::Coordinates::VandH::XS converts from V&H to Lat/Lon just fine. I just can't get it to go the other way.

BTW, my converted code is very raw. I haven't cleaned out unnecessary lines, prettyied anything up or even put in a big, bold comment stating how I stole re-used this code from OpenMap.

Jack

Cogito cogito, ergo cogito sum
(I think I think, therefore I think I am)

Replies are listed 'Best First'.
Re^3: Lat/Lon to V&H conversion
by tachyon (Chancellor) on Oct 15, 2004 at 20:38 UTC

    There is an issue with sign I did not really bother to diagnose. I was not sure if it was an error with the toVH or the toLatLon function as the only sample data I found used negative Longitudes (so it looked like toVH was wrong) but toVH agreed with the existing module results. If you enter -104 degrees for the longitude it works exactly as expected.

    V = 7349.7333432988 Latitude = 40.423792190582 H = 5909.05477294282 Longitude = -104.791265047498

    I was to lazy to grok why it should be so. There are comments about the sign for E-W and N-S and also notes that it is US centric. I would be interested in some clarification on the sign issue. Evidently one is 'wrong'. Its easy to fix of course.

    With the XS code (which will be around 100x faster than pure perl) you need to import the functions you want to avoid a fully qualified call. It is good practice with modules not to export by default.

    # import all the available functions specifying by name use Geo::Coordinates::VandH::XS qw( toVH toLatLon distance degrees rad +ians ); # or as documented in the very sparse docs ;-) use Geo::Coordinates::VandH::XS qw( :all );

    cheers

    tachyon

      I figured the sign thing out just a few minutes ago and was turning to PerlMonks to post my stupidity when I saw that you had figured it out ahead of me. The rhythmic thumping sound you hear in the background is me pounding my head against my desk.

      V&H is VERY US centric. It's a Ma Bell invention from the late 50's when they were THE telephone monopoly. My guess is they were throwing in their own obfuscation to keep themselves a monopoly. BTW, if you go here, you'll see a map showing the V&H grid system. Note the relationship of the grid to a North-South axis and how the origin of the grid is upper-right as opposed to the normal lower-left. Add to that the fact that the paper describing the V&H system and the conversion to/from Lat/Lon is 109 freaking pages long and I don't think clarity and ease of use were primary considerations.

      Anyway, thank you VERY much for your module and your help. You've been a life saver.

      Jack

      Cogito cogito, ergo cogito sum
      (I think I think, therefore I think I am)