From 561fb1dca1e91f090b6f0bbeecf4f67c4c8f47c1 Mon Sep 17 00:00:00 2001 From: Pim Nelissen Date: Wed, 25 Feb 2026 14:31:42 +0100 Subject: [PATCH] update SegmentedRoadGenerator --- src/pg_rad/configs/defaults.py | 8 ++++ .../generators/segmented_road_generator.py | 47 ++++++++++++++----- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/pg_rad/configs/defaults.py b/src/pg_rad/configs/defaults.py index 9523c84..97fae3d 100644 --- a/src/pg_rad/configs/defaults.py +++ b/src/pg_rad/configs/defaults.py @@ -8,3 +8,11 @@ DEFAULT_ACQUISITION_TIME = 1.0 # --- Source defaults --- DEFAULT_PATH_HEIGHT = 0.0 DEFAULT_SOURCE_HEIGHT = 0.0 + +# --- Segmented road defaults --- +DEFAULT_MIN_TURN_ANGLE = 30. +DEFAULT_MAX_TURN_ANGLE = 90. + +DEFAULT_FRICTION_COEFF = 0.7 # dry asphalt +DEFAULT_GRAVITATIONAL_ACC = 9.81 # m/s^2 +DEFAULT_ALPHA = 100. \ No newline at end of file diff --git a/src/road_gen/generators/segmented_road_generator.py b/src/road_gen/generators/segmented_road_generator.py index 351d27f..0ba6f90 100644 --- a/src/road_gen/generators/segmented_road_generator.py +++ b/src/road_gen/generators/segmented_road_generator.py @@ -1,3 +1,4 @@ +import logging from typing import Tuple import numpy as np @@ -6,11 +7,16 @@ from .base_road_generator import BaseRoadGenerator from road_gen.prefabs import prefabs from road_gen.integrator.integrator import integrate_road +from pg_rad.configs import defaults + + +logger = logging.getLogger(__name__) + class SegmentedRoadGenerator(BaseRoadGenerator): def __init__( self, - length: int | float, + length: int | float | list[int | float], ds: int | float, velocity: int | float, mu: float = 0.7, @@ -29,14 +35,20 @@ class SegmentedRoadGenerator(BaseRoadGenerator): Defaults to random seed. """ + if isinstance(length, list): + length = sum( + [seg_len for seg_len in length if seg_len is not None] + ) super().__init__(length, ds, velocity, mu, g, seed) def generate( self, segments: list[str], - alpha: float = 100, - min_turn_angle: float = 15., - max_turn_angle: float = 90. + lengths: list[int | float] | None = None, + angles: list[int | float] | None = None, + alpha: float = defaults.DEFAULT_ALPHA, + min_turn_angle: float = defaults.DEFAULT_MIN_TURN_ANGLE, + max_turn_angle: float = defaults.DEFAULT_MAX_TURN_ANGLE ) -> Tuple[np.ndarray, np.ndarray]: """Generate a curvature profile from a list of segments. @@ -76,16 +88,21 @@ class SegmentedRoadGenerator(BaseRoadGenerator): self.segments = segments self.alpha = alpha - num_points = int(self.length / self.ds) + num_points = np.ceil(self.length / self.ds).astype(int) # divide num_points into len(segments) randomly sized parts. - parts = self._rng.dirichlet(np.full(len(segments), alpha), size=1)[0] - parts = parts * num_points - parts = np.round(parts).astype(int) + if isinstance(self.length, list): + parts = self.length + else: + parts = self._rng.dirichlet( + np.full(len(segments), alpha), + size=1)[0] + parts = parts * num_points + parts = np.round(parts).astype(int) - # correct round off so the sum of parts is still total length L. - if sum(parts) != num_points: - parts[0] += num_points - sum(parts) + # correct round off so the sum of parts is still total length L. + if sum(parts) != num_points: + parts[0] += num_points - sum(parts) curvature = np.zeros(num_points) current_index = 0 @@ -103,7 +120,13 @@ class SegmentedRoadGenerator(BaseRoadGenerator): R_min = max(self.min_radius, R_min_angle) if R_min > R_max_angle: - raise ValueError("No valid radius for this turn segment") + raise ValueError( + f"{seg_name} with length {seg_length} does not have " + "a possible radius. The minimum for the provided " + "velocity and friction coefficient is " + f"{self.min_radius}, but the possible range is " + f"({R_min}, {R_max_angle})" + ) rand_radius = self._rng.uniform(R_min, R_max_angle)