Search code examples
phpcoordinatesextrapolation

Create coordinate grid given number of rows, columns and starting point


I need some help with extrapolating a lat/lon pair to a square grid. The grid is 200x200 cells. Each cell is 1NM*1NM. The starting lat/lon pair is the southwest corner of the grid.

For example, column 0 and row 0 should be the first four coordinate pairs to make the first grid cell that is 1NM*1NM. Column 0 row 1 should be the next four coordinate pairs to make the next grid cell above the first one. After 200 rows, move to the next column, etc.

I have attempted this using the following PHP code, but I can't seem to extrapolate the data correctly.

<?php
header('Content-Type:text/plain');

// southwest coordinate pair (starting point)
$lat = 38.883672;
$lon = -105.698848;

for($col = 0; $col < 200; $col++) {
  $startLat = $startLat2 = 0;
  $startLon = $startLon2 = 0;

  if($col > 0) {
    $lat = Extrapolate($lat, $lon, 1.0, 90)[0];
    $lon = Extrapolate($lat, $lon, 1.0, 90)[1];
  }

  $debug = sprintf("%s,%s\r\n", $lat, $lon);

  for($row = 0; $row < 200; $row++) {
    if($row == 0) {
      $startLat = Extrapolate($lat, $lon, 1.0, 360)[0];
      $startLon = Extrapolate($lat, $lon, 1.0, 360)[1];

      $startLat2 = Extrapolate($lat, $lon, 1.0, 90)[0];
      $startLon2 = Extrapolate($lat, $lon, 1.0, 90)[1];

      $nextLat = $startLat;
      $nextLon = $startLon;

      $nextLat2 = $startLat2;
      $nextLon2 = $startLon2;

      $debug .= sprintf("%s,%s\r\n", $startLat, $startLon);
      $debug .= sprintf("%s,%s\r\n", $startLat2, $startLon2);
    }
    else {
      $nextLat = Extrapolate($nextLat, $nextLon, 1.0, 360)[0];
      $nextLon = Extrapolate($nextLat, $nextLon, 1.0, 360)[1];

      $nextLat2 = Extrapolate($nextLat2, $nextLon2, 1.0, 90)[0];
      $nextLon2 = Extrapolate($nextLat2, $nextLon2, 1.0, 90)[1];

      $debug .= sprintf("%s,%s\r\n", $nextLat, $nextLon);
      $debug .= sprintf("%s,%s\r\n", $nextLat2, $nextLon2);
    }
  }

  echo $debug;
}

function Extrapolate($lat1,$long1,$d,$angle)
{
  # Earth Radious in KM
  $R = 6378.14;

  # Degree to Radian
  $latitude1 = $lat1 * (M_PI/180);
  $longitude1 = $long1 * (M_PI/180);
  $brng = $angle * (M_PI/180);

  # Distance to NM
  $d *= 1.85200;

  $latitude2 = asin(sin($latitude1)*cos($d/$R) + cos($latitude1)*sin($d/$R)*cos($brng));
  $longitude2 = $longitude1 + atan2(sin($brng)*sin($d/$R)*cos($latitude1),cos($d/$R)-sin($latitude1)*sin($latitude2));

  # back to degrees
  $latitude2 = $latitude2 * (180/M_PI);
  $longitude2 = $longitude2 * (180/M_PI);

  $lat2 = round ($latitude2,6);
  $long2 = round ($longitude2,6);

  // Push in array and get back
  $coords[0] = $lat2;
  $coords[1] = $long2;
  return $coords;
 }

Solution

  • There is a shortcut way to solve this by recognising that the 1NM is "equal to" 1/60 of a degree. I say "equal to" because that is an old definition that has not survived very accurate modern measurements, but nevertheless is still useful.

    Coordinates increase as you move N and E. This means to move 1NM East or 1NM North (corresponding to your 1NM grid), you only have to add 1/60 of a degree to the respective coordinate.

    For example, if you start at

    // southwest coordinate pair (starting point)

    $lat = 38.883672;
    $lon = -105.698848;
    

    Move 1NM North (1 grid square)

    $lat[1] = 38.883672 + .016667; // 38.900339
    

    Move 1NM East (1 grid square)

    $lon[1] = -105.698848 + .016667; // -105.682181
    

    So using this you can easily build a grid 200x200 by just incrementing.

    The top right hand grid corner would have coordinates:

    Move 200NM North (200 grid squares)

    $lat[1] = 38.883672 + .016667*200; // 42.217072
    

    Move 200NM East (200 grid square)

    $lon[1] = -105.698848 + .016667*200; // -102.365448
    

    Also if you want to build a grid, this is best stored in a 2 dimensional array like as below:

    <?php
    //header('Content-Type:text/plain');
    
    // southwest coordinate pair (starting point)
    $lat = 38.883672;
    $lon = -105.698848;
    
    for ($col=0; $col< 200; $col++){
        echo PHP_EOL."Grid values for col ".$col.PHP_EOL;
        for ($row=0; $row< 200; $row++){
          $newCoords = extrapolate($lat,$lon,$row,$col);
          $coords[$col][$row]["lat"] = $newCoords["lat"];
          $coords[$col][$row]["lon"] = $newCoords["lon"];
          echo "Row ".$row." = ".$coords[$col][$row]["lat"]." , ";
          echo $coords[$col][$row]["lon"].PHP_EOL;
        }
    }
    
    function extrapolate($lat,$lon,$row,$col){
      $newCoords["lat"] = round($lat + (1/60)*$row,6);
      $newCoords["lon"] = round($lon + (1/60)*$col,6);
      return ($newCoords);
    }
    

    Now if you prefer to use your own method to calculate the offsets you can just modify the extrapolate() function.

    EDIT: Add this at request.

    Once you have the array above you can pick the coordinates surrounding each cell as follows. By example will will pick the bottom SW cell. Its 4 coordinate pairs are:

    // SW corner

    $coords[0][0]["lat"];
    $coords[0][0]["lon"];
    

    // NW corner

    $coords[0][1]["lat"];
    $coords[0][1]["lon"];
    

    // SE corner

    $coords[1][0]["lat"];
    $coords[1][0]["lon"];
    

    // NE corner

    $coords[1][1]["lat"];
    $coords[1][1]["lon"];
    

    By another example will will pick the top NE cell. Its 4 coordinate pairs are:

    // SW corner

    $coords[198][198]["lat"];
    $coords[198][198]["lon"];
    

    // NW corner

    $coords[198][199]["lat"];
    $coords[198][199]["lon"];
    

    // SE corner

    $coords[199][198]["lat"];
    $coords[199][198]["lon"];
    

    // NE corner

    $coords[199][199]["lat"];
    $coords[199][199]["lon"];
    

    Does this help?