geokit icon indicating copy to clipboard operation
geokit copied to clipboard

bumped into a shrink call on a BoundingBox that yielded a bbox that goes around the globe

Open victusfate opened this issue 3 years ago • 0 comments

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
                )
        )
Screen Shot 2021-03-09 at 2 08 52 PM

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]; Screen Shot 2021-03-09 at 1 55 53 PM

victusfate avatar Mar 09 '21 19:03 victusfate