fleaflet / flutter_map

A versatile mapping package for Flutter. Simple and easy to learn, yet completely customizable and configurable, it's the best choice for mapping in your Flutter app.
https://pub.dev/packages/flutter_map
BSD 3-Clause "New" or "Revised" License
2.73k stars 859 forks source link

[BUG] LatLngBounds does not account for angular wrapping #1844

Open pcba-dev opened 6 months ago

pcba-dev commented 6 months ago

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

JaffaKetchup commented 3 months ago

Related to #1689 / #1860 ?

monsieurtanuki commented 2 months ago

In order to avoid regression, a solution would to add a named constructor like LatLngBounds.fromLTRB (cf. Rect) where the developer would be able to say "my left is 160 and my right is -140 so the middle is -170 (instead of 10)"

JaffaKetchup commented 1 month ago

This needs re-triage after #1860 was merged.

github-actions[bot] commented 2 weeks ago

This issue requires additional information in order to be resolved. However, there hasn't been any response within the last 3 weeks. If this issue still persists, please provide the requested information. This issue will be automatically closed in one week if there is no response.

monsieurtanuki commented 2 weeks ago

I started coding something weeks ago. May PR one day.