将坐标标准化为度数对

问题描述 投票:0回答:1

用户可以输入不同形式的坐标:有或没有度数符号(分、秒)、点后有不同数量的数字和不同数量的空格。 UTM 格式中的坐标也可能会被错误地指定。 目标是将字符串转换为 WGS84 格式的两度值。 为简单起见,我们假设纬度和经度字母不会变化,因为坐标位于同一国家/地区。

php regex
1个回答
0
投票

这里的示例展示了一种从字符串获取坐标的可能方法:

<?php

// https://ru.wikipedia.org/wiki/. Преобразование_геодезических_систем_координат
// Online converter https://coordinates-converter.com/


function convert_DMS_2_deg($coord)
{
  $coord = str_replace(',', '.', $coord);
  preg_match_all('/\d+\.?\d{0,6}/', $coord, $mtch);

  if (count($mtch[0]) === 1)     return $mtch[0][0];
  elseif (count($mtch[0]) === 2) return round($mtch[0][0]+((($mtch[0][1]*60))/3600), 6);
  elseif (count($mtch[0]) >= 3)  return round($mtch[0][0]+((($mtch[0][1]*60)+($mtch[0][2]))/3600), 6);

  return false;
}

$patterns = array();
$patterns['lat'] = array();
$patterns['lng'] = array();

$wgs = <<<'WGS84'
  World Geodetic System 1984 (WGS84)
  Latitude: 48.8584° N, Longitude: 2.2945° E
  Latitude: 66.84° S, Longitude: 36.5° W
  72.123456, 66.123456

  Decimal Degrees (DD)
  40.446° N         79.982° W
  Precede South latitudes and West longitudes with a minus sign.
  Latitude  (vertical axis)   between -90° and +90°,
  Longitude (horizontal axis) between -180° and +180°.
  Up to 6 decimal places
  The geographic coodinate system = horizontal datum + prime meridian + angular unit.
WGS84;

$patterns['lat']['wgs'] = '/^[^\d\+-]*[\+-]?(([1-8]?[0-9])([\.,]\d{1,6})?|90)\D*[NS]?\s*$/i';
$patterns['lng']['wgs'] = '/^[^\d\+-]*[\+-]?((1[0-7][0-9]|[1-9]?[0-9])([\.,]\d{1,6})?|180)\D*[EW]?\s*$/i';

// =====================================

$dms = <<<'DMS'
  Degrees Minutes Seconds (DMS)

  40° 26′ 46″ N 79° 58′ 56″ W
  40° 26′ 46″ S 79° 58′ 56″ E
  90° 0′ 0″ S 180° 0′ 0″ E
  40° 26′ 45.9996″ N   79° 58′ 55.2″ E

  Latitudes range from 0 to 90.
  Longitudes range from 0 to 180.
  Minutes & Seconds range from 0-60
  Use N, S, E or W as either the last character,
which represents a compass direction North, South, East or West.
  D & M must be intergers, S may be an interger or float.
DMS;

$patterns['lat']['dms'] = '/^[^\d]*(([1-8]?[0-9])\D+([1-5]?[0-9]|60)\D+([1-5]?[0-9]|60)([\.,][0-9]+)?|90\D+0\D+0)\D*[NS]*\s*$/i';
$patterns['lng']['dms'] = '/^[^\d]*((1[0-7][0-9]|[1-9]?[0-9])\D+([1-5]?[0-9]|60)\D+([1-5]?[0-9]|60)([\.,][0-9]+)?|180\D+0\D+0)\D*[EW]*\s*$/i';

// =====================================
$ddm = <<<'DDM'
  Degrees Decimal Minutes (DDM)
  40° 26.767′ N    79° 58.933′ W
  90°  0′     N   180°  0′     W
  90°         N   180°         W
  Latitudes range from 0 to 90.
  Longitudes range from 0 to 180.
  Use N, S, E or W as either the last character,
which represents a compass direction North, South, East or West.
  The last degree, minute, or second of a latitude or longitude
may contain a decimal portion.
  DDM;

$ddm_pattern = '/^(\d{1,2})°\s+(\d{1,2})′\s+(\d{1,2})″\s+([NS])*';
$patterns['lat']['ddm'] = '/^[^\d]*(([1-8]?[0-9])\D+[1-6]?[0-9]([\.,]\d{1,3})?|90(\D+0)?)\D+([NSns])$/';
$patterns['lng']['ddm'] = '/^[^\d]*((1[0-7][0-9]|[1-9]?[0-9])\D+[1-6]?[0-9]([\.,]\d{1,3})?|180(\D+0)?)\D+([EWew])$/';

$mockings = [
  ['Latitude: 48.8584° N', 'Longitude: 2.2945° E'],
  [          '66.84° S',              '36.5° W'],
  [          '72.123456',             '66.123456'],
  [          '71,456°',               '62,6'],

  ['40° 26′ 46″ N',       '79° 58′ 56″ W'],
  ['40° 26′ 46″ S',       '79° 58′ 56″ E'],
  ['90° 0′ 0″   S',         '180° 0′ 0″  E'],
  ['40° 26′ 45.9996″',  '79° 58′ 55.2″ '],

  ['40° 26.767′ N',  '79° 58.933′ W'],
  ['90° 26′     S',  '180° 58′    E'],
  ['72° 12′      ',  '120° 22′     '],
  ['89 12′      N',  '179° 58′     '],
];

// var_dump($mockings);

foreach ($mockings as $mocking => $coords)
  {
    $lat = $coords[0];
    $lng = $coords[1];

    echo "_________________________\n";
    // echo 'Mocking: '.($mocking+1)."\n";
    echo "Lat: $lat\n";
    echo "Lng: $lng\n";

    // if (preg_match($patterns['lat']['wgs'], $lat) && preg_match($patterns['lng']['wgs'], $lng))
    // {
    //   echo "===WGS\n";
    // }
    // if (preg_match($patterns['lat']['ddm'], $lat) && preg_match($patterns['lng']['ddm'], $lng))
    // {
    //   echo "===DDM\n";
    // }
    // if (preg_match($patterns['lat']['dms'], $lat) && preg_match($patterns['lng']['dms'], $lng))
    // {
    //   echo "===DMS\n";
    // }

    preg_match_all('/\d+[\.,]?\d{0,6}/', $lat, $matches_lat);
    preg_match_all('/\d+[\.,]?\d{0,6}/', $lng, $matches_lng);

    if (count($matches_lat[0]) === 1 && count($matches_lng[0]) === 1)
    {
      // echo "---WGS\n";
      echo '>Lat: '.$matches_lat[0][0].' ('.convert_DMS_2_deg($lat).')'."\n";
      echo '>Lng: '.$matches_lng[0][0].' ('.convert_DMS_2_deg($lng).')';
      echo "\n";
    }
    elseif (count($matches_lat[0]) === 2 && count($matches_lng[0]) === 2)
    {
      // echo "---DDM\n";
  
      // echo 'Lat: '.$matches_lat[0][0].' '.$matches_lat[0][1]."\n";
      echo '>Lat_WGS: '.$matches_lat[0][0]+((($matches_lat[0][1]*60))/3600).' ('.convert_DMS_2_deg($lat).')'."\n";
      // echo 'Lng: '.$matches_lng[0][0].' '.$matches_lng[0][1]."\n";
      echo '>Lng_WGS: '.$matches_lng[0][0]+((($matches_lng[0][1]*60))/3600).' ('.convert_DMS_2_deg($lng).')';
  
      echo "\n";
     }
    elseif (count($matches_lat[0]) === 3 && count($matches_lng[0]) === 3)
    {
      // echo "---DMS\n";
  
      // echo 'Lat: '.$matches_lat[0][0].' '.$matches_lat[0][1].' '.$matches_lat[0][2]."\n";
      echo '>Lat_WGS: '.$matches_lat[0][0]+((($matches_lat[0][1]*60)+($matches_lat[0][2]))/3600).' ('.convert_DMS_2_deg($lat).')'."\n";
      // echo 'Lng: '.$matches_lng[0][0].' '.$matches_lng[0][1].' '.$matches_lng[0][2]."\n";
      echo '>Lng_WGS: '.$matches_lng[0][0]+((($matches_lng[0][1]*60)+($matches_lng[0][2]))/3600).' ('.convert_DMS_2_deg($lng).')';

      echo "\n";
     }

    unset($matches_lat);
    unset($matches_lng);

    echo "\n";
  }
© www.soinside.com 2019 - 2024. All rights reserved.