Winch
Winch

Reputation: 147

Calculating Longitude Center Over 180th Meridian

I am computing a simple average of latitude/longitude pairs to get the centerpoint (as projected on a flat plane) and I am struggling to develop an algorithm to correctly account for the 180th Meridian. I am developing this in PHP.

I'm computing a simple average, adding up all of the longitudes and dividing by the count. However, in a situation where there is, for example, a -175 and 175 point, it returns an average of 0, whereas I need a value of 180.

Once approach I tried was to add 360 to all negative values, take the average, and then subtract 360. This fixes the problem over the 180th Meridian, but it creates the same issue over the Prime Meridian (0 Meridian).

$neg_lng_flag = false;
//calculate centerpoint
$i = 0;
while($i < $vertice_count) {
    $lat_sum += $vertice_obj[$i]->lat;
    //if lng is negative, add 360
    if($vertice_obj[$i]->lng < 0) {
        $lng_sum += $vertice_obj[$i]->lng + 360;
        $neg_lng_flag = true;
    } else {
        $lng_sum += $vertice_obj[$i]->lng;
    }
    $i++;
}
$avg_lat = round($lat_sum / $vertice_count,2);
$avg_lng = round($lng_sum / $vertice_count,2);

if($neg_lng_flag) {
    $avg_lng = $avg_lng - 360;
    if($avg_lng < -180) {
        $avg_lng = $avg_lng + 180;
    }
}

I am not sure what I can do to come up with a consistent algorithm to return a true center longitudal point for all scenarios. I have not been able to find a robust solution either here or through Google more generally. I would appreciate any outside consideration/ideas. Thank you.

Upvotes: 0

Views: 485

Answers (1)

Winch
Winch

Reputation: 147

I was able to come up with a robust solution for my purposes. In my case, I just needed to calculate the minimum and maximum Longitude coordinates, and if the difference exceeded 180, I knew to shift the negative values by +360, then calculate the average. If the average was greater than 180, I needed to subtract 360, and if it was less than -180 I needed to add 360.

//COMPUTE LONGITUDAL MIDPOINT
function getLngMidpoint($vertice_obj) {
    //get min and max vals
    $i = 0;
    while($i < count($vertice_obj)) {
        $min = $vertice_obj[$i]->lng;
        $max = $vertice_obj[$i]->lng;

        if($vertice_obj[i]->lng > $max) {
            $max = $vertice_obj[$i]->lng;
        }
        if($vertice_obj[$i]->lng < $min) {
            $min = $vertice_obj[$i]->lng;
        }

        $i += 1;
    }

    $shift = 0;
    //check if distance between min and max > 180. If so, need to shift
    if(($max - $min) > 180) {
        //shift all lng by 180
        $shift = 360;
    }

    $i = 0;
    $sum_lng = 0;
    while($i < count($vertice_obj)) {
        if($vertice_obj[$i] < 0) {
            $sum_lng += $vertice_obj[$i]->lng + $shift;
        } else {
            $sum_lng += $vertice_obj[$i]->lng;
        }
        $i += 1;
    }

    $avg_lng = $sum_lng / count($vertice_obj);
    if($avg_lng > 180) {
        $avg_lng = $avg_lng - 360;
    }
    if($avg_lng < -180) {
        $avg_lng = $avg_lng + 360;
    }

    return $avg_lng;
}

Upvotes: 1

Related Questions