You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP KML圆形生成器在国际日期变更线附近失效求助

问题描述

我开发的KML圆形生成器,99%的输入坐标都能正常工作,但当位置靠近国际日期变更线时,绘制会出现异常。

测试坐标:19.282494,166.636650,半径1047海里,生成的圆形会跨越国际日期变更线,输出的坐标在经过0度和180度时出现跳变,导致绘制异常。

异常输出

<coordinates>166.63665,36.70122262,30 170.33929602,36.39506383,30 173.86075879,35.49288317,30 177.04308391,34.04103068,30 179.76710126,32.10928643,30 -178.04299159,29.78247231,30 -176.42417943,27.15263215,30 -175.38386586,24.31316399,30 -174.90965799,21.35519771,30 -174.97725208,18.36580524,30 -175.55559428,15.42737555,30 -176.60947581,12.617518,30 -178.10014056,10.00900144,30 -179.98458741,7.66939861,30 177.7857603,5.66025581,30 175.26638245,4.0357509,30 172.52041272,2.84094525,30 169.61836825,2.10986796,30 166.63665,1.86376538,30 163.65493175,2.10986796,30 160.75288728,2.84094525,30 158.00691755,4.0357509,30 155.4875397,5.66025581,30 153.25788741,7.66939861,30 151.37344056,10.00900144,30 149.88277581,12.617518,30 148.82889428,15.42737555,30 148.25055208,18.36580524,30 148.18295799,21.35519771,30 148.65716586,24.31316399,30 149.69747943,27.15263215,30 151.31629159,29.78247231,30 153.50619874,32.10928643,30 156.23021609,34.04103068,30 159.41254121,35.49288317,30 162.93400398,36.39506383,30 166.63665,36.70122262,30 </coordinates>

相关PHP代码

foreach($ap as $name)
{
    $name=trim(strtoupper($name));
    $circleLat = $airport[$name][0];
    $circleLon = $airport[$name][1];
    $circleRadius = $_GET['circleRadius']*1852;
    $circlePrecision = mostPrecision($circleLat, $circleLon, $circleRadius);
    $coordinatesList = "";
    // Code based on Google Earth community posting by 'ink_polaroid'
    $num_points = 36;
    $delta_pts = 360/$num_points;
    // convert coordinates to radians
    $lat = deg2rad(floatval($circleLat));
    $lon = deg2rad(floatval($circleLon));
    $d = $circleRadius;
    $d_rad = $d/6378137; // convert dist to angular distance in radians
    // loop around the compass, appending coordinates of each vertex
    for($i=0; $i<=$num_points; $i++) {  
      $radial = deg2rad($i*$delta_pts);
      $lat_rad = asin(sin($lat)*cos($d_rad) + cos($lat)*sin($d_rad)*cos($radial));
      $dlon_rad = atan2(sin($radial)*sin($d_rad)*cos($lat), cos($d_rad)-sin($lat)*sin($lat_rad));
      $lon_rad = fmod(($lon+$dlon_rad + M_PI), 2*M_PI) - M_PI;
      $coordinatesList .= Round(rad2deg($lon_rad),$circlePrecision)."," . Round(rad2deg($lat_rad),$circlePrecision).",30 ";
    }
问题原因

当前代码将经度转换为-180°~180°范围,当圆形跨越国际日期变更线(180°/-180°)时,相邻点的经度会出现从179.x°跳变到-178.x°的情况。KML解析时会将这两个点用最短路径连接,也就是跨太平洋的直线,而非沿着圆形边缘的弧线,导致绘制异常。

解决方案

可以通过两种方式修复这个问题:

方式一:统一使用0°~360°经度格式

修改经度的计算逻辑,将所有经度转换为0°~360°范围,避免正负跳变:

foreach($ap as $name)
{
    $name=trim(strtoupper($name));
    $circleLat = $airport[$name][0];
    $circleLon = $airport[$name][1];
    $circleRadius = $_GET['circleRadius']*1852;
    $circlePrecision = mostPrecision($circleLat, $circleLon, $circleRadius);
    $coordinatesList = "";
    $num_points = 36;
    $delta_pts = 360/$num_points;
    // convert coordinates to radians
    $lat = deg2rad(floatval($circleLat));
    $lon = deg2rad(floatval($circleLon));
    $d = $circleRadius;
    $d_rad = $d/6378137; // convert dist to angular distance in radians
    // loop around the compass, appending coordinates of each vertex
    for($i=0; $i<=$num_points; $i++) {  
      $radial = deg2rad($i*$delta_pts);
      $lat_rad = asin(sin($lat)*cos($d_rad) + cos($lat)*sin($d_rad)*cos($radial));
      $dlon_rad = atan2(sin($radial)*sin($d_rad)*cos($lat), cos($d_rad)-sin($lat)*sin($lat_rad));
      // 修改为0~2π范围的弧度,转度数后为0°~360°
      $lon_rad = fmod(($lon+$dlon_rad), 2*M_PI);
      // 处理fmod可能返回负数的情况(当lon+dlon_rad为负时)
      if ($lon_rad < 0) {
          $lon_rad += 2*M_PI;
      }
      $coordinatesList .= Round(rad2deg($lon_rad),$circlePrecision)."," . Round(rad2deg($lat_rad),$circlePrecision).",30 ";
    }

方式二:保持-180°~180°但保证相邻点经度连续

记录前一个点的经度,当当前点与前一个点的经度差绝对值超过180°时,调整当前经度(加/减360°),确保相邻点的最短路径是圆形边缘:

foreach($ap as $name)
{
    $name=trim(strtoupper($name));
    $circleLat = $airport[$name][0];
    $circleLon = $airport[$name][1];
    $circleRadius = $_GET['circleRadius']*1852;
    $circlePrecision = mostPrecision($circleLat, $circleLon, $circleRadius);
    $coordinatesList = "";
    $num_points = 36;
    $delta_pts = 360/$num_points;
    // convert coordinates to radians
    $lat = deg2rad(floatval($circleLat));
    $lon = deg2rad(floatval($circleLon));
    $d = $circleRadius;
    $d_rad = $d/6378137; // convert dist to angular distance in radians
    $prev_lon_deg = null; // 记录前一个点的经度
    // loop around the compass, appending coordinates of each vertex
    for($i=0; $i<=$num_points; $i++) {  
      $radial = deg2rad($i*$delta_pts);
      $lat_rad = asin(sin($lat)*cos($d_rad) + cos($lat)*sin($d_rad)*cos($radial));
      $dlon_rad = atan2(sin($radial)*sin($d_rad)*cos($lat), cos($d_rad)-sin($lat)*sin($lat_rad));
      $lon_rad = fmod(($lon+$dlon_rad + M_PI), 2*M_PI) - M_PI;
      $current_lon_deg = Round(rad2deg($lon_rad),$circlePrecision);
      
      // 调整经度保证连续
      if ($prev_lon_deg !== null) {
          $diff = $current_lon_deg - $prev_lon_deg;
          if ($diff > 180) {
              $current_lon_deg -= 360;
          } elseif ($diff < -180) {
              $current_lon_deg += 360;
          }
      }
      
      $coordinatesList .= $current_lon_deg."," . Round(rad2deg($lat_rad),$circlePrecision).",30 ";
      $prev_lon_deg = $current_lon_deg;
    }
说明

两种方式都能解决跨国际日期变更线的绘制异常问题,方式一实现更简单,方式二更贴合传统的-180°~180°经度习惯,可根据需求选择。

内容的提问来源于stack exchange,提问作者Steve C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:39:58