 good chemistry is complicated,and a little bit messy -LW PerlMonks

### Lat/Lon to V&H conversion

by jcoxen (Deacon)
 on Oct 14, 2004 at 12:22 UTC Need Help??

jcoxen has asked for the wisdom of the Perl Monks concerning the following question:

I need to convert location coordinates from Latitude/Longitude to V&H (Vertical/Horizontal) and back again. For those who've never come across it, V&H is a coordinate system developed by and used heavily in the Telco industry. It's used to calculate mileage for circuits via the formula

```sqrt((V1-V2)^2+(H1-H2)^2/10)
[download]```

I can use Geo::Coordinates::VandH to convert V&H to Lat/Lon but I've struck out on a package or algorithm to convert Lat/Lon to V&H. I've found simple calculator programs to convert one coordinate pair at a time but I have to convert potentially tens of thousands of coordinate pairs as a cross check on existing records. Doing this one pair at a time isn't an option. Is anyone aware of a solution for this?

Thanks,

Jack

Replies are listed 'Best First'.
Re: Lat/Lon to V&H conversion
by Random_Walk (Prior) on Oct 14, 2004 at 12:47 UTC

Do you really need to convert back again ? If you are converting them from Lat/Long in the first place why not maintain a hash (or tied db if too many for hash) keyed on V&H of each Lat/Long you convert ? This assumes you are not performing any transformations of the resultant V&H only calculating various mileage distances as given above.

The other possibility is to calculate mileage directly from the Lat/Long pairs, this is not too hard (I can't remember the formula now but look up spherical geometry or celestial navigation (as in with a sextant, not for spacecraft :-) You can solve a spherical triangle based on the angle your two points make with one of the poles and the distance between each point and the pole (90-Lat)*CircEarth/360(in your desired units).

```# why is there not a <pseudocode> tag :) ?
# here is the triangle we solve...
#
#     A (North Pole)
#    / \
#   c   b
#  /     \
# B---a---C
#
# Point A is the north pole, B an C are all yours
# \$pointB \$latB, \$longB
# \$pointC \$latC, \$longC
# here is the formula
# cos a = cos b * cos c + sin b * sin c + cos A

\$miles_per_degree=\$Earths_Circumference/360;
\$Angle_A=abs(\$longB - \$longC); # needs fix for wrapping round the prim
+e meridian
\$Len_b = (90-LongC)*\$miles_per_degree; # fix for south of equator
\$Len_c = (90-LongB)*\$miles_per_degree; # make degrees S negative ?

# plug those three into the spherical circle equasion
[download]```

Cheers,
R.

Sorry if I gave the wrong idea. I don't need to calculate wire miles, I need to do data verification on several databases - some containing lat/long, some containing V&H, some containing both.

I need to cross verify that none of the coordinates were fat-fingered when they were entered (lat/long listed matches v&h listed) and play fill in the blanks where one or the other coordinate pair is missing.

Jack

Re: Lat/Lon to V&H conversion
by Yendor (Pilgrim) on Oct 14, 2004 at 12:56 UTC

A quick Google search on "Convert V&H to lat long" (sans quotes) turned up this message from the isp-clec mailing list. It contains C code that was converted from FORTRAN. Perhaps you (or someone) could convert it to Perl and either update the Geo::Coordinates::VandH modules, or at least email the module author.

Yeah, I found that same link when I started researching this. The only problem is that I don't know either Fortran or C or know anyone who does - at least no-one that I can ask for help.

Guess I'm going to have to decipher the algorithms from the code given and roll my own. This is a great disapointment to someone as lazy as me. :)

Jack

Well, fine. If you're that lazy...I had a few spare cycles.

NOTE: The following code is completely UNTESTED. I will not guarantee anything about it. I will not even guarantee that it will compile, much less produce the correct output. For all I know, there's some secret obfu in there that converts everything to rm -r /. It is a straight-up conversion of the code found in the link I referenced earlier. Use at your own risk.

```my \$y # V, the vertical component of VH
my \$x # H, the horizontal component of VH

# FUNCTION NAME: convert_geo_vh()
# INPUTS: double b (latitude)
#         double l (longitude)
# OUTPUT: double y (V, the vertical component of VH)
#         double x (H, the horizontal component of VH)
# PURPOSE:
# This function converts latitude and longitude (in radians) to
# V-H coordinates (unit of measure square root of 0.1 mile).
# This function returns V-H coordinates with two decimal places:
# VVVV.VV as the Y-coordinate and HHHH.HH as the X-coordinate.
# This is precise to only a "16.7 x 16.7"-foot square. The
# distortion inherent in a continent-wide projection makes any
# more than two decimal places meaningless. Thus, any conversion
# to or from V-H coordinates is only an approximate location.

sub convert_geo_vh() {
my \$b = shift;
my \$l = shift;

my (\$i, \$v, \$h);
my (\$h1, \$v1, \$e, \$w, \$e1, \$w1);
my (\$xx, \$yy, \$zz, \$p, \$q);
my (\$kk, \$ll, \$k1, \$k3, \$k5, \$k7, \$k9);

\$k1 = 0.99435487 * \$b;
\$k3 = 0.00336523 * \$b * \$b * \$b;
\$k5 = 0.00065596 * \$b * \$b * \$b * \$b * \$b;
\$k7 = 0.00005606 * \$b * \$b * \$b * \$b * \$b * \$b * \$b;
\$k9 = 0.00000188 * \$b * \$b * \$b * \$b * \$b * \$b * \$b * \$b * \$b;
\$kk = \$k1 + \$k3 - \$k5 + \$k7 - \$k9;
\$xx = sin(\$kk);
\$ll = \$l - 0.907571211;
\$yy = cos(\$kk) * sin(\$ll);
\$zz = cos(\$kk) * cos(\$ll);
\$e1 = (0.60933887 * \$xx) + (0.40426992 * \$yy) + (0.68210848 * \$zz);
if (\$e1 > 1.0)
\$e1 = 1.0;
\$q = sqrt(fabs(1.0 - (\$e1 * \$e1)));
\$e = asin(\$q);
\$w1 = (0.6544921 * \$xx) + (0.65517646 * \$yy) + (0.3773379 * \$zz);
if (\$w1 > 1.0)
\$w1 = 1.0;
\$q = sqrt(fabs(1.0 - (\$w1 * \$w1)));
\$w = asin(\$q);
\$h1 = ((\$e * \$e) - (\$w * \$w) + 0.16) / 0.8;
\$v1 = sqrt(fabs((\$e * \$e) - (\$h1 * \$h1)));
\$i = (10.0*(\$xx - (0.73553336 * \$yy) - (0.45738305 * \$zz)) + 0.5);
if (\$i < 0)
\$i--;
\$p = \$i;
\$p = \$p / 100000000.0;
if (\$p < 0)
\$v1 *= -1.0;
if (\$p == 0)
\$v1 = 0.0;
\$v = ((6363.235 + (2893.0 * \$h1) - (12141.19003 * \$v1)) * 100.0 + 0.
+5);
\$h = ((2250.7 + (12141.19003 * \$h1) + (2893.0 * \$v1)) * 100.0 + 0.5)
+;
\$y = \$v / 100.0;
\$x = \$h / 100.0;
\$c = 0.0;
\$k = 1.0;
return;
}
[download]```
Re: Lat/Lon to V&H conversion
by tachyon (Chancellor) on Oct 15, 2004 at 05:10 UTC

Here is an Inline C version that swings both way. It is a port of the Java code used in openmap VHTransform class, and unlike the other code you linked to actually works properly. http://openmap.bbn.com/doc/api/com/bbn/openmap/util/VHTransform.html

I followed the link and d/l'd OpenMap. I'm in the process of translating the 'toVH' section of the code into Perl. At this point, it runs, it just doesn't give the correct answers. (details, details)

Once I've figured out which bit I've dropped, I'll be a happy camper.

Thanks,

Jack

Cogito cogito, ergo cogito sum
(I think I think, therefore I think I am)
Re: Lat/Lon to V&H conversion
by tachyon (Chancellor) on Oct 15, 2004 at 06:58 UTC
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...

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
[download]```

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 );
[download]```

cheers

tachyon

Could you define "shortly"?

Never mind. Shortly means now. Just found it.

Cogito cogito, ergo cogito sum
(I think I think, therefore I think I am)
Re: Lat/Lon to V&H conversion
by perlcapt (Pilgrim) on Oct 15, 2004 at 21:26 UTC
I might suggest you make your coordinate transform to UTM then make your distance calculations or next transform. The Geo::Coordinates::UTM module is bidirectional and supports many different Ellipsoids for the Lat/Long. I suggest using the WGS84 ellipsoid since that is the standard for GPS. The precision of these calculations is to the centimeter if not better, assuming that the earth is not a pulsating ellipsoid, which it really is. The one drawback is that the UTM system divides the planet into zones. Calculations across zone bounderys may not be as precise.

We (Center for Coastal and Ocean Mapping) do a lot of this, but in the metric system. We need that flat model to do measurement calculations.
Thanks for the suggestion but I'm not going to be doing any distance calculations. All I need to do is verify existing data and fill where data is missing. Telco's normally use V&H coordinates to locate offices, customer premises, etc. so I need to double check that the V&H information matches up with the Lat/Lon for that location or, if one or the other coordinate pair is missing, calculate it from the other.

Jack

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

Log In?
 Username: Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://399174]
Approved by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2021-06-24 15:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
What does the "s" stand for in "perls"? (Whence perls)

Results (128 votes). Check out past polls.

Notices?