Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions lib/src/geo/latlng_bounds.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,40 @@ class LatLngBounds {
east = min(longitudeCenter + longitudeWidth / 2, maxLongitude),
west = max(longitudeCenter - longitudeWidth / 2, minLongitude);

/// Creates bounds that can span the antimeridian. If this is the case,
/// [west] will be larger than [east].
LatLngBounds.unconstrainedLng({
required this.north,
required this.south,
required this.longitudeCenter,
required this.longitudeWidth,
}) : assert(north <= maxLatitude,
"The north latitude can't be bigger than $maxLatitude: $north"),
assert(north >= minLatitude,
"The north latitude can't be smaller than $minLatitude: $north"),
assert(south <= maxLatitude,
"The south latitude can't be bigger than $maxLatitude: $south"),
assert(south >= minLatitude,
"The south latitude can't be smaller than $minLatitude: $south"),
assert(longitudeCenter <= maxLongitude,
"The longitude center can't be bigger than $maxLongitude: $longitudeCenter"),
assert(longitudeCenter >= minLongitude,
"The longitude center can't be smaller than $minLongitude: $longitudeCenter"),
assert(longitudeWidth >= 0, 'The longitude width must be positive'),
assert(
north >= south,
"The north latitude ($north) can't be smaller than the "
'south latitude ($south)',
),
east = _wrapLng(longitudeCenter + longitudeWidth / 2),
west = _wrapLng(longitudeCenter - longitudeWidth / 2);

static double _wrapLng(double longitude) => longitude > maxLongitude
? longitude - 360
: longitude < minLongitude
? longitude + 360
: longitude;

/// Create a [LatLngBounds] instance from raw edge values.
///
/// Potentially throws assertion errors if the coordinates exceed their max
Expand Down
70 changes: 55 additions & 15 deletions lib/src/map/camera/camera_fit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ class FitBounds extends CameraFit {
projectedCenter = (swPoint + nePoint) / 2 + paddingOffset;
}

final center = camera.unprojectAtZoom(projectedCenter, newZoom);
final center = _correctBoundsCenterForAntimeridianSpan(
camera.unprojectAtZoom(projectedCenter, newZoom),
bounds,
);

return camera.withPosition(
center: center,
zoom: newZoom,
Expand All @@ -137,16 +141,13 @@ class FitBounds extends CameraFit {
MapCamera camera,
Offset pixelPadding,
) {
final nw = bounds.northWest;
final se = bounds.southEast;
var size = camera.nonRotatedSize - pixelPadding as Size;
// Prevent negative size which results in NaN zoom value later on in the calculation

size = Size(math.max(0, size.width), math.max(0, size.height));
var boundsSize = Rect.fromPoints(
camera.projectAtZoom(se, camera.zoom),
camera.projectAtZoom(nw, camera.zoom),
).size;

Size boundsSize = _boundsSizeWithPossibleAntimeridianSpan(bounds, camera);

if (camera.rotation != 0.0) {
final cosAngle = math.cos(camera.rotationRad).abs();
final sinAngle = math.sin(camera.rotationRad).abs();
Expand Down Expand Up @@ -225,10 +226,8 @@ class FitInsideBounds extends CameraFit {

final cameraSize = camera.nonRotatedSize - paddingTotalXY as Size;

final projectedBoundsSize = Rect.fromPoints(
camera.projectAtZoom(bounds.southEast, camera.zoom),
camera.projectAtZoom(bounds.northWest, camera.zoom),
).size;
final projectedBoundsSize =
_boundsSizeWithPossibleAntimeridianSpan(bounds, camera);

final scale = _rectInRotRectScale(
angleRad: camera.rotationRad,
Expand All @@ -254,10 +253,13 @@ class FitInsideBounds extends CameraFit {
);
newZoom = newZoom.clamp(min, max);

final newCenter = _getCenter(
camera,
newZoom: newZoom,
paddingOffset: paddingOffset,
final newCenter = _correctBoundsCenterForAntimeridianSpan(
_getCenter(
camera,
newZoom: newZoom,
paddingOffset: paddingOffset,
),
bounds,
);

return camera.withPosition(
Expand Down Expand Up @@ -496,3 +498,41 @@ class FitCoordinates extends CameraFit {
return newZoom.clamp(min, max);
}
}

LatLng _correctBoundsCenterForAntimeridianSpan(
LatLng center,
LatLngBounds bounds,
) {
if (bounds.west > bounds.east) {
// Handle a bounding box that spans the antimeridian
var centerLng = (bounds.west + (bounds.east + 360)) / 2;
if (centerLng > 180) {
centerLng -= 360;
}

return LatLng(center.latitude, centerLng);
} else {
return center;
}
}

Size _boundsSizeWithPossibleAntimeridianSpan(
LatLngBounds bounds,
MapCamera camera,
) {
if (bounds.west > bounds.east) {
// Handle a bounding box that spans the antimeridian
return Rect.fromPoints(
camera.projectAtZoom(
LatLng(bounds.south, bounds.east + 360),
camera.zoom,
),
camera.projectAtZoom(bounds.northWest, camera.zoom),
).size;
} else {
return Rect.fromPoints(
camera.projectAtZoom(bounds.southEast, camera.zoom),
camera.projectAtZoom(bounds.northWest, camera.zoom),
).size;
}
}