Skip to content
This repository has been archived by the owner on Nov 22, 2022. It is now read-only.

Splitting large polygons can take hours #12

Open
xivk opened this issue Oct 15, 2020 · 2 comments
Open

Splitting large polygons can take hours #12

xivk opened this issue Oct 15, 2020 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@xivk
Copy link
Contributor

xivk commented Oct 15, 2020

Splitting large polygons can take hours while there is a lot of room for improvement.

  • Most of the tiles are 100% covered by the polygons.
  • The polygons are split along the same lines at multiple zoom levels.

We should change the PolygonTiler to take advantage of these properties.

@xivk xivk self-assigned this Oct 15, 2020
@xivk xivk added the enhancement New feature or request label Oct 15, 2020
@xivk
Copy link
Contributor Author

xivk commented Oct 15, 2020

As a test case take the Russia boundary from OSM.

@FObermaier
Copy link
Contributor

Adding an additional PreparedGeometry.Contains check to return the whole tile as geometry should improve the performance a lot:

    /// <summary>
    /// Returns all the tiles this polygon is part of and the polygonal portion in it..
    /// </summary>
    /// <param name="polygon">The linestring.</param>
    /// <param name="zoom">The zoom.</param>
    /// <param name="margin">The margin for the tiles polygon (in %)</param>
    /// <returns>An enumerable of all tiles.</returns>
    public static IEnumerable<(ulong, IPolygonal)> Tiles(Polygon polygon, int zoom, int margin = 5)
    {
        // Get the envelope
        var envelope = polygon.EnvelopeInternal;
        var lt = Tile.CreateAroundLocation(envelope.MaxY, envelope.MinX, zoom);
        if (lt == null) throw new Exception();
        var rb = Tile.CreateAroundLocation(envelope.MinY, envelope.MaxX, zoom);
        if (rb == null) throw new Exception();

        // Compute the possible tile range
        var tileRange = new TileRange(lt.X, lt.Y, rb.X,rb.Y, zoom);

        // Build a prepared geometry to perform faster intersection predicate
        var prep = Geometries.Prepared.PreparedGeometryFactory.Prepare(polygon);

        // Test polygon tiles.
        foreach (var tile in tileRange)
        {
            if (tile == null) continue;
            var testPolygon = tile.ToPolygon(margin);
            if (prep.Contains(testPolygon))
            {
                // the whole tile polygon is inside the geometry
                yield return (tile.Id, testPolygon);
            }
            else if (prep.Intersects(testPolygon))
            {
                // Compute the intersection geometry
                var result = polygon.Intersection(testPolygon);

                // Only return if result is polygonal
                if (result is IPolygonal polygonalResult)
                    yield return (tile.Id, polygonalResult);
            }
        }
    }

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants