Skip to content

Commit

Permalink
fix: bugs in drawing edges, file modal error state and line section h…
Browse files Browse the repository at this point in the history
…andling
  • Loading branch information
CalliEve committed Dec 27, 2024
1 parent 36f7c9f commit f87c657
Show file tree
Hide file tree
Showing 15 changed files with 179 additions and 149 deletions.
14 changes: 14 additions & 0 deletions src/algorithm/drawing/draw_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,24 @@ pub fn draw_edge(
state: CanvasState,
height_offset: f64,
) {
let mut steps = steps;
let from_pos = from.to_canvas_pos(state);
let to_pos = to.to_canvas_pos(state);
let has_offset = height_offset.abs() > f64::EPSILON;

#[allow(unused_assignments)] // It is used to keep the borrow going
let mut steps_vec = Vec::new();
if let Some(start) = steps.first() {
if !from.is_neighbor_of(start) {
steps_vec = steps
.iter()
.rev()
.copied()
.collect::<Vec<GridNode>>();
steps = steps_vec.as_ref();
}
}

// The position of the start node on the canvas, based on the direction it is
// leaving the station from
let (from_x, from_y) = calc_closest_corner(
Expand Down
3 changes: 1 addition & 2 deletions src/algorithm/local_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,7 @@ pub async fn local_search(
if station.get_pos() != station.get_original_pos()
&& !station
.get_pos()
.get_neighbors()
.contains(&station.get_original_pos())
.is_neighbor_of(&station.get_original_pos())
{
neighborhood.insert(0, station.get_original_pos());
}
Expand Down
134 changes: 87 additions & 47 deletions src/algorithm/station_contraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use crate::{
},
utils::{
line_sections::{
get_line_section_parts,
trace_line_section,
LineSection,
},
Result,
},
Expand All @@ -28,42 +28,39 @@ use crate::{

/// Resolves a cycle of two stations in a line section by taking out the
/// starting edge from the line section.
fn resolve_two_station_cycle(
mut line_section: Vec<Edge>,
mut start: StationID,
mut middles: Vec<StationID>,
) -> (Vec<Edge>, StationID, Vec<StationID>) {
for edge in &line_section.clone() {
if edge.get_from() == start {
line_section.retain(|e| e != edge);
start = edge.get_to();
fn resolve_two_station_cycle(mut line_section: LineSection) -> LineSection {
for edge in &line_section
.edges
.clone()
{
if edge.get_from() == line_section.ends[0] {
line_section
.edges
.retain(|e| e != edge);
line_section.ends[0] = edge.get_to();
break;
} else if edge.get_to() == start {
line_section.retain(|e| e != edge);
start = edge.get_from();
} else if edge.get_to() == line_section.ends[0] {
line_section
.edges
.retain(|e| e != edge);
line_section.ends[0] = edge.get_from();
break;
}
}

middles.retain(|id| *id != start);
(line_section, start, middles)
line_section
.middles
.retain(|id| *id != line_section.ends[0]);
line_section
}

/// Resolves a line section that is a cycle by taking the station with the most
/// edges connected out of the cycle together with the edges it is connected
/// to.
fn resolve_cycle(
map: &Map,
mut line_section: Vec<Edge>,
mut middles: Vec<StationID>,
) -> (
Vec<Edge>,
Vec<StationID>,
Vec<StationID>,
) {
fn resolve_cycle(map: &Map, mut line_section: LineSection) -> LineSection {
// Find the station with the most edges connected to it.
let mut biggest_station = (middles[0], 0);
for edge in &line_section {
let mut biggest_station = (line_section.middles[0], 0);
for edge in &line_section.edges {
let start = edge.get_from();
let end = edge.get_to();
let start_station = map
Expand Down Expand Up @@ -103,20 +100,34 @@ fn resolve_cycle(
// Take out the biggest station and the edges it is connected to, this will
// ensure the cycle will now have at least 3 stations in it after contraction.
let mut ends = Vec::new();
middles.retain(|id| *id != biggest_station.0);
for edge in &line_section.clone() {
line_section
.middles
.retain(|id| *id != biggest_station.0);
for edge in &line_section
.edges
.clone()
{
if edge.get_from() == biggest_station.0 {
line_section.retain(|e| e != edge);
line_section
.edges
.retain(|e| e != edge);
ends.push(edge.get_to());
middles.retain(|id| *id != edge.get_to());
line_section
.middles
.retain(|id| *id != edge.get_to());
} else if edge.get_to() == biggest_station.0 {
line_section.retain(|e| e != edge);
line_section
.edges
.retain(|e| e != edge);
ends.insert(0, edge.get_from());
middles.retain(|id| *id != edge.get_from());
line_section
.middles
.retain(|id| *id != edge.get_from());
}
}
line_section.ends = ends;

(line_section, ends, middles)
line_section
}

/// Check if the station can be contracted into an edge between its neighboring
Expand Down Expand Up @@ -164,35 +175,59 @@ pub fn contract_stations(

while let Some(edge) = unchecked_edges.next() {
let mut line_section = trace_line_section(map, edge.get_id(), true);
let (mut ends, mut middles) = get_line_section_parts(&line_section);
if ends.is_empty() {
if middles.len() <= 3 {

if line_section
.ends
.first()
== line_section
.ends
.last()
{
if line_section
.middles
.len()
<= 3
{
// Just skip, we need at least 4 stations to contract part of a cycle.
continue;
}
logging::log!("Line section has no ends, resolving cycle");
(line_section, ends, middles) = resolve_cycle(map, line_section, middles);
} else if ends.len() != 2 {
line_section = resolve_cycle(map, line_section);
} else if line_section
.ends
.len()
!= 2
{
panic!(
"Line section does not have two ends, but instead {}",
ends.len()
line_section
.ends
.len()
);
}

let mut start = ends[0];
let end = ends[1];
let mut start = line_section.ends[0];
let end = line_section.ends[1];
if map
.get_edge_id_between_if_exists(start, end)
.is_some()
{
// Edge already exists, so we have to resolve the two station cycle this would
// form.
(line_section, start, middles) =
resolve_two_station_cycle(line_section, start, middles);
line_section = resolve_two_station_cycle(line_section);
start = line_section.ends[0];
}

// Check for other edge cases preventing contraction.
if !can_contract_into(settings, map, start, end, middles.len()) {
if !can_contract_into(
settings,
map,
start,
end,
line_section
.middles
.len(),
) {
continue;
}

Expand All @@ -203,9 +238,10 @@ pub fn contract_stations(
.get_mut_edge(new_edge_id)
.unwrap();

new_edge.extend_contracted_stations(&middles);
new_edge.extend_contracted_stations(&line_section.middles);

let middle_stations = middles
let middle_stations = line_section
.middles
.iter()
.map(|id| {
map.get_station(*id)
Expand All @@ -222,7 +258,11 @@ pub fn contract_stations(
// Remove the edges that we contracted from our list of unchecked edges, as we
// checked them by contracting them.
unchecked_edges = unchecked_edges
.filter(|e| !line_section.contains(e))
.filter(|e| {
!line_section
.edges
.contains(e)
})
.collect::<Vec<_>>()
.into_iter();
}
Expand Down
11 changes: 4 additions & 7 deletions src/components/canvas/dbl_click.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ use crate::{
GridNode,
SelectedStation,
},
utils::line_sections::{
get_line_section_parts,
trace_line_section,
},
utils::line_sections::trace_line_section,
MapState,
};

Expand All @@ -33,10 +30,9 @@ pub fn on_dbl_click(map_state: &mut MapState, ev: &UiEvent, shift_key: bool) {
if let Some(edge_id) = map.edge_at_node(mouse_pos) {
let line_section = trace_line_section(map, edge_id, false);

let (_, middles) = get_line_section_parts(&line_section);

map_state.set_selected_stations(
middles
line_section
.middles
.into_iter()
.map(|s| {
let mut selected = SelectedStation::new(
Expand Down Expand Up @@ -76,6 +72,7 @@ pub fn on_dbl_click(map_state: &mut MapState, ev: &UiEvent, shift_key: bool) {

map_state.set_selected_edges(
line_section
.edges
.into_iter()
.map(|e| e.get_id())
.chain(
Expand Down
6 changes: 0 additions & 6 deletions src/components/canvas/keydown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ pub fn on_keydown(map_state_signal: &RwSignal<MapState>, ev: &KeyboardEvent) {
});
}

leptos::logging::log!(
"Key pressed: {}, ctrl: {}",
ev.key(),
ev.ctrl_key()
);

if ev.key() == "z" && ev.ctrl_key() {
map_state_signal.update(|map_state| {
if let Some(map) = HistoryState::undo(
Expand Down
10 changes: 5 additions & 5 deletions src/components/molecules/file_modal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,10 @@ impl FileType {

/// Gets the file uploaded to the input element by the user and passes its
/// contents to the provided `on_submit` callback function.
fn get_file<S>(input: &HtmlInputElement, on_submit: S)
fn get_file<S>(input: &HtmlInputElement, on_submit: S, error_state: RwSignal<ErrorState>)
where
S: Fn(FileType, String) + 'static,
{
let error_state =
use_context::<RwSignal<ErrorState>>().expect("to have found the global error state");

let Some(file) = input
.files()
.and_then(|l| l.item(0))
Expand Down Expand Up @@ -105,6 +102,9 @@ where
S: Fn(FileType, String) + Send + 'static + Copy,
C: Fn() + 'static,
{
let error_state =
use_context::<RwSignal<ErrorState>>().expect("to have found the global error state");

let input_ref: NodeRef<Input> = NodeRef::new();

view! {
Expand All @@ -125,7 +125,7 @@ where
</div>
// footer
<div class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600">
<Button text="Upload File" on_click=Box::new(move |_| get_file(&input_ref.get().unwrap(), on_submit))/>
<Button text="Upload File" on_click=Box::new(move |_| get_file(&input_ref.get().unwrap(), on_submit, error_state))/>
</div>
</Modal>
}
Expand Down
Loading

0 comments on commit f87c657

Please sign in to comment.