flutter_map icon indicating copy to clipboard operation
flutter_map copied to clipboard

[BUG] LatLngBounds does not account for angular wrapping

Open pcba-dev opened this issue 4 months ago • 2 comments

What is the bug?

I want check if some bounds are contained (LatLngBounds.contains) or overlapping (LatLngBounds.isOverlapping) another bound. In the case of bound boxes which wrap around the 180th meridian it fails since the current implementation does not account for it.

How can we reproduce it?

Define bounds that wrap around the 180th meridian, and check if they contain another bound that is indeed contained.

print(LatLngBounds(LatLng(0, 180), LatLng(45, -135)).containsBounds(LatLngBounds(LatLng(0, 180), LatLng(45, -150)))==true);
print(LatLngBounds(LatLng(0, 180), LatLng(45, -135)).containsBounds(LatLngBounds(LatLng(0, -165), LatLng(45, -135)))==true);
print(LatLngBounds(LatLng(0, 180), LatLng(45, -135)).containsBounds(LatLngBounds(LatLng(0, -165), LatLng(45, -150)))==true);

print(LatLngBounds(LatLng(0, 135), LatLng(45, -135)).containsBounds(LatLngBounds(LatLng(0, 150), LatLng(45, -135)))==true);
print(LatLngBounds(LatLng(0, 135), LatLng(45, -135)).containsBounds(LatLngBounds(LatLng(0, 180), LatLng(45, -135)))==true);
print(LatLngBounds(LatLng(0, 135), LatLng(45, -135)).containsBounds(LatLngBounds(LatLng(0, -165), LatLng(45, -135)))==true);

Do you have a potential solution?

    /// Flag indicating whether this bounds wrap around the 180th meridian. Longitudes are considered in the range (-180, 180].
  bool get wrapped => west >= 0 && east < 0;
 
  bool contains(final LatLongBounds other) {
    // First check if the other box is within the latitude bounds.
    if (other.south < south || other.north > north) {
      return false;
    }

    // Then check if the other box is within the longitude bounds considering the arc.
    final double eastVal = wrapped ? east + 360 : east;
    final double otherWest = wrapped && other.west < 0 ? other.west + 360 : other.west;
    final double otherEast = wrapped && other.east < 0 ? other.east + 360 : other.east;
    return otherWest >= west &&
        otherWest <= eastVal &&
        otherEast >= west &&
        otherEast <= eastVal &&
        otherEast > otherWest;
  }
  
  bool overlaps(final LatLongBounds other) {
    // First check if the other box is within the latitude bounds.
    if (other.south > north || other.north < south) {
      return false;
    }

    // Wrap around if the range wraps around the 180th meridian.
    final double eastVal = wrapped ? east + 360 : east;
    final double otherWest = wrapped && other.west < 0 ? other.west + 360 : other.west;
    final double otherEast = wrapped && other.east < 0 ? other.east + 360 : other.east;

    return (otherWest >= west && otherWest < eastVal) || (otherEast > west && otherEast <= eastVal);
  }

Platforms

any

Severity

Obtrusive: Prevents normal functioning but causes no errors in the console

pcba-dev avatar Mar 07 '24 12:03 pcba-dev