rail_network/src/rail_segment.rs

142 lines
5 KiB
Rust
Raw Normal View History

use crate::prelude::*;
use crate::rail_connector::RailConnector;
use std::error;
use std::fmt;
use std::iter::Iterator;
#[derive(Debug)]
pub enum Error {
IndexError(usize),
EndpointError(usize),
OffsetError(f32),
ConnectionError(usize),
StateError(f32),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
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}."),
}
}
}
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>;
/** Copy the connector associated with the given endpoint. */
fn get_connection(&self, endpoint: usize) -> Result<RailConnector, Error>;
/** 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. */
fn set_state(&mut self, value: f32) -> Result<f32, Error>;
}