@@ -434,16 +434,16 @@ class BoundingBox:
434434 optionally (geo)referenced.
435435
436436 .. note::
437- About anti-meridian handling:
438- when working in a cyclic CRS like EPSG:4326 with a bounding box that crosses the anti-meridian ,
437+ About antimeridian handling:
438+ when working in a cyclic CRS like EPSG:4326 with a bounding box that crosses the antimeridian ,
439439 the "west" coordinate will be larger than the "east" coordinate.
440440 For example::
441441
442- # Bounding box of 10 degrees wide across the anti-meridian
442+ # Bounding box of 10 degrees wide across the antimeridian
443443 bbox_a = BoundingBox(west=175, east=-175, crs="EPSG:4326", ...)
444444
445445 # bounding box of 350 degrees wide, starting in the west
446- # and going all the way to the east, but not crossing the anti-meridian .
446+ # and going all the way to the east, but not crossing the antimeridian .
447447 bbox_b = BoundingBox(west=-175, east=175, crs="EPSG:4326", ...)
448448
449449 also see https://datatracker.ietf.org/doc/html/rfc7946#section-5.2
@@ -544,15 +544,25 @@ def assert_crs(self):
544544 def _crs_with_cyclic_x (crs : Union [None , str ]) -> bool :
545545 """
546546 Whether the x coordinate is cyclic (e.g. longitude in EPSG:4326)
547- which requires some special handling like coordinate normalization and anti-meridian crossing handling.
547+ which requires some special handling like coordinate normalization and antimeridian crossing handling.
548548 """
549549 return crs == "EPSG:4326"
550550
551551 @staticmethod
552552 def _normalize_longitude (x : float ) -> float :
553553 """Normalize an EPSG:4326 longitude coordinate to the range [-180, 180)"""
554+ # TODO: do this normalization in constructor, instead of each time on the fly?
554555 return (x + 180 ) % 360 - 180
555556
557+ def cyclic_antimeridian_crossing (self ) -> bool :
558+ """
559+ Whether this bounding box uses cyclic longitude coordinates
560+ and crosses the antimeridian (so that west > east).
561+ """
562+ return self ._crs_with_cyclic_x (self .crs ) and (
563+ self ._normalize_longitude (self .west ) > self ._normalize_longitude (self .east )
564+ )
565+
556566 def as_dict (self ) -> dict :
557567 return {
558568 "west" : self .west ,
@@ -571,7 +581,7 @@ def as_wsen_tuple(self) -> Tuple[float, float, float, float]:
571581 def as_polygon (self ) -> shapely .geometry .Polygon :
572582 """
573583 Get bounding box as a shapely Polygon.
574- Simple single polygon, but not ideal for proper handling of anti-meridian crossing in EPSG:4326,
584+ Simple single polygon, but not ideal for proper handling of antimeridian crossing in EPSG:4326,
575585 which require to split the geometry in two parts: use `as_geometry` instead for that.
576586 """
577587 west , east = self .west , self .east
@@ -584,7 +594,7 @@ def as_polygon(self) -> shapely.geometry.Polygon:
584594 return shapely .geometry .box (minx = west , miny = self .south , maxx = east , maxy = self .north )
585595
586596 def as_geometry (self ) -> Union [shapely .geometry .Polygon , shapely .geometry .MultiPolygon ]:
587- """Get bounding box as a shapely geometry (Polygon or MultiPolygon when crossing anti-meridian )"""
597+ """Get bounding box as a shapely geometry (Polygon or MultiPolygon when crossing antimeridian )"""
588598 west , east = self .west , self .east
589599 if self ._crs_with_cyclic_x (self .crs ):
590600 east = self ._normalize_longitude (east )
@@ -614,7 +624,7 @@ def as_geojson(self) -> dict:
614624
615625 def centroid (self ) -> Tuple [float , float ]:
616626 if self ._crs_with_cyclic_x (self .crs ):
617- # Properly handle cyclic longitude coordinates, and anti-meridian crossing
627+ # Properly handle cyclic longitude coordinates, and antimeridian crossing
618628 west = self ._normalize_longitude (self .west )
619629 east = self ._normalize_longitude (self .east )
620630 if west <= east :
@@ -654,7 +664,7 @@ def contains(self, x: float, y: float) -> bool:
654664 if west <= east :
655665 return west <= x <= east
656666 else :
657- # Handle anti-meridian crossing
667+ # Handle antimeridian crossing
658668 return not (east < x < west )
659669 else :
660670 return self .west <= x <= self .east
@@ -681,7 +691,7 @@ def reproject(self, crs: Union[str, int]) -> "BoundingBox":
681691 west , south , east , north = reprojected .bounds
682692
683693 if self ._crs_with_cyclic_x (crs ):
684- # Handle bounding boxes in EPSG:4326 around the anti-meridian
694+ # Handle bounding boxes in EPSG:4326 around the antimeridian
685695 # use the projection of the centroid to detect coordinate wrapping, and adjust bounds properly
686696 cx , cy = transformer .transform (* self .centroid ())
687697 if not (west <= cx <= east ):
0 commit comments