Skip to content

Commit

Permalink
Issue #83: display transition as connection.
Browse files Browse the repository at this point in the history
Display road part with placement=transition as connection between
two roads.
  • Loading branch information
enzet committed Nov 9, 2021
1 parent c3dfaf0 commit c193901
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 66 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
pip install .
- name: Check code style with Black
run: |
black -l 80 --check map_machine tests
black -l 80 --check map_machine setup.py tests
- name: Lint with Flake8
run: |
flake8 --max-line-length=80 --ignore=E203,W503
Expand Down
77 changes: 49 additions & 28 deletions map_machine/feature/road.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
WIP: road shape drawing.
"""
import logging
from collections import defaultdict
from dataclasses import dataclass
from typing import Any, Optional, Union

Expand Down Expand Up @@ -376,7 +377,7 @@ def __init__(
self.matcher: RoadMatcher = matcher

self.line: Polyline = Polyline(
[flinger.fling(x.coordinates) for x in self.nodes]
[flinger.fling(node.coordinates) for node in self.nodes]
)
self.width: Optional[float] = matcher.default_width
self.lanes: list[Lane] = []
Expand Down Expand Up @@ -420,19 +421,19 @@ def __init__(
self.layer = float(tags["layer"])

self.placement_offset: float = 0.0
self.transition: bool = False
self.is_transition: bool = False

if "placement" in tags:
value: str = tags["placement"]
if value == "transition":
self.is_transition = True
elif ":" in value and len(parts := value.split(":")) == 2:
place, lane = parts
lane_number: int = int(lane)
place, lane_string = parts
lane_number: int = int(lane_string)
self.placement_offset = (
sum(
x.get_width(self.scale)
for x in self.lanes[: lane_number - 1]
lane.get_width(self.scale)
for lane in self.lanes[: lane_number - 1]
)
- self.width * self.scale / 2
)
Expand Down Expand Up @@ -629,8 +630,12 @@ def __init__(
self.road_1, self.index_1 = connections[0]
self.priority = self.road_1.matcher.priority

self.min_layer: float = min(x[0].layer for x in connections)
self.max_layer: float = max(x[0].layer for x in connections)
self.min_layer: float = min(
connection[0].layer for connection in connections
)
self.max_layer: float = max(
connection[0].layer for connection in connections
)
self.scale: float = self.road_1.scale
self.flinger: Flinger = flinger

Expand Down Expand Up @@ -697,8 +702,11 @@ def __init__(
self.road_1.line.shorten(self.index_1, length)
self.road_2.line.shorten(self.index_2, length)

node: OSMNode = self.road_1.nodes[self.index_1]
point: np.ndarray = flinger.fling(node.coordinates)
node_1: OSMNode = self.road_1.nodes[self.index_1]
point_1: np.ndarray = flinger.fling(node_1.coordinates)
node_2: OSMNode = self.road_2.nodes[self.index_2]
point_2: np.ndarray = flinger.fling(node_2.coordinates)
point = (point_1 + point_2) / 2

points_1: list[np.ndarray] = get_curve_points(
self.road_1,
Expand Down Expand Up @@ -796,15 +804,29 @@ def draw(
if not self.roads:
return

layered_roads: dict[float, list[Road]] = {}
layered_connectors: dict[float, list[Connector]] = {}
layered_roads: dict[float, list[Road]] = defaultdict(list)
layered_connectors: dict[float, list[Connector]] = defaultdict(list)

for road in self.roads:
if road.layer not in layered_roads:
layered_roads[road.layer] = []
layered_roads[road.layer].append(road)
if not road.is_transition:
layered_roads[road.layer].append(road)
else:
connections = []
for end in 0, -1:
connections.append(
[
connection
for connection in self.nodes[road.nodes[end].id_]
if not connection[0].is_transition
]
)
if len(connections[0]) == 1 and len(connections[1]) == 1:
connector: Connector = ComplexConnector(
[connections[0][0], connections[1][0]], flinger
)
layered_connectors[road.layer].append(connector)

for _, connected in self.nodes.items():
for connected in self.nodes.values():
connector: Connector

if len(connected) <= 1:
Expand All @@ -819,19 +841,16 @@ def draw(
or index_2 not in [0, len(road_2.nodes) - 1]
):
connector = SimpleConnector(connected, flinger)
else:
elif not road_1.is_transition and not road_2.is_transition:
connector = ComplexConnector(connected, flinger)
else:
continue
else:
# We can also use SimpleIntersection(connected, flinger, scale)
# here.
continue

if connector.min_layer not in layered_connectors:
layered_connectors[connector.min_layer] = []
layered_connectors[connector.min_layer].append(connector)

if connector.max_layer not in layered_connectors:
layered_connectors[connector.max_layer] = []
layered_connectors[connector.max_layer].append(connector)

for layer in sorted(layered_roads.keys()):
Expand All @@ -844,17 +863,19 @@ def draw(

for road in roads:
road.draw(svg, True)
for connector in connectors:
if connector.min_layer == layer:
connector.draw_border(svg)
if connectors:
for connector in connectors:
if connector.min_layer == layer:
connector.draw_border(svg)

# Draw inner parts.

for road in roads:
road.draw(svg, False)
for connector in connectors:
if connector.max_layer == layer:
connector.draw(svg)
if connectors:
for connector in connectors:
if connector.max_layer == layer:
connector.draw(svg)

# Draw lane separators.

Expand Down
84 changes: 47 additions & 37 deletions tests/test_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,37 @@
SHAPE_EXTRACTOR: ShapeExtractor = ShapeExtractor(
workspace.ICONS_PATH, workspace.ICONS_CONFIG_PATH
)


ROAD_TYPES: list[dict[str, str]] = [
{"highway": "motorway"},
{"highway": "trunk"},
{"highway": "primary"},
{"highway": "secondary"},
{"highway": "tertiary"},
{"highway": "unclassified"},
{"highway": "residential"},
{"highway": "service"},
{"highway": "service_minor"},
{"highway": "road"},
{"highway": "pedestrian"},
{"highway": "living_street"},
{"highway": "bridleway"},
{"highway": "cycleway"},
{"highway": "footway"},
{"highway": "steps"},
{"highway": "path"},
{"highway": "track"},
{"highway": "raceway"},
DEFAULT_ZOOM: float = 18.0


HIGHWAY_VALUES: list[str] = [
"motorway",
"trunk",
"primary",
"secondary",
"tertiary",
"unclassified",
"residential",
"service",
"service_minor",
"road",
"pedestrian",
"living_street",
"bridleway",
"cycleway",
"footway",
"steps",
"path",
"track",
"raceway",
]

AEROWAY_TYPES: list[dict[str, str]] = [
{"aeroway": "runway"},
{"aeroway": "taxiway"},
AEROWAY_VALUES: list[str] = [
"runway",
"taxiway",
]

RAILWAY_TYPES: list[dict[str, str]] = [
RAILWAY_TAGS: list[dict[str, str]] = [
{"railway": "rail"},
{"railway": "light_rail"},
{"railway": "monorail"},
Expand Down Expand Up @@ -120,9 +121,9 @@ class Grid:
"""Creating map with elements ordered in grid."""

def __init__(self) -> None:
self.x_step: float = 0.0003
self.x_step: float = 0.0002
self.y_step: float = 0.0003
self.x_start: float = 0.0028
self.x_start: float = 0.0
self.index: int = 0
self.nodes: dict[OSMNode, tuple[int, int]] = {}
self.max_j: float = 0
Expand Down Expand Up @@ -156,7 +157,6 @@ def road_features(
) -> None:
"""Draw test image with different road features."""
osm_data: OSMData = OSMData()

grid: Grid = Grid()

for i, type_ in enumerate(types):
Expand All @@ -166,8 +166,8 @@ def road_features(
node: OSMNode = grid.add_node({}, i, j)

if previous:
tags: dict[str, str] = dict(features[j - 1])
tags |= type_
tags: dict[str, str] = dict(type_)
tags |= dict(features[j - 1])
way: OSMWay = OSMWay(
tags, i * (len(features) + 1) + j, [previous, node]
)
Expand All @@ -178,12 +178,15 @@ def road_features(


def draw(
osm_data: OSMData, output_path: Path, boundary_box: BoundaryBox
osm_data: OSMData,
output_path: Path,
boundary_box: BoundaryBox,
zoom: float = DEFAULT_ZOOM,
) -> None:
"""Draw map."""
configuration: MapConfiguration = MapConfiguration(level="all")

flinger: Flinger = Flinger(boundary_box, 18, osm_data.equator_length)
flinger: Flinger = Flinger(boundary_box, zoom, osm_data.equator_length)
svg: Drawing = Drawing(output_path.name, flinger.size)
constructor: Constructor = Constructor(
osm_data, flinger, SCHEME, SHAPE_EXTRACTOR, configuration
Expand All @@ -200,16 +203,23 @@ def draw(
if __name__ == "__main__":
logging.basicConfig(format="%(levelname)s %(message)s", level=logging.INFO)

highway_tags: list[dict[str, str]] = [
{"highway": value} for value in HIGHWAY_VALUES
]
aeroway_tags: list[dict[str, str]] = [
{"aeroway": value} for value in AEROWAY_VALUES
]

road_features(
ROAD_TYPES, ROAD_LANES_AND_FEATURES, Path("out") / "lanes.svg"
highway_tags, ROAD_LANES_AND_FEATURES, Path("out") / "lanes.svg"
)
road_features(
ROAD_TYPES + RAILWAY_TYPES + AEROWAY_TYPES,
highway_tags + RAILWAY_TAGS + aeroway_tags,
ROAD_WIDTHS_AND_FEATURES,
Path("out") / "width.svg",
)
road_features(
ROAD_TYPES,
PLACEMENT_FEATURES_1 + [{}] + PLACEMENT_FEATURES_2,
highway_tags,
PLACEMENT_FEATURES_1 + [{"highway": "none"}] + PLACEMENT_FEATURES_2,
Path("out") / "placement.svg",
)

0 comments on commit c193901

Please sign in to comment.