feat: add cesium traffic signal countdowns

This commit is contained in:
2026-08-06 16:43:08 +08:00
parent 9fbc218e10
commit 043766b84e
22 changed files with 1022 additions and 170 deletions

View File

@@ -59,6 +59,7 @@ from osmassets import grass as _grass # noqa: E402
from osmassets import roads as _roads # noqa: E402
from osmassets import scrub as _scrub # noqa: E402
from osmassets import tree as _tree # noqa: E402
from osmassets import traffic_signals as _traffic_signals # noqa: E402
CUSTOM_MODEL_ROOT = os.path.abspath(os.path.join(
@@ -638,6 +639,7 @@ def build(args):
roads_c = new_collection("03_Roads")
buildings_c = new_collection("04_Buildings")
props_c = new_collection("05_Props")
traffic_dynamic_c = new_collection("06_TrafficSignalsDynamic")
ground_mat = material_from_spec(catalog.MATERIALS["ground"])
water_mat = material_from_spec(catalog.MATERIALS["water"])
@@ -661,6 +663,25 @@ def build(args):
layer["id"]: material_from_spec(spec)
for layer, spec in zip(catalog.ROAD_LAYERS, catalog.road_material_specs())
}
traffic_signal_mats = {
"metal": material_from_spec(catalog.MATERIALS["traffic_signal_metal"]),
"housing": material_from_spec(catalog.MATERIALS["traffic_signal_housing"]),
"lenses": {
"red": material_from_spec(catalog.MATERIALS["traffic_signal_red"]),
"yellow": material_from_spec(catalog.MATERIALS["traffic_signal_yellow"]),
"green": material_from_spec(catalog.MATERIALS["traffic_signal_green"]),
},
"active": material_from_spec(catalog.MATERIALS["traffic_signal_active_green"]),
"dynamic": {
state: material_from_spec(catalog.MATERIALS["traffic_signal_active_" + state])
for state in ("red", "yellow", "green")
},
}
traffic_signal_mats["dynamic"]["countdown"] = {}
for phase_group in (0, 1):
material = traffic_signal_mats["dynamic"]["green"].copy()
material.name = "Traffic Signal Countdown Group %d" % phase_group
traffic_signal_mats["dynamic"]["countdown"][phase_group] = material
b = bounds
scene_xmin, scene_ymin = projector.xy((b["min_lon"], b["min_lat"]))
@@ -690,6 +711,7 @@ def build(args):
"scrub_bush_count": 0,
"scrub_count": 0,
"scrub_tree_count": 0,
"traffic_signal_count": 0,
}
def add_scrub_patch_with_bushes(name, ring, ground_material, collection):
@@ -781,6 +803,22 @@ def build(args):
_roads.assemble_osm_fallback(
ways, projector, roads_c, road_mats["road_surface"])
traffic_signal_path = os.path.join(geojson_dir or "", "traffic_signals.json")
dynamic_signal_objects = 0
if os.path.exists(traffic_signal_path):
try:
with open(traffic_signal_path, "r", encoding="utf-8") as handle:
signal_data = json.load(handle)
counts["traffic_signal_count"] = _traffic_signals.assemble(
signal_data, projector, props_c, traffic_signal_mats)
dynamic_signal_objects = len(_traffic_signals.assemble_dynamic(
signal_data, projector, traffic_dynamic_c,
traffic_signal_mats["dynamic"]))
except (OSError, ValueError, TypeError) as error:
print("Traffic signal warning:", error)
if dynamic_signal_objects == 0:
raise RuntimeError("Traffic signal dynamic geometry failed") from error
trees = []
individual_tree_count = 0
for feature in point_features:
@@ -883,6 +921,7 @@ def build(args):
scene["scrub_bush_count"] = counts["scrub_bush_count"]
scene["scrub_tree_count"] = counts["scrub_tree_count"]
scene["fountain_count"] = counts["fountain_count"]
scene["traffic_signal_count"] = counts["traffic_signal_count"]
scene["tree_node_count"] = individual_tree_count
scene["tree_row_count"] = row_tree_count
scene["tree_count"] = len(trees)
@@ -914,6 +953,8 @@ def build(args):
"scrub_bushes": counts["scrub_bush_count"],
"scrub_trees": counts["scrub_tree_count"],
"fountains": counts["fountain_count"],
"traffic_signals": counts["traffic_signal_count"],
"traffic_signal_dynamic_objects": dynamic_signal_objects,
"tree_nodes": individual_tree_count,
"tree_row_instances": row_tree_count,
"trees": len(trees),