Skip to main content

elevator_core/components/
line.rs

1//! Line (physical path) component — shaft, tether, track, etc.
2
3use serde::{Deserialize, Serialize};
4
5use crate::ids::GroupId;
6
7/// Physical orientation of a line.
8///
9/// This is metadata for external systems (rendering, spatial queries).
10/// The simulation always operates along a 1D axis regardless of orientation.
11#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
12#[non_exhaustive]
13pub enum Orientation {
14    /// Standard vertical elevator shaft.
15    #[default]
16    Vertical,
17    /// Angled incline (e.g., funicular).
18    Angled {
19        /// Angle from horizontal in degrees (0 = horizontal, 90 = vertical).
20        degrees: f64,
21    },
22    /// Horizontal people-mover or transit line.
23    Horizontal,
24}
25
26/// 2D position on a floor plan (for spatial queries and rendering).
27#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
28pub struct FloorPosition {
29    /// X coordinate on the floor plan.
30    pub x: f64,
31    /// Y coordinate on the floor plan.
32    pub y: f64,
33}
34
35/// Component for a line entity — the physical path an elevator car travels.
36///
37/// In a building this is a hoistway/shaft. For a space elevator it is a
38/// tether or cable. The term "line" is domain-neutral.
39///
40/// A line belongs to exactly one [`GroupId`] at a time but can be
41/// reassigned at runtime (swing-car pattern). Multiple cars may share
42/// a line (multi-car shafts); collision avoidance is left to game hooks.
43///
44/// Intrinsic properties only — relationship data (which elevators, which
45/// stops) lives in [`LineInfo`](crate::dispatch::LineInfo) on the
46/// [`ElevatorGroup`](crate::dispatch::ElevatorGroup).
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct Line {
49    /// Human-readable name.
50    pub(crate) name: String,
51    /// Dispatch group this line currently belongs to.
52    pub(crate) group: GroupId,
53    /// Physical orientation (metadata for rendering).
54    pub(crate) orientation: Orientation,
55    /// Optional floor-plan position (for spatial queries).
56    pub(crate) position: Option<FloorPosition>,
57    /// Lowest reachable position along the line axis.
58    pub(crate) min_position: f64,
59    /// Highest reachable position along the line axis.
60    pub(crate) max_position: f64,
61    /// Maximum number of cars allowed on this line (None = unlimited).
62    pub(crate) max_cars: Option<usize>,
63}
64
65impl Line {
66    /// Human-readable name.
67    #[must_use]
68    pub fn name(&self) -> &str {
69        &self.name
70    }
71
72    /// Dispatch group this line currently belongs to.
73    #[must_use]
74    pub const fn group(&self) -> GroupId {
75        self.group
76    }
77
78    /// Physical orientation.
79    #[must_use]
80    pub const fn orientation(&self) -> Orientation {
81        self.orientation
82    }
83
84    /// Optional floor-plan position.
85    #[must_use]
86    pub const fn position(&self) -> Option<&FloorPosition> {
87        self.position.as_ref()
88    }
89
90    /// Lowest reachable position along the line axis.
91    #[must_use]
92    pub const fn min_position(&self) -> f64 {
93        self.min_position
94    }
95
96    /// Highest reachable position along the line axis.
97    #[must_use]
98    pub const fn max_position(&self) -> f64 {
99        self.max_position
100    }
101
102    /// Maximum number of cars allowed on this line.
103    #[must_use]
104    pub const fn max_cars(&self) -> Option<usize> {
105        self.max_cars
106    }
107}