question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

transform_bounds does not appear to support bbox crossing the antimeridian

See original GitHub issue

example (EPSG:32601)

Upper Left  (365474, 7696071) 
Lower Left  (365474, 7591951) 
Upper Right (477094, 7696071)
Lower Right (477094, 7591951)

rasterio. warp.transform_bounds return flattened bounds.

transform_bounds('EPSG:32601', 'EPSG:4326', 365474, 7591951, 477094, 7696071)
-> (-179.90689695793938, 68.40816857051695, 179.96969316611757, 69.37306968939305)

correct bounds (179.5819541972332, 68.40816857051695, -177.55854062377162, 69.37306968939305)

It seems to need checking transformed points is crossing the antimeridian. For example, like this.

def is_clockwise(xs, ys):
    if len(xs) != len(ys):
        raise TransformError("xs and ys arrays must be the same length") 
    
    area = 0
    if len(xs) > 2:
        if xs[0] == xs[-1] and ys[0] == ys[-1]:
            length = len(xs) - 1
        else:
            length = len(xs)
        
        for i in range(length - 1):
            area = area + xs[i] * ys[i+1] - ys[i] * xs[i+1]
        area = area + xs[length - 1] * ys[0] - ys[length - 1] * xs[0]
            
    return area >= 0

def transform_bounds(
        src_crs,
        dst_crs,
        left,
        bottom,
        right,
        top,
        densify_pts=21):
    if densify_pts < 0:
        raise ValueError('densify parameter must be >= 0')

    if src_crs == dst_crs:
        return [left, bottom, right, top]
    
    in_xs = []
    in_ys = []

    if densify_pts > 0:
        densify_factor = 1.0 / float(densify_pts + 1)
        
        # left_bottom to right_bottom
        in_xs.extend(
            left + np.arange(1, densify_pts + 1, dtype=np.float64) *
            ((right - left) * densify_factor)
        )
        in_ys.extend([bottom] * densify_pts)
        # right_bottom to right_top
        in_xs.extend([right] * (densify_pts + 2))
        in_ys.extend(
            bottom + np.arange(0, densify_pts + 2, dtype=np.float64) *
            ((top - bottom) * densify_factor)
        )
        # right_top to left_top
        in_xs.extend(
            right + np.arange(1, densify_pts + 1, dtype=np.float64) *
            ((left - right) * densify_factor)
        )
        in_ys.extend([top] * densify_pts)
        # left_top to left_bottom
        in_xs.extend([left] * (densify_pts + 2))
        in_ys.extend(
            top + np.arange(0, densify_pts + 2, dtype=np.float64) *
            ((bottom - top) * densify_factor)
        )        

    else:
        in_xs = np.array(left, right, right, left,left)
        in_ys = np.array(bottom, bottom, top, top, bottom)

    xs, ys = transform(src_crs, dst_crs, in_xs, in_ys)
    if dst_crs == 'EPSG:4326' and not is_clockwise(xs, ys):
        xs = [x + 360 if x < 0 else x for x in xs]
        return (min(xs), min(ys), max(xs) - 360, max(ys))
    
    return (min(xs), min(ys), max(xs), max(ys))

cogeo.bounds, cogeo.get_zooms, reader.part , etc., a lot of methods to create tile are affected. Couldn’t we improve?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
vincentsaragocommented, Dec 22, 2020

Alright @yonda-yonda, first thanks for starting the PR I really appreciate it.

Working with bounds, crs and antimeridan is definitely not an easy task. I’d like for us to take a step back and define clearly:

  • what’s the problem (is there anything that make rio-tiler not working as expected)
  • why we think the problem is in rio-tiler (and not in morecantile or rasterio)
  • if there is a bug in rio-tiler, is it worth it to make rio-tiler more complicated for edge cases, instead of just raising a warning that rio-tiler is not optimized for this
1reaction
vincentsaragocommented, Dec 16, 2020

It has to be that self.bounds is always ‘EPSG:4326’, though.

this is not really defined anywhere in the docs, but yeah bounds should always be in WGS84.

Feel free to start a PR to improve tile_exits 🙏

Read more comments on GitHub >

github_iconTop Results From Across the Web

bounding boxes crossing the antimeridian are not rendered ...
Bounding boxes which cross the anti-meridian (i.e. international date line) do not show up correctly. Solr requires east and west values to ...
Read more >
gdal - Get a bounding box of a geometry that crosses the ...
It has no notion of SRS / antimeridian / etc. ... box from a geometry that crosses the antimeridian using OGR/GDAL is by...
Read more >
Wrapping lines/polygons across the antimeridian in Leaflet.js
My solution is not perfect, as I will show below, but it is a good start. Here is the code: function addLineToMap(start, end)...
Read more >
Antimeridian Crossing with Python and Shapely
Splitting or cutting GeoJSON polygons crossing the antimeridian (180th meridian or international date line) in Python with Shapely.
Read more >
rasterio Documentation - Read the Docs
Before Rasterio there was one Python option for accessing the many different kind of raster data files used in the GIS.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found