Skip to content

Commit

Permalink
fix: ends of lines not connecting to stations
Browse files Browse the repository at this point in the history
  • Loading branch information
CalliEve committed Jul 25, 2024
1 parent 6c484f5 commit 6b595c1
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 85 deletions.
2 changes: 1 addition & 1 deletion src/models/grid_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::ops::{
use crate::components::CanvasState;

/// Represents a node on the grid.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
pub struct GridNode(pub i32, pub i32);

impl GridNode {
Expand Down
233 changes: 149 additions & 84 deletions src/models/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,58 +38,58 @@ pub struct Line {
/// Color of the line.
color: (u8, u8, u8),
/// All stations the line visits.
stations: Vec<(Station, Vec<GridNode>, Option<Station>)>,
stations: Vec<Station>,
/// All edges between the stations.
edges: Vec<(Station, Vec<GridNode>, Option<Station>)>,
}

impl Line {
/// Create a new [`Line`] with the stations it visits and an identifier.
/// Color and name are set to default values.
pub fn new(stations: Vec<Station>, id: Option<String>) -> Self {
let mut l = Self {
stations: stations
.clone()
.into_iter()
.zip(
stations
.clone()
.into_iter()
.skip(1),
)
.map(|(s, a)| (s, Vec::new(), Some(a)))
.collect(),
Self {
edges: if stations.len() > 1 {
stations
.clone()
.into_iter()
.zip(
stations
.clone()
.into_iter()
.skip(1),
)
.map(|(s, a)| (s, Vec::new(), Some(a)))
.collect()
} else if let Some(s) = stations
.first()
.cloned()
{
vec![(s, Vec::new(), None)]
} else {
Vec::new()
},
stations,
id: id.unwrap_or_else(|| {
LINE_ID
.fetch_add(1, AtomicOrdering::SeqCst)
.to_string()
}),
color: (0, 0, 0),
name: String::new(),
};

if let Some(s) = stations
.last()
.cloned()
{
l.stations
.push((s, Vec::new(), None));
}

l
}

/// A getter method for the stations the line visits.
pub fn get_stations(&self) -> Vec<&Station> {
self.stations
.iter()
.map(|(s, ..)| s)
.collect()
}

/// A mutable getter method for the stations the line visits.
pub fn get_mut_stations(&mut self) -> Vec<&mut Station> {
self.stations
.iter_mut()
.map(|(s, ..)| s)
.collect()
}

Expand All @@ -102,9 +102,17 @@ impl Line {
before: Option<&Station>,
after: Option<&Station>,
) {
if !self
.stations
.contains(&station)
{
self.stations
.push(station.clone());
}

if let (Some(before_station), Some(after_station)) = (before, after) {
if let Some(index) = self
.stations
.edges
.iter()
.position(|s| {
&s.0 == before_station
Expand All @@ -113,50 +121,44 @@ impl Line {
== after
})
{
self.stations
// replace edge with the station and the two edges connecting it
self.edges
.remove(index);
self.stations
.insert(
index,
(
station.clone(),
Vec::new(),
Some(before_station.clone()),
),
);
self.stations
.insert(
index,
(
after_station.clone(),
Vec::new(),
Some(station),
),
);
self.edges
.push((
station.clone(),
Vec::new(),
Some(before_station.clone()),
));
self.edges
.push((
after_station.clone(),
Vec::new(),
Some(station),
));
return;
}
unreachable!("Station inserted on an edge, but can't find the edge.");
}

if let Some(index) = before.and_then(|a| {
self.stations
.iter()
.position(|s| &s.0 == a)
}) {
// found after and will insert station after after
self.stations
.insert(
index,
(station, Vec::new(), before.cloned()),
);
if after.is_some() {
// Insert edge between station and the station it comes before
self.edges
.push((station, Vec::new(), after.cloned()));
return;
} else if let Some(b) = before.cloned() {
// before exists but not found, so inserting it at the end
self.stations
.push((station, Vec::new(), Some(b.clone())));
self.stations
.push((b, Vec::new(), None));
}

if let Some(before_station) = before {
// Insert edge between station and the station it comes after
self.edges
.push((
before_station.clone(),
Vec::new(),
Some(station),
));
} else {
self.stations
// Insert as a lone station part of the line
self.edges
.push((station, Vec::new(), None));
}
}
Expand Down Expand Up @@ -190,7 +192,7 @@ impl Line {
pub fn get_station_neighbors(&self, station: &Station) -> (Vec<Station>, Vec<Station>) {
let (mut before, mut after) = (Vec::new(), Vec::new());

for edge in &self.stations {
for edge in &self.edges {
if &edge.0 == station {
if let Some(after_station) = edge
.2
Expand All @@ -215,7 +217,8 @@ impl Line {

/// Gets the stations on either side of the position on this line.
pub fn get_edge_stations(&self, node: GridNode) -> (Option<Station>, Option<Station>) {
for edge in &self.stations {
// First check if the node is on an edge between stations
for edge in &self.edges {
if edge
.1
.contains(&node)
Expand All @@ -231,37 +234,60 @@ impl Line {
}
}

// else it may be on a node around a station
for edge in &self.edges {
if edge
.0
.get_pos()
.get_neighbors()
.contains(&node)
{
return (
None,
Some(
edge.0
.clone(),
),
);
}

if let Some(after) = edge
.2
.clone()
{
if after
.get_pos()
.get_neighbors()
.contains(&node)
{
return (Some(after.clone()), None);
}
}
}

(None, None)
}

/// Returns true if the line goes through the given grid node.
pub fn visits_node(&self, node: GridNode) -> bool {
if self
.stations
.len()
> 1
{
self.stations
.iter()
.any(|(s, steps, _)| s.get_pos() == node || steps.contains(&node))
} else if let Some(s) = self
.stations
.first()
.edges
.iter()
.any(|(s, steps, _)| s.get_pos() == node || steps.contains(&node))
{
s.0.get_pos() == node
|| s.0
.get_pos()
.get_neighbors()
.contains(&node)
} else {
unreachable!("line can't have 0 stations")
return true;
}

return self
.get_line_ends()
.into_iter()
.any(|e| e.is_neighbor(node));
}

/// Recalculates the edges between the stations.
pub fn calculate_line_edges(&mut self) {
for (from, edges, to) in self
.stations
.edges
.iter_mut()
.filter(|(_, _, to)| to.is_some())
{
Expand All @@ -273,6 +299,45 @@ impl Line {
);
}
}

/// Gets the start and end stations of the line.
fn get_line_ends(&self) -> Vec<&Station> {
let mut ends = Vec::new();
let mut middles = Vec::new();

for edge in &self.edges {
if !middles.contains(&&edge.0) {
if let Some(i) = ends
.iter()
.position(|e| e == &&edge.0)
{
ends.remove(i);
middles.push(&edge.0);
} else {
ends.push(&edge.0);
}
}

if let Some(to) = edge
.2
.as_ref()
{
if !middles.contains(&to) {
if let Some(i) = ends
.iter()
.position(|e| e == &to)
{
ends.remove(i);
middles.push(to);
} else {
ends.push(to);
}
}
}
}

ends
}
}

impl Drawable for Line {
Expand All @@ -299,7 +364,7 @@ impl Drawable for Line {
// Draw a line between each two sequential stations on the line.
Ordering::Greater => {
for (start_station, steps, end_station) in self
.stations
.edges
.iter()
.filter(|(_, _, to)| to.is_some())
{
Expand Down
7 changes: 7 additions & 0 deletions src/models/station.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ impl Station {
&self.name
}

/// If the given node is a neighboring grid node to the station.
pub fn is_neighbor(&self, node: GridNode) -> bool {
self.get_pos()
.get_neighbors()
.contains(&node)
}

/// Clone the [`Station`] without keeping a reference to the coordinate
/// position.
pub fn clone_non_ref(&self) -> Self {
Expand Down

0 comments on commit 6b595c1

Please sign in to comment.