Varying a Latitude/Longitude

Discussion in 'Perl Misc' started by essary@gmail.com, Nov 2, 2005.

  1. Guest

    A while ago while I was in the Army I co-wrote an exercise SIGINT
    generator with a friend. We made a mess of a few functions called
    VaryLat and VaryLong. The functions basically took in two arguments: a
    Latitude or Longitude and an amount to vary it by(in seconds). The
    second parameter could be any number positive or negative. The real
    issues started rising when we figured out that crossing over either the
    90' mark or the 180' mark was throwing off our numbers. The functions
    turned out to be very long seeing as how neither of us was very
    experience with Perl at the time. I wish I had the code to post to show
    how messy this thing was but seeing as how it was on a Top Secret//SCI
    machine security protocols made if impossible to bring a copy of this
    source home at the time. Basically I was wondering if anyone else has
    had this particular problem and came up with a good solution. It's been
    bugging me ever since I wrote the stupid code. The function prototype
    was something like this: VaryLat($theLatitude,$varyAmount).
    , Nov 2, 2005
    #1
    1. Advertising

  2. Guest

    wrote:
    > Basically I was wondering if anyone else has
    > had this particular problem and came up with a good solution.


    There are a whole bunch of modules on CPAN that deal with latitude and
    longitude. I'll bet one of them can do these calculations, but nothing
    jumped out at me when I very quickly skimmed over the one-liner
    descriptions.
    , Nov 2, 2005
    #2
    1. Advertising

  3. Guest

    Yeah, we did it horribly I think. Here's the code we had:

    sub varyLat{

    $lat = $_[0];

    $latVariant = $locVariantSec - floor(rand($locVariantSec * 2));

    $degrees = substr($lat, 0, 2);
    $minutes = substr($lat, 2, 2);
    $seconds = substr($lat, 4, 2);
    $ns = substr($lat, 6, 1);
    $delta = 1;
    if ($latVariant < 0){
    $delta = -1;
    $latVariant = $latVariant * -1;
    }
    $degVariant = floor($latVariant / 3600) * $delta;
    if ($degVariant > 0){
    $latVariant = $latVariant - ($degVariant * 3600);
    }
    $minVariant = floor($latVariant / 60) * $delta;
    if ($minVariant > 0){
    $latVariant = $latVariant - ($minVariant * 60);
    }
    $secVariant = ($latVariant % 60) * $delta;
    fixSeconds;
    fixMinutes;
    fixLatDegrees;
    $degrees = &fixLength($degrees,2,0);
    $minutes = &fixLength($minutes,2,0);
    $seconds = &fixLength($seconds,2,0);

    return $degrees . $minutes . $seconds. $ns;
    }

    Here's the code for fixSeconds and fixMinutes and fixLatDegrees:

    sub fixSeconds{

    $seconds = $seconds + $secVariant;

    if ($seconds < 0){
    $minVariant--;
    $seconds = 60 + $seconds;
    }
    else{
    if ($seconds > 59){
    $minVariant++;
    $seconds = $seconds % 60;
    }
    }
    }

    sub fixMinutes{

    $minutes = $minutes + $minVariant;

    if ($minutes < 0){
    $degVariant--;
    $minutes = 60 + $minutes;
    }
    else{
    if ($minutes > 59){
    $degVariant++;
    $minutes = $minutes % 60;
    }
    }
    }

    sub fixLatDegrees{

    $degrees = $degrees + $degVariant;

    CASE:{

    (($degrees eq 90) and ($minutes eq 0) and ($seconds eq 0)) && do{

    last CASE;
    };

    (($degrees < 90) and ($degrees >= 0)) && do{

    last CASE;
    };

    ($degrees >= 90) && do{
    $degrees = 90 - ($degrees % 90) - 1;
    $minutes = 60 - ($minutes % 60) - 1;
    $seconds = 60 - ($seconds % 60);
    last CASE;
    };

    ($degrees < 0) && do{
    $degrees = 90 - ($degrees % 90) - 1;
    $minutes = 60 - ($minutes % 60) - 1;
    $seconds = 60 - ($seconds % 60);
    if ($ns eq 'S'){
    $ns = 'N';
    }
    else{
    $ns = 'S';
    }
    last CASE;
    };
    }
    }
    , Nov 3, 2005
    #3
  4. Guest

    wrote:
    >
    > $degrees = substr($lat, 0, 2);
    > $minutes = substr($lat, 2, 2);
    > $seconds = substr($lat, 4, 2);


    What happens if $lat is a string like "-214530"? Then $degrees will
    be "-2", $minutes will be "14", and $seconds will be "53". I don't
    think that's what you intend to happen.

    You might want to try something like this:

    return unless $lat =~ m/^(-?\d+)(\d{2})(\d{2})$/;
    my ($degrees, $minutes, $seconds) = ($1, $2, $3);

    That way, degrees will be set to "-21", $minutes will be set to "45",
    and $seconds will be set to "30", which is probably what you wanted.
    If $lat happens to be malformed, then the function returns without
    modifying anything.

    I notice that you are using a lot of global variables. Many of
    programmers (me included) frown at that habit, and recommend using only
    variables passed into functions (by way of their parameter lists) and
    only modifying variables declared inside those functions. Should any
    variables need to be changed that exist outside the function, then
    their values should be set at the function call, like this:

    $lat = varyLat($lat, $latVariant);

    That way it'll be much, much easier to keep track of what each function
    modifies and uses to compute its return values.

    And I truly recommend that you use the lines:

    use strict;
    use warnings;

    at the top of all your Perl programs. They catch SO MANY errors!
    (Even very subtle ones!) Some people are discouraged from using
    'strict' because they can't get their program to work with it, but what
    they really should be doing is asking for help from a more experienced
    programmer on how to get their program to run with 'strict' (instead of
    removing it).

    So consider using 'strict' and 'warnings', as well as not using
    global variables in your program. Then your program will likely be
    much easier to debug and maintain.

    Hope this helps,

    -- Jean-Luc
    , Nov 3, 2005
    #4
  5. Guest

    wrote:
    > wrote:
    > >
    > > $degrees = substr($lat, 0, 2);
    > > $minutes = substr($lat, 2, 2);
    > > $seconds = substr($lat, 4, 2);

    >
    > What happens if $lat is a string like "-214530"? Then $degrees will
    > be "-2", $minutes will be "14", and $seconds will be "53". I don't
    > think that's what you intend to happen.
    >
    > You might want to try something like this:
    >
    > return unless $lat =~ m/^(-?\d+)(\d{2})(\d{2})$/;
    > my ($degrees, $minutes, $seconds) = ($1, $2, $3);
    >
    > That way, degrees will be set to "-21", $minutes will be set to "45",
    > and $seconds will be set to "30", which is probably what you wanted.
    > If $lat happens to be malformed, then the function returns without
    > modifying anything.


    You'll notice that a lot of the time-related functions do things in
    terms of seconds and only convert back to more conventionally formats
    at the very end. So, I'd suggest using this for the second line:
    my $lat_sec = (60 * $1 + $2) * 60 + $3);

    If you really want to use degrees, then use this:
    my $lat_deg = $1 + ($2 + $3 / 60) / 60;
    But this can be prone to rounding errors, since 3600 isn't a power of
    two.
    , Nov 3, 2005
    #5
  6. Guest

    > wrote:
    > >
    > > You might want to try something like this:
    > >
    > > return unless $lat =~ m/^(-?\d+)(\d{2})(\d{2})$/;
    > > my ($degrees, $minutes, $seconds) = ($1, $2, $3);


    replied:
    >
    > You'll notice that a lot of the time-related functions do things in
    > terms of seconds and only convert back to more conventionally formats
    > at the very end. So, I'd suggest using this for the second line:
    > my $lat_sec = (60 * $1 + $2) * 60 + $3);


    That's a good point. But just be careful about the fact that if $1
    is a negative value, then $2 and $3 should be subtracted instead of
    added. These lines should take care of that:

    return unless $lat =~ m/^(-?)(\d+)(\d{2})(\d{2})$/;
    my $lat_sec = (60 * $2 + $3) * 60 + $4);
    $lat_sec *= -1 if defined $1 and $1 eq '-';
    , Nov 3, 2005
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. YS Sze
    Replies:
    4
    Views:
    612
    -berlin.de
    Feb 7, 2004
  2. kbperry
    Replies:
    2
    Views:
    302
    kbperry
    May 31, 2006
  3. helpneeded
    Replies:
    6
    Views:
    510
    Help needed
    Aug 1, 2006
  4. Replies:
    5
    Views:
    2,429
    Luc The Perverse
    Aug 14, 2006
  5. Penn
    Replies:
    5
    Views:
    564
Loading...

Share This Page