geokit
geokit copied to clipboard
bumped into a shrink call on a BoundingBox that yielded a bbox that goes around the globe
believe the issue is with BoundingBox::shrink + BoundingBox::transformBoundingBox https://github.com/jsor/geokit/blob/793e6f8847f0dd0d52a64497f7d9120dcdcdc3ea/src/BoundingBox.php#L200 https://github.com/jsor/geokit/blob/793e6f8847f0dd0d52a64497f7d9120dcdcdc3ea/src/BoundingBox.php#L219
example input to recreate:
$oBBox = BoundingBox::fromCoordinates([-118.45982654727163,33.858738223292775,-118.27313345274219,34.19377442763222]);
$fShrinkDistance = Distance::fromString('12km');
$oShrinkBBox = $oBBox->shrink($fShrinkDistance);
$oShrinkBox coords (note NE x is < SW x)
[$oShrinkBox] => Geokit\BoundingBox Object
(
[southWest:Geokit\BoundingBox:private] => Geokit\Position Object
(
[x:Geokit\Position:private] => -118.32986907162
[y:Geokit\Position:private] => 33.96665666694
)
[northEast:Geokit\BoundingBox:private] => Geokit\Position Object
(
[x:Geokit\Position:private] => -118.40360502789
[y:Geokit\Position:private] => 34.085855983985
)
)

the original method when passed with a positive shrink distance can result in minLon > maxLon. I added the additional check on lat just to be clear. Maybe there's something more elegant :D
below is my local fix
/**
* @see http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates
*/
private static function transformBoundingBox(BoundingBox $bbox, float $distanceInMeters): BoundingBox
{
$latSW = deg2rad($bbox->southWest()->latitude());
$lngSW = deg2rad($bbox->southWest()->longitude());
$latNE = deg2rad($bbox->northEast()->latitude());
$lngNE = deg2rad($bbox->northEast()->longitude());
$angularDistance = $distanceInMeters / Earth::RADIUS;
$minLat = $latSW - $angularDistance;
$maxLat = $latNE + $angularDistance;
$fMinLat = min($minLat,$maxLat);
$fMaxLat = max($minLat,$maxLat);
$minLat = $fMinLat;
$maxLat = $fMaxLat;
$deltaLonSW = asin(sin($angularDistance) / cos($latSW));
$deltaLonNE = asin(sin($angularDistance) / cos($latNE));
$minLon = $lngSW - $deltaLonSW;
$maxLon = $lngNE + $deltaLonNE;
// asin can be neg Mark E.
$fMinLon = min($minLon,$maxLon);
$fMaxLon = max($minLon,$maxLon);
$minLon = $fMinLon;
$maxLon = $fMaxLon;
$positionSW = Position::fromXY(rad2deg($minLon), rad2deg($minLat));
$positionNE = Position::fromXY(rad2deg($maxLon), rad2deg($maxLat));
// Check if we're shrinking too much
if ($positionSW->latitude() > $positionNE->latitude()) {
$center = $bbox->center();
return BoundingBox::fromCornerPositions($center, $center);
}
return BoundingBox::fromCornerPositions($positionSW, $positionNE);
}
final result calling above vs shrink:
shrunken bbox coords -> [-118.40360502789,33.96665666694,-118.32986907162,34.085855983985];