|
|
""" |
|
|
Algorithm configuration settings and constants. |
|
|
|
|
|
Contains all configurable parameters for the land redistribution algorithm, |
|
|
organized into dataclasses for type safety and clarity. |
|
|
""" |
|
|
|
|
|
from dataclasses import dataclass, field |
|
|
from typing import Tuple |
|
|
|
|
|
|
|
|
@dataclass(frozen=True) |
|
|
class RoadSettings: |
|
|
"""Road and transportation infrastructure settings (TCVN standards).""" |
|
|
|
|
|
|
|
|
main_width: float = 20.0 |
|
|
internal_width: float = 10.0 |
|
|
sidewalk_width: float = 4.0 |
|
|
turning_radius: float = 15.0 |
|
|
|
|
|
|
|
|
@dataclass(frozen=True) |
|
|
class SubdivisionSettings: |
|
|
"""Block and lot subdivision settings.""" |
|
|
|
|
|
|
|
|
service_area_ratio: float = 0.10 |
|
|
min_block_area: float = 400.0 |
|
|
|
|
|
|
|
|
min_lot_width: float = 20.0 |
|
|
max_lot_width: float = 80.0 |
|
|
target_lot_width: float = 40.0 |
|
|
|
|
|
|
|
|
setback_distance: float = 6.0 |
|
|
fire_safety_gap: float = 4.0 |
|
|
|
|
|
|
|
|
solver_time_limit: float = 0.5 |
|
|
|
|
|
|
|
|
@dataclass(frozen=True) |
|
|
class InfrastructureSettings: |
|
|
"""Infrastructure planning settings.""" |
|
|
|
|
|
|
|
|
transformer_radius: float = 300.0 |
|
|
lots_per_transformer: int = 15 |
|
|
|
|
|
|
|
|
loop_redundancy_ratio: float = 0.15 |
|
|
max_connection_distance: float = 500.0 |
|
|
|
|
|
|
|
|
drainage_arrow_length: float = 30.0 |
|
|
|
|
|
|
|
|
@dataclass(frozen=True) |
|
|
class OptimizationSettings: |
|
|
"""NSGA-II genetic algorithm settings.""" |
|
|
|
|
|
|
|
|
population_size: int = 30 |
|
|
generations: int = 15 |
|
|
|
|
|
|
|
|
crossover_probability: float = 0.7 |
|
|
mutation_probability: float = 0.3 |
|
|
eta: float = 20.0 |
|
|
|
|
|
|
|
|
|
|
|
spacing_bounds: Tuple[float, float] = (50.0, 150.0) |
|
|
angle_bounds: Tuple[float, float] = (0.0, 90.0) |
|
|
|
|
|
|
|
|
good_block_ratio: float = 0.65 |
|
|
fragmented_block_ratio: float = 0.1 |
|
|
|
|
|
|
|
|
@dataclass(frozen=True) |
|
|
class AestheticSettings: |
|
|
"""Shape quality thresholds for aesthetic optimization (from Beauti_mode).""" |
|
|
|
|
|
|
|
|
|
|
|
min_rectangularity: float = 0.65 |
|
|
|
|
|
|
|
|
max_aspect_ratio: float = 4.0 |
|
|
|
|
|
|
|
|
|
|
|
min_lot_area: float = 250.0 |
|
|
|
|
|
|
|
|
deviation_penalty_weight: float = 50.0 |
|
|
|
|
|
|
|
|
enable_leftover_management: bool = True |
|
|
|
|
|
|
|
|
@dataclass |
|
|
class AlgorithmSettings: |
|
|
"""Complete algorithm configuration.""" |
|
|
|
|
|
road: RoadSettings = field(default_factory=RoadSettings) |
|
|
subdivision: SubdivisionSettings = field(default_factory=SubdivisionSettings) |
|
|
infrastructure: InfrastructureSettings = field(default_factory=InfrastructureSettings) |
|
|
optimization: OptimizationSettings = field(default_factory=OptimizationSettings) |
|
|
aesthetic: AestheticSettings = field(default_factory=AestheticSettings) |
|
|
|
|
|
|
|
|
random_seed: int = 42 |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, config: dict) -> 'AlgorithmSettings': |
|
|
"""Create settings from API config dictionary.""" |
|
|
settings = cls() |
|
|
|
|
|
|
|
|
if 'min_lot_width' in config: |
|
|
settings = cls( |
|
|
subdivision=SubdivisionSettings( |
|
|
min_lot_width=config.get('min_lot_width', 20.0), |
|
|
max_lot_width=config.get('max_lot_width', 80.0), |
|
|
target_lot_width=config.get('target_lot_width', 40.0), |
|
|
solver_time_limit=config.get('ortools_time_limit', 0.5), |
|
|
), |
|
|
optimization=OptimizationSettings( |
|
|
population_size=config.get('population_size', 30), |
|
|
generations=config.get('generations', 15), |
|
|
spacing_bounds=( |
|
|
config.get('spacing_min', 50.0), |
|
|
config.get('spacing_max', 150.0) |
|
|
), |
|
|
angle_bounds=( |
|
|
config.get('angle_min', 0.0), |
|
|
config.get('angle_max', 90.0) |
|
|
), |
|
|
), |
|
|
road=RoadSettings( |
|
|
main_width=DEFAULT_SETTINGS.road.main_width, |
|
|
internal_width=config.get('road_width', DEFAULT_SETTINGS.road.internal_width), |
|
|
sidewalk_width=DEFAULT_SETTINGS.road.sidewalk_width, |
|
|
turning_radius=DEFAULT_SETTINGS.road.turning_radius |
|
|
) |
|
|
) |
|
|
|
|
|
return settings |
|
|
|
|
|
|
|
|
|
|
|
DEFAULT_SETTINGS = AlgorithmSettings() |
|
|
|
|
|
|
|
|
|
|
|
ROAD_MAIN_WIDTH = DEFAULT_SETTINGS.road.main_width |
|
|
ROAD_INTERNAL_WIDTH = DEFAULT_SETTINGS.road.internal_width |
|
|
SIDEWALK_WIDTH = DEFAULT_SETTINGS.road.sidewalk_width |
|
|
TURNING_RADIUS = DEFAULT_SETTINGS.road.turning_radius |
|
|
SERVICE_AREA_RATIO = DEFAULT_SETTINGS.subdivision.service_area_ratio |
|
|
MIN_BLOCK_AREA = DEFAULT_SETTINGS.subdivision.min_block_area |
|
|
MIN_LOT_WIDTH = DEFAULT_SETTINGS.subdivision.min_lot_width |
|
|
MAX_LOT_WIDTH = DEFAULT_SETTINGS.subdivision.max_lot_width |
|
|
TARGET_LOT_WIDTH = DEFAULT_SETTINGS.subdivision.target_lot_width |
|
|
SETBACK_DISTANCE = DEFAULT_SETTINGS.subdivision.setback_distance |
|
|
FIRE_SAFETY_GAP = DEFAULT_SETTINGS.subdivision.fire_safety_gap |
|
|
SOLVER_TIME_LIMIT = DEFAULT_SETTINGS.subdivision.solver_time_limit |
|
|
TRANSFORMER_RADIUS = DEFAULT_SETTINGS.infrastructure.transformer_radius |
|
|
|
|
|
|
|
|
MIN_RECTANGULARITY = DEFAULT_SETTINGS.aesthetic.min_rectangularity |
|
|
MAX_ASPECT_RATIO = DEFAULT_SETTINGS.aesthetic.max_aspect_ratio |
|
|
MIN_LOT_AREA = DEFAULT_SETTINGS.aesthetic.min_lot_area |
|
|
DEVIATION_PENALTY_WEIGHT = DEFAULT_SETTINGS.aesthetic.deviation_penalty_weight |
|
|
ENABLE_LEFTOVER_MANAGEMENT = DEFAULT_SETTINGS.aesthetic.enable_leftover_management |
|
|
|