diff --git a/src/titiler/core/titiler/core/factory.py b/src/titiler/core/titiler/core/factory.py index faad24749..7f32e5abb 100644 --- a/src/titiler/core/titiler/core/factory.py +++ b/src/titiler/core/titiler/core/factory.py @@ -23,7 +23,6 @@ from fastapi.dependencies.utils import get_parameterless_sub_dependant from fastapi.params import Depends as DependsFunc from geojson_pydantic.features import Feature, FeatureCollection -from geojson_pydantic.geometries import MultiPolygon, Polygon from morecantile import TileMatrixSet from morecantile import tms as morecantile_tms from morecantile.defaults import TileMatrixSets @@ -85,7 +84,7 @@ from titiler.core.resources.enums import ImageType from titiler.core.resources.responses import GeoJSONResponse, JSONResponse, XMLResponse from titiler.core.routing import EndpointScope -from titiler.core.utils import render_image +from titiler.core.utils import bounds_to_geometry, render_image jinja2_env = jinja2.Environment( loader=jinja2.ChoiceLoader([jinja2.PackageLoader(__package__, "templates")]) @@ -398,15 +397,7 @@ def info_geojson( with rasterio.Env(**env): with self.reader(src_path, **reader_params.as_dict()) as src_dst: bounds = src_dst.get_geographic_bounds(crs or WGS84_CRS) - if bounds[0] > bounds[2]: - pl = Polygon.from_bounds(-180, bounds[1], bounds[2], bounds[3]) - pr = Polygon.from_bounds(bounds[0], bounds[1], 180, bounds[3]) - geometry = MultiPolygon( - type="MultiPolygon", - coordinates=[pl.coordinates, pr.coordinates], - ) - else: - geometry = Polygon.from_bounds(*bounds) + geometry = bounds_to_geometry(bounds) return Feature( type="Feature", @@ -1443,15 +1434,7 @@ def info_geojson( with rasterio.Env(**env): with self.reader(src_path, **reader_params.as_dict()) as src_dst: bounds = src_dst.get_geographic_bounds(crs or WGS84_CRS) - if bounds[0] > bounds[2]: - pl = Polygon.from_bounds(-180, bounds[1], bounds[2], bounds[3]) - pr = Polygon.from_bounds(bounds[0], bounds[1], 180, bounds[3]) - geometry = MultiPolygon( - type="MultiPolygon", - coordinates=[pl.coordinates, pr.coordinates], - ) - else: - geometry = Polygon.from_bounds(*bounds) + geometry = bounds_to_geometry(bounds) return Feature( type="Feature", @@ -1701,15 +1684,7 @@ def info_geojson( with rasterio.Env(**env): with self.reader(src_path, **reader_params.as_dict()) as src_dst: bounds = src_dst.get_geographic_bounds(crs or WGS84_CRS) - if bounds[0] > bounds[2]: - pl = Polygon.from_bounds(-180, bounds[1], bounds[2], bounds[3]) - pr = Polygon.from_bounds(bounds[0], bounds[1], 180, bounds[3]) - geometry = MultiPolygon( - type="MultiPolygon", - coordinates=[pl.coordinates, pr.coordinates], - ) - else: - geometry = Polygon.from_bounds(*bounds) + geometry = bounds_to_geometry(bounds) return Feature( type="Feature", diff --git a/src/titiler/core/titiler/core/utils.py b/src/titiler/core/titiler/core/utils.py index eaffe7307..99513d7ae 100644 --- a/src/titiler/core/titiler/core/utils.py +++ b/src/titiler/core/titiler/core/utils.py @@ -4,11 +4,12 @@ from typing import Any, Optional, Sequence, Tuple, Union import numpy +from geojson_pydantic.geometries import MultiPolygon, Polygon from rasterio.dtypes import dtype_ranges from rio_tiler.colormap import apply_cmap from rio_tiler.errors import InvalidDatatypeWarning from rio_tiler.models import ImageData -from rio_tiler.types import ColorMapType, IntervalTuple +from rio_tiler.types import BBox, ColorMapType, IntervalTuple from rio_tiler.utils import linear_rescale, render from titiler.core.resources.enums import ImageType @@ -116,3 +117,15 @@ def render_image( ), output_format.mediatype, ) + + +def bounds_to_geometry(bounds: BBox) -> Union[Polygon, MultiPolygon]: + """Convert bounds to geometry.""" + if bounds[0] > bounds[2]: + pl = Polygon.from_bounds(-180, bounds[1], bounds[2], bounds[3]) + pr = Polygon.from_bounds(bounds[0], bounds[1], 180, bounds[3]) + return MultiPolygon( + type="MultiPolygon", + coordinates=[pl.coordinates, pr.coordinates], + ) + return Polygon.from_bounds(*bounds) diff --git a/src/titiler/mosaic/titiler/mosaic/factory.py b/src/titiler/mosaic/titiler/mosaic/factory.py index 052cbf4ac..03dab94a8 100644 --- a/src/titiler/mosaic/titiler/mosaic/factory.py +++ b/src/titiler/mosaic/titiler/mosaic/factory.py @@ -11,7 +11,7 @@ from cogeo_mosaic.mosaic import MosaicJSON from fastapi import Depends, HTTPException, Path, Query from geojson_pydantic.features import Feature -from geojson_pydantic.geometries import MultiPolygon, Polygon +from geojson_pydantic.geometries import Polygon from morecantile import tms as morecantile_tms from morecantile.defaults import TileMatrixSets from pydantic import Field @@ -48,7 +48,7 @@ from titiler.core.models.OGC import TileSet, TileSetList from titiler.core.resources.enums import ImageType, OptionalHeader from titiler.core.resources.responses import GeoJSONResponse, JSONResponse, XMLResponse -from titiler.core.utils import render_image +from titiler.core.utils import bounds_to_geometry, render_image from titiler.mosaic.models.responses import Point MOSAIC_THREADS = int(os.getenv("MOSAIC_CONCURRENCY", MAX_THREADS)) @@ -257,15 +257,7 @@ def info_geojson( **backend_params.as_dict(), ) as src_dst: bounds = src_dst.get_geographic_bounds(crs or WGS84_CRS) - if bounds[0] > bounds[2]: - pl = Polygon.from_bounds(-180, bounds[1], bounds[2], bounds[3]) - pr = Polygon.from_bounds(bounds[0], bounds[1], 180, bounds[3]) - geometry = MultiPolygon( - type="MultiPolygon", - coordinates=[pl.coordinates, pr.coordinates], - ) - else: - geometry = Polygon.from_bounds(*bounds) + geometry = bounds_to_geometry(bounds) return Feature( type="Feature", diff --git a/src/titiler/xarray/titiler/xarray/factory.py b/src/titiler/xarray/titiler/xarray/factory.py index 897016cd2..579091685 100644 --- a/src/titiler/xarray/titiler/xarray/factory.py +++ b/src/titiler/xarray/titiler/xarray/factory.py @@ -6,7 +6,6 @@ from attrs import define, field from fastapi import Body, Depends, Query from geojson_pydantic.features import Feature, FeatureCollection -from geojson_pydantic.geometries import MultiPolygon, Polygon from rio_tiler.constants import WGS84_CRS from rio_tiler.models import Info from typing_extensions import Annotated @@ -23,6 +22,7 @@ from titiler.core.factory import TilerFactory as BaseTilerFactory from titiler.core.models.responses import InfoGeoJSON, StatisticsGeoJSON from titiler.core.resources.responses import GeoJSONResponse, JSONResponse +from titiler.core.utils import bounds_to_geometry from titiler.xarray.dependencies import DatasetParams, PartFeatureParams, XarrayParams from titiler.xarray.io import Reader @@ -116,16 +116,7 @@ def info_geojson( with rasterio.Env(**env): with self.reader(src_path, **reader_params.as_dict()) as src_dst: bounds = src_dst.get_geographic_bounds(crs or WGS84_CRS) - if bounds[0] > bounds[2]: - pl = Polygon.from_bounds(-180, bounds[1], bounds[2], bounds[3]) - pr = Polygon.from_bounds(bounds[0], bounds[1], 180, bounds[3]) - geometry = MultiPolygon( - type="MultiPolygon", - coordinates=[pl.coordinates, pr.coordinates], - ) - else: - geometry = Polygon.from_bounds(*bounds) - + geometry = bounds_to_geometry(bounds) info = src_dst.info().model_dump() if show_times and "time" in src_dst.input.dims: times = [str(x.data) for x in src_dst.input.time]