2025-01-03 17:39:08 -05:00
|
|
|
use crate::prelude::*;
|
|
|
|
use crate::rail_connector::RailConnector;
|
|
|
|
use std::error;
|
|
|
|
use std::fmt;
|
|
|
|
use std::iter::Iterator;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
2025-01-20 13:50:07 -05:00
|
|
|
IndexError(usize),
|
|
|
|
EndpointError(usize),
|
|
|
|
OffsetError(f32),
|
|
|
|
ConnectionError(usize),
|
|
|
|
StateError(f32),
|
2025-01-03 17:39:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
2025-01-20 13:50:07 -05:00
|
|
|
Self::IndexError(index) => write!(f, "Nonexistent sub-segment index: {index}."),
|
|
|
|
Self::EndpointError(endpoint) => write!(f, "Nonexistent endpoint index: {endpoint}."),
|
|
|
|
Self::OffsetError(offset) => write!(f, "Invalid offset: {offset}."),
|
|
|
|
Self::ConnectionError(endpoint) => write!(f, "Endpoint {endpoint} is not connected."),
|
|
|
|
Self::StateError(state) => write!(f, "Invalid state: {state}."),
|
2025-01-03 17:39:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl error::Error for Error {}
|
|
|
|
|
|
|
|
pub struct ConnectionIter<'a> {
|
|
|
|
segment: &'a dyn RailSegment,
|
|
|
|
index: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> ConnectionIter<'a> {
|
|
|
|
pub fn new(segment: &'a impl RailSegment) -> Self {
|
|
|
|
Self {
|
|
|
|
segment,
|
|
|
|
index: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for ConnectionIter<'a> {
|
|
|
|
type Item = &'a RailConnector;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
while self.index < self.segment.num_endpoints() {
|
|
|
|
if let Ok(connection) = self.segment.borrow_connection(self.index) {
|
|
|
|
self.index += 1;
|
|
|
|
return Some(connection);
|
|
|
|
} else {
|
|
|
|
self.index += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** A RailSegment represents a section of track.
|
|
|
|
* They contain at least one internal curve which is addressibe via an integer
|
|
|
|
* index. Valid indecies start at 0, though a negative index may be used to
|
|
|
|
* indicate that a point does not exist on any internal curve. Offsets are in
|
|
|
|
* Godot units (which shall be interpreted as meters).
|
|
|
|
*/
|
|
|
|
pub trait RailSegment {
|
|
|
|
|
|
|
|
/** Get the overall length of the internal curve represented by the given
|
|
|
|
* `index`.
|
|
|
|
*/
|
|
|
|
fn get_length(&self, index: usize) -> Result<f32, Error>;
|
|
|
|
|
|
|
|
/** Get the location defined by the given `offset` on the internal curve
|
|
|
|
* represented by the given `index`.
|
|
|
|
*/
|
|
|
|
fn sample(&self, index: usize, offset: f32) -> Result<Vector3, Error>;
|
|
|
|
|
|
|
|
/** Get the location defined by the given `offset` on the internal curve
|
|
|
|
* represented by the given `index`, but with additional rotation data.
|
|
|
|
*/
|
|
|
|
fn sample_with_rotation(&self, index: usize, offset: f32) -> Result<Transform3D, Error>;
|
|
|
|
|
|
|
|
/** Similar to sample_with_rotation, but the rotation is facing the opposite direction.
|
|
|
|
*/
|
|
|
|
fn sample_with_rotation_reverse(&self, index: usize, offset: f32) -> Result<Transform3D, Error>;
|
|
|
|
|
|
|
|
/** Get the direction that constitutes "up" for the given `offset` on the
|
|
|
|
* internal curve represented by the given `index`.
|
|
|
|
*/
|
|
|
|
fn sample_up_vector(&self, index: usize, offset: f32) -> Result<Vector3, Error>;
|
|
|
|
|
|
|
|
// endpoint functions
|
|
|
|
|
|
|
|
/** Get the segment index associated with an endpoint. */
|
|
|
|
fn segment_from_endpoint(&self, endpoint: usize) -> Result<usize, Error>;
|
|
|
|
|
|
|
|
/** Get the location of an endpoint. */
|
|
|
|
fn get_endpoint_transform(&self, endpoint: usize) -> Result<Transform3D, Error>;
|
|
|
|
|
|
|
|
/** Get whether an endpoint represents the upper or lower end of a segment. */
|
|
|
|
fn is_endpoint_upper(&self, endpoint: usize) -> Result<bool, Error>;
|
|
|
|
|
|
|
|
/** Get the number of endpoins this segment has. */
|
|
|
|
fn num_endpoints(&self) -> usize;
|
|
|
|
|
|
|
|
// connection functions
|
|
|
|
|
|
|
|
/** Borrow the connector associated with the given endpoint. */
|
|
|
|
fn borrow_connection(&self, endpoint: usize) -> Result<&RailConnector, Error>;
|
|
|
|
|
2025-01-20 13:50:07 -05:00
|
|
|
/** Copy the connector associated with the given endpoint. */
|
|
|
|
fn get_connection(&self, endpoint: usize) -> Result<RailConnector, Error>;
|
|
|
|
|
2025-01-03 17:39:08 -05:00
|
|
|
/** Check if a connection is established on the given endpoint. */
|
|
|
|
fn check_connection(&self, endpoint: usize) -> Result<bool, Error>;
|
|
|
|
|
|
|
|
/** Get an iterator of the connections on this segment.
|
|
|
|
* If an endpoint is not connected, then it will not be represented by this iterator.
|
|
|
|
* This iterator keeps an immutable reference to the segment from which it was created.
|
|
|
|
*/
|
|
|
|
fn connection_iter(&self) -> ConnectionIter;
|
|
|
|
|
|
|
|
/** Add a connection to the given endpoint.
|
|
|
|
* Any previous connection on it is overwritten.
|
|
|
|
*/
|
|
|
|
fn add_connection(&mut self, endpoint: usize, connector: RailConnector) -> Result<bool, Error>;
|
|
|
|
|
|
|
|
/** Remove the given endpoint's connection if it has one. */
|
|
|
|
fn remove_connection(&mut self, endpoint: usize) -> Result<bool, Error>;
|
|
|
|
|
|
|
|
/** Remove all connections from the segment. */
|
|
|
|
fn remove_all_connections(&mut self);
|
|
|
|
|
|
|
|
// internal variable state functions
|
|
|
|
|
|
|
|
/** Get the internal state float value. */
|
|
|
|
fn get_state(&self) -> f32;
|
|
|
|
|
|
|
|
/** Set the internal state float value. */
|
2025-01-20 13:50:07 -05:00
|
|
|
fn set_state(&mut self, value: f32) -> Result<f32, Error>;
|
2025-01-03 17:39:08 -05:00
|
|
|
}
|