①对曲线进行采样简化,即在曲线上取有限个点,将其变为折线,并且能够在一定程度保持原有形状。比较常用的两种抽稀算法是:道格拉斯-普克(Douglas-Peuker)算法和垂距限值法
chouxi.png

<?php
/*
 * 点抽稀算法
 * @param array $line 多个点组成的线
 * @param int $tolerance 取样临界值(米为单位)
 */
function douglasPeucker($line, $tolerance)
{
    $distanceMax = 0;
    $index       = 0;
    $lineSize = count($line)-1;
    if($lineSize<3){
        return $line;
    }
    for ($i = 1; $i <=$lineSize; $i ++) {
        $distance = getPerpendicularDistance($line[$i], array($line[0],$line[$lineSize]));
        if ($distance > $distanceMax) {
            $index       = $i;
            $distanceMax = $distance;
        }
    }
    if ($distanceMax > $tolerance) {
        $lineSplitFirst  = array_slice($line, 0, $index);
        $lineSplitSecond = array_slice($line, $index-1, $lineSize);
        $recursiveResultsSplitFirst  = douglasPeucker($lineSplitFirst, $tolerance);
        $recursiveResultsSplitSecond = douglasPeucker($lineSplitSecond, $tolerance);
        return array_merge($recursiveResultsSplitFirst, $recursiveResultsSplitSecond);
    }
    return [$line[0], $line[$lineSize]];
}

/*
 * 获取点到线之间的垂直距离
 * $point array 点信息
 * $line array 由两点组成的直线
 */
function getPerpendicularDistance($point,$line)
{
    //$ellipsoidRadius = 6378137.0 * (1 - 1 / 298.257222100 / 3); //GRS-80
    $ellipsoidRadius = 6378137.0 * (1 - 1 / 298.257223563 / 3); //84坐标转
    $firstLinePointLat = deg2radLatitude($line[0]['lat']);
    $firstLinePointLng = deg2radLongitude($line[0]['lng']);
    $firstLinePointX = $ellipsoidRadius * cos($firstLinePointLng) * sin($firstLinePointLat);
    $firstLinePointY = $ellipsoidRadius * sin($firstLinePointLng) * sin($firstLinePointLat);
    $firstLinePointZ = $ellipsoidRadius * cos($firstLinePointLat);
    $secondLinePointLat =deg2radLatitude($line[1]['lat']);
    $secondLinePointLng =deg2radLongitude($line[1]['lng']);

    $secondLinePointX = $ellipsoidRadius * cos($secondLinePointLng) * sin($secondLinePointLat);
    $secondLinePointY = $ellipsoidRadius * sin($secondLinePointLng) * sin($secondLinePointLat);
    $secondLinePointZ = $ellipsoidRadius * cos($secondLinePointLat);

    $pointLat =deg2radLatitude($point['lat']);
    $pointLng =deg2radLongitude($point['lng']);

    $pointX = $ellipsoidRadius * cos($pointLng) * sin($pointLat);
    $pointY = $ellipsoidRadius * sin($pointLng) * sin($pointLat);
    $pointZ = $ellipsoidRadius * cos($pointLat);

    $normalizedX = $firstLinePointY * $secondLinePointZ - $firstLinePointZ * $secondLinePointY;
    $normalizedY = $firstLinePointZ * $secondLinePointX - $firstLinePointX * $secondLinePointZ;
    $normalizedZ = $firstLinePointX * $secondLinePointY - $firstLinePointY * $secondLinePointX;

    $length = sqrt($normalizedX * $normalizedX + $normalizedY * $normalizedY + $normalizedZ * $normalizedZ);

    if ($length == 0) {
        return 0;
    }

    $normalizedX /= $length;
    $normalizedY /= $length;
    $normalizedZ /= $length;

    $thetaPoint = $normalizedX * $pointX + $normalizedY * $pointY + $normalizedZ * $pointZ;
    $length = sqrt($pointX * $pointX + $pointY * $pointY + $pointZ * $pointZ);
    $thetaPoint /= $length;
    $distance = abs((M_PI / 2) - acos($thetaPoint));
    return $distance * $ellipsoidRadius;
}


function deg2radLatitude($latitude)
{
    return deg2rad(90 - $latitude);
}

/**
 * @param float $longitude
 *
 * @return float
 */
function deg2radLongitude($longitude)
{
    if ($longitude > 0) {
        return deg2rad($longitude);
    }

    return deg2rad($longitude + 360);
}

标签: none