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

Test/nodes #57

Merged
merged 10 commits into from
Jul 14, 2023
315 changes: 313 additions & 2 deletions tests/test_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np
import geopandas as gpd
import pandas as pd
from shapely.geometry import Point, Polygon
from shapely.geometry import Point, Polygon, JOIN_STYLE
from typing import List


Expand Down Expand Up @@ -319,13 +319,324 @@ def test_average_distance_between_buildings(self):
default_street_width = Settings.DEFAULT_STREET_WIDTH

expected = pd.DataFrame(
{"id": ids, "distance": pd.Series([1.5, 2.0, 1.0, 3.0, default_street_width])}
{
Settings.id_field: ids,
Settings.average_distance_between_buildings: pd.Series(
[1.5, 2.0, 1.0, 3.0, default_street_width]
),
}
)

actual = nodes.average_distance_between_buildings(ids, distance)

pd.testing.assert_frame_equal(expected, actual)

def test_buildings_intersecting_plan_area(self):
"""Test that the function buildings_intersecting_plan_area returns the correct intersecting buildings."""

polygon1 = Polygon([[0, 0], [0, 1], [1, 1], [1, 0]])
polygon2 = Polygon([[3, 3], [3, 4], [4, 4], [4, 3]])
building_id = pd.Series([0, 1])
building_height = pd.Series([5, 10])
building_geometry = pd.Series([polygon1, polygon2])
building_area = pd.Series([polygon1.area, polygon2.area])
crs = "epsg:3857"

total_plan_area_geometry_no_overlap = pd.Series([polygon1.buffer(1), polygon2.buffer(1)])
total_plan_area_geometry_some_overlap = pd.Series(
[polygon1.buffer(3.5), polygon2.buffer(3.5)]
)
total_plan_area_geometry_total_overlap = pd.Series([polygon1.buffer(5), polygon2.buffer(5)])

no_overlap_output_gdf = gpd.GeoDataFrame(
{
"building_id_neighbor": building_id,
"building_id_target": building_id,
"building_height_target": building_height,
"building_area_target": building_area,
"building_geometry": building_geometry,
"building_buffered_target": gpd.GeoSeries(total_plan_area_geometry_no_overlap),
"index_neighbor": building_id,
"building_height_neighbor": building_height,
"building_area_neighbor": building_area,
"building_buffered_neighbor": total_plan_area_geometry_no_overlap,
"building_geometry_neighbor": gpd.GeoSeries(building_geometry),
},
geometry="building_geometry",
).set_index("building_id_neighbor")

some_overlap_output_gdf = gpd.GeoDataFrame(
{
"building_id_neighbor": pd.Series([0, 0, 1, 1]),
"building_id_target": pd.Series([0, 1, 0, 1]),
"building_height_target": pd.Series([5, 10, 5, 10]),
"building_area_target": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_geometry": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[1],
building_geometry[0],
building_geometry[1],
]
),
"building_buffered_target": gpd.GeoSeries(
[
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[1],
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[1],
]
),
"index_neighbor": pd.Series([0, 0, 1, 1]),
"building_height_neighbor": pd.Series([5, 5, 10, 10]),
"building_area_neighbor": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_buffered_neighbor": pd.Series(
[
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[1],
total_plan_area_geometry_some_overlap[1],
]
),
"building_geometry_neighbor": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[0],
building_geometry[1],
building_geometry[1],
]
),
},
geometry="building_geometry",
).set_index("building_id_neighbor")

total_overlap_output_gdf = gpd.GeoDataFrame(
{
"building_id_neighbor": pd.Series([0, 0, 1, 1]),
"building_id_target": pd.Series([0, 1, 0, 1]),
"building_height_target": pd.Series([5, 10, 5, 10]),
"building_area_target": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_geometry": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[1],
building_geometry[0],
building_geometry[1],
]
),
"building_buffered_target": gpd.GeoSeries(
[
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[1],
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[1],
]
),
"index_neighbor": pd.Series([0, 0, 1, 1]),
"building_height_neighbor": pd.Series([5, 5, 10, 10]),
"building_area_neighbor": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_buffered_neighbor": pd.Series(
[
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[1],
total_plan_area_geometry_total_overlap[1],
]
),
"building_geometry_neighbor": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[0],
building_geometry[1],
building_geometry[1],
]
),
},
geometry="building_geometry",
).set_index("building_id_neighbor")

@dataclass
class TestCase:
name: str
input: pd.Series
expected: gpd.GeoDataFrame

testcases = [
TestCase(
name="no overlap",
input=total_plan_area_geometry_no_overlap,
expected=no_overlap_output_gdf,
),
TestCase(
name="some overlap",
input=total_plan_area_geometry_some_overlap,
expected=some_overlap_output_gdf,
),
TestCase(
name="total overlap",
input=total_plan_area_geometry_total_overlap,
expected=total_overlap_output_gdf,
),
]

for case in testcases:
actual = nodes.buildings_intersecting_plan_area(
building_id, building_height, building_geometry, building_area, case.input, crs
)
expected = case.expected
pd.testing.assert_frame_equal(
expected,
actual,
"failed test {} expected {}, actual {}".format(case.name, expected, actual),
)

def test_building_plan_area(self):
"""Test that the function building_plan_area returns the correct building plan area."""

polygon1 = Polygon([[0, 0], [0, 1], [1, 1], [1, 0]])
polygon2 = Polygon([[3, 3], [3, 4], [4, 4], [4, 3]])
building_id = pd.Series([0, 1])
building_height = pd.Series([5, 10])
building_geometry = pd.Series([polygon1, polygon2])
building_area = pd.Series([polygon1.area, polygon2.area])

total_plan_area_geometry_no_overlap = pd.Series([polygon1.buffer(1), polygon2.buffer(1)])
total_plan_area_geometry_some_overlap = pd.Series(
[
polygon1.buffer(2.5, join_style=JOIN_STYLE.mitre),
polygon2.buffer(2.5, join_style=JOIN_STYLE.mitre),
]
)
total_plan_area_geometry_total_overlap = pd.Series([polygon1.buffer(5), polygon2.buffer(5)])

no_overlap_gdf = gpd.GeoDataFrame(
{
"building_id_neighbor": building_id,
"building_id_target": building_id,
"building_height_target": building_height,
"building_area_target": building_area,
"building_geometry": building_geometry,
"building_buffered_target": gpd.GeoSeries(total_plan_area_geometry_no_overlap),
"index_neighbor": building_id,
"building_height_neighbor": building_height,
"building_area_neighbor": building_area,
"building_buffered_neighbor": total_plan_area_geometry_no_overlap,
"building_geometry_neighbor": gpd.GeoSeries(building_geometry),
},
geometry="building_geometry",
).set_index("building_id_neighbor")

some_overlap_gdf = gpd.GeoDataFrame(
{
"building_id_neighbor": pd.Series([0, 0, 1, 1]),
"building_id_target": pd.Series([0, 1, 0, 1]),
"building_height_target": pd.Series([5, 10, 5, 10]),
"building_area_target": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_geometry": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[1],
building_geometry[0],
building_geometry[1],
]
),
"building_buffered_target": gpd.GeoSeries(
[
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[1],
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[1],
]
),
"index_neighbor": pd.Series([0, 0, 1, 1]),
"building_height_neighbor": pd.Series([5, 5, 10, 10]),
"building_area_neighbor": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_buffered_neighbor": pd.Series(
[
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[0],
total_plan_area_geometry_some_overlap[1],
total_plan_area_geometry_some_overlap[1],
]
),
"building_geometry_neighbor": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[0],
building_geometry[1],
building_geometry[1],
]
),
},
geometry="building_geometry",
).set_index("building_id_neighbor")

total_overlap_gdf = gpd.GeoDataFrame(
{
"building_id_neighbor": pd.Series([0, 0, 1, 1]),
"building_id_target": pd.Series([0, 1, 0, 1]),
"building_height_target": pd.Series([5, 10, 5, 10]),
"building_area_target": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_geometry": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[1],
building_geometry[0],
building_geometry[1],
]
),
"building_buffered_target": gpd.GeoSeries(
[
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[1],
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[1],
]
),
"index_neighbor": pd.Series([0, 0, 1, 1]),
"building_height_neighbor": pd.Series([5, 5, 10, 10]),
"building_area_neighbor": pd.Series([1.0, 1.0, 1.0, 1.0]),
"building_buffered_neighbor": pd.Series(
[
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[0],
total_plan_area_geometry_total_overlap[1],
total_plan_area_geometry_total_overlap[1],
]
),
"building_geometry_neighbor": gpd.GeoSeries(
[
building_geometry[0],
building_geometry[0],
building_geometry[1],
building_geometry[1],
]
),
},
geometry="building_geometry",
).set_index("building_id_neighbor")

@dataclass
class TestCase:
name: str
input: gpd.GeoDataFrame
expected: List[float]

testcases = [
TestCase(name="no overlap", input=no_overlap_gdf, expected=[1.0, 1.0]),
TestCase(name="some overlap", input=some_overlap_gdf, expected=[1.25, 1.25]),
TestCase(name="total overlap", input=total_overlap_gdf, expected=[2.0, 2.0]),
]

for case in testcases:
actual = nodes.building_plan_area(case.input)
expected = pd.Series(case.expected)
pd.testing.assert_series_equal(
expected,
actual,
"failed test {} expected {}, actual {}".format(case.name, expected, actual),
)


if __name__ == "__main__":
unittest.main()