def centroid_corner(geom):
    '''all these characters working with corners could be merged and cleaned
    '''
    from shapely.geometry import Point
    
    if geom is None:
        return (None, None)
    
    distances = []  # set empty list of distances
    centroid = geom.centroid  # define centroid
    points = list(geom.exterior.coords)  # get points of a shape
    stop = len(points) - 1  # define where to stop
    for i in np.arange(
        len(points)
    ):  # for every point, calculate angle and add 1 if True angle
        if i == 0:
            continue
        elif i == stop:
            a = np.asarray(points[i - 1])
            b = np.asarray(points[i])
            c = np.asarray(points[1])
            p = Point(points[i])

            if _true_angle(a, b, c) is True:
                distance = centroid.distance(
                    p
                )  # calculate distance point - centroid
                distances.append(distance)  # add distance to the list
            else:
                continue

        else:
            a = np.asarray(points[i - 1])
            b = np.asarray(points[i])
            c = np.asarray(points[i + 1])
            p = Point(points[i])

            if _true_angle(a, b, c) is True:
                distance = centroid.distance(p)
                distances.append(distance)
            else:
                continue
    if not distances:  # circular buildings
        from momepy.dimension import _longest_axis

        if geom.has_z:
            coords = [
                (coo[0], coo[1]) for coo in geom.convex_hull.exterior.coords
            ]
        else:
            coords = geom.convex_hull.exterior.coords
        return (_longest_axis(coords) / 2, 0)

    return (np.mean(distances), np.std(distances))
Exemplo n.º 2
0
    def __init__(self, gdf):
        self.gdf = gdf
        # define empty list for results
        results_list = []
        results_list_sd = []

        # calculate angle between points, return true or false if real corner
        def true_angle(a, b, c):
            ba = a - b
            bc = c - b

            cosine_angle = np.dot(
                ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
            angle = np.arccos(cosine_angle)

            if np.degrees(angle) <= 170:
                return True
            if np.degrees(angle) >= 190:
                return True
            return False

        # iterating over rows one by one
        for index, row in tqdm(gdf.iterrows(), total=gdf.shape[0]):
            distances = []  # set empty list of distances
            centroid = row["geometry"].centroid  # define centroid
            points = list(
                row["geometry"].exterior.coords)  # get points of a shape
            stop = len(points) - 1  # define where to stop
            for i in np.arange(
                    len(points)
            ):  # for every point, calculate angle and add 1 if True angle
                if i == 0:
                    continue
                elif i == stop:
                    a = np.asarray(points[i - 1])
                    b = np.asarray(points[i])
                    c = np.asarray(points[1])
                    p = Point(points[i])

                    if true_angle(a, b, c) is True:
                        distance = centroid.distance(
                            p)  # calculate distance point - centroid
                        distances.append(distance)  # add distance to the list
                    else:
                        continue

                else:
                    a = np.asarray(points[i - 1])
                    b = np.asarray(points[i])
                    c = np.asarray(points[i + 1])
                    p = Point(points[i])

                    if true_angle(a, b, c) is True:
                        distance = centroid.distance(p)
                        distances.append(distance)
                    else:
                        continue
            if not distances:  # circular buildings
                from momepy.dimension import _longest_axis

                results_list.append(
                    _longest_axis(row["geometry"].convex_hull.exterior.coords)
                    / 2)
                results_list_sd.append(0)
            else:
                results_list.append(np.mean(distances))  # calculate mean
                results_list_sd.append(np.std(distances))  # calculate st.dev
        self.mean = pd.Series(results_list, index=gdf.index)
        self.std = pd.Series(results_list_sd, index=gdf.index)
Exemplo n.º 3
0
def centroid_corners(objects):
    """
    Calculates mean distance centroid - corners and st. deviation.

    .. math::
        \\overline{x}=\\frac{1}{n}\\left(\\sum_{i=1}^{n} dist_{i}\\right);\\space \\mathrm{SD}=\\sqrt{\\frac{\\sum|x-\\overline{x}|^{2}}{n}}

    Parameters
    ----------
    objects : GeoDataFrame
        GeoDataFrame containing objects

    Returns
    -------
    means, st_devs : tuple

    means : Series
        Series containing mean distance values.
    st_devs : Series
        Series containing standard deviation values.

    References
    ----------
    Schirmer PM and Axhausen KW (2015) A multiscale classification of urban morphology.
    Journal of Transport and Land Use 9(1): 101–130.
    + Cimburova (ADD)

    Examples
    --------
    >>> means, deviations = momepy.centroid_corners(buildings_df)
    Calculating distance centroid - corner...
    100%|██████████| 144/144 [00:00<00:00, 846.58it/s]
    Distances centroid - corner calculated.
    >>> buildings_df['ccd_means'] = means
    >>> buildings_df['ccd_stdev'] = deviations
    >>> buildings_df['ccd_means'][0]
    15.961531913184833
    >>> buildings_df['ccd_stdev'][0]
    3.0810634305400177
    """
    # define empty list for results
    results_list = []
    results_list_sd = []
    print('Calculating distance centroid - corner...')

    # calculate angle between points, return true or false if real corner
    def true_angle(a, b, c):
        ba = a - b
        bc = c - b

        cosine_angle = np.dot(ba,
                              bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
        angle = np.arccos(cosine_angle)

        if np.degrees(angle) <= 170:
            return True
        elif np.degrees(angle) >= 190:
            return True
        return False

    # iterating over rows one by one
    for index, row in tqdm(objects.iterrows(), total=objects.shape[0]):
        distances = []  # set empty list of distances
        centroid = row['geometry'].centroid  # define centroid
        points = list(row['geometry'].exterior.coords)  # get points of a shape
        stop = len(points) - 1  # define where to stop
        for i in np.arange(
                len(points)
        ):  # for every point, calculate angle and add 1 if True angle
            if i == 0:
                continue
            elif i == stop:
                a = np.asarray(points[i - 1])
                b = np.asarray(points[i])
                c = np.asarray(points[1])
                p = Point(points[i])

                if true_angle(a, b, c) is True:
                    distance = centroid.distance(
                        p)  # calculate distance point - centroid
                    distances.append(distance)  # add distance to the list
                else:
                    continue

            else:
                a = np.asarray(points[i - 1])
                b = np.asarray(points[i])
                c = np.asarray(points[i + 1])
                p = Point(points[i])

                if true_angle(a, b, c) is True:
                    distance = centroid.distance(p)
                    distances.append(distance)
                else:
                    continue
        if not distances:
            from momepy.dimension import _longest_axis
            results_list.append(
                _longest_axis(row['geometry'].convex_hull.exterior.coords) / 2)
            results_list_sd.append(0)
        else:
            results_list.append(np.mean(distances))  # calculate mean
            results_list_sd.append(np.std(distances))  # calculate st.dev
    means = pd.Series(results_list)
    st_devs = pd.Series(results_list_sd)

    print('Distances centroid - corner calculated.')
    return means, st_devs