Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve overlapping polygons by merging them #36

Closed
martinfleis opened this issue Aug 25, 2022 · 2 comments
Closed

Resolve overlapping polygons by merging them #36

martinfleis opened this issue Aug 25, 2022 · 2 comments

Comments

@martinfleis
Copy link
Collaborator

I am currently trying to use geoplanar to preprocess building footprints that have a ton of overlapping geometries. In some cases, trimming is not the right solution because the two polygons represent different height of parts of buildings. So the solution there is to merge then together.

I have a function that does that, would you be interested in a PR?

def merge_overlapping(gdf, merge_limit, overlap_limit, largest=None):
    """Merge overlapping polygons based on a set of conditions.
    
    Overlapping polygons smaller than ``merge_limit`` are merged to a neighboring polygon.
    If ``largest=None`` it picks one randomly, otherwise it picks the largest (True) or the
    smallest (False).
    
    Polygons larger than ``merge_limit`` are merged to neighboring if they share area larger
    than ``area * overlap_limit``.
    
    Parameters
    ----------
    gdf : GeoDataFrame
        GeoDataFrame with polygon or mutli polygon geometry
    merge_limit : float
        area of overlapping polygons that are to be merged with neighbors no matter the size
        of the overlap
    overlap_limit : float (0-1)
        ratio of area of an overlapping polygon that has to be shared with other polygon 
        to merge both into a one
    largest : bool (default None)
        Merge each overlapping polygons smaller than merge_limit with its largest (True), or smallest (False) neighbor.
        If None, merge with any neighbor non-deterministically but performantly.
        
    Returns
    -------

    GeoDataFrame
    """
    neighbors = {}
    for i, poly in tqdm(gdf.geometry.iteritems(), total=len(gdf)):
        hits = gdf.sindex.query(poly, predicate='intersects')
        hits = hits[hits != i]

        if hits.size == 0:
            neighbors[i] = []
            continue

        if poly.area < merge_limit:
            if hits.size == 0:
                neighbors[i] = list(hits)
            else:
                if largest is None:
                    neighbors[i] = [hits[0]]
                else:
                    sub = gdf.geometry.iloc[hits]
                    inters = sub.intersection(poly.exterior)
                    if largest:
                        neighbors[i] = [inters.length.idxmax()]
                    else:
                        neighbors[i] = [inters.length.idxmin()]
        else:
            sub = gdf.geometry.iloc[hits]
            inters = sub.intersection(poly)
            include = sub.index[inters.area > (sub.area * overlap_limit)]
            neighbors[i] = list(include)
    
    W = libpysal.weights.W(neighbors, silence_warnings=True)
    return gdf.dissolve(W.component_labels)
@sjsrey
Copy link
Owner

sjsrey commented Aug 25, 2022

This would definitely be a useful piece of functionality to have. +1 on a pr.

@martinfleis
Copy link
Collaborator Author

Closed by #50

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants