From 9839fc12130eabefa2e8c0e3b74064cc0ed73ffb Mon Sep 17 00:00:00 2001 From: Logan King Date: Wed, 22 Jun 2022 00:04:42 -0400 Subject: [PATCH 1/8] render paths and intersections --- .gitignore | 4 +- Cargo.toml | 4 +- src/main.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index b19a093..8056e7c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,6 @@ input/ *.png -.vscode/ \ No newline at end of file +.vscode/ + +*.json \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 7ef79cf..416e43f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,6 @@ edition = "2021" [dependencies] macroquad = "0.3" glob = "0.3.0" -futures = "0.3.21" \ No newline at end of file +futures = "0.3.21" +serde = { version = "1.0.104", features = ["derive"] } +serde_json = "1.0.48" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index ab8dcc5..70b20e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use glob::{glob, GlobError}; use std::{ collections::HashMap, path::PathBuf, - sync::{Arc, Mutex}, + sync::{Arc, Mutex}, fs::File, io::Read, }; use macroquad::prelude::*; @@ -51,7 +51,7 @@ fn get_files_in_dir(path: &str, filetype: &str) -> Result, GlobErro } -const TILE_DIR: &str = "./tile_images/moon/"; +const TILE_DIR: &str = "./tile_images/terrain/"; async fn get_textures_for_zoom_level( level: u32, @@ -185,6 +185,102 @@ async fn cache_texture( drop(retrieving_tile_map); } +fn pathtype_to_color(pathtype: &str) -> Color{ + match pathtype { + "iceroad" => BLUE, + "roofless iceroad" => SKYBLUE, + "rail" => GRAY, + "normal" => GREEN, + _ => GREEN, + } +} + +fn point_on_screen(point: (f32,f32)) -> bool { + !(point.0 < 0. || point.0 > screen_width() - 0. || point.1 < 0. || point.1 > screen_height() - 0.) +} + +fn get_path_lines(path_data: &serde_json::Value) -> (Vec, Vec){ + + let mut path_lines = Vec::new(); + let mut intersections = Vec::new(); + + let nodes = path_data.as_object().unwrap(); + let mut already_rendered: HashMap = HashMap::new(); + + // for every existing + for (node, node_value) in nodes{ + // println!("node: {}",node); + if let Some(neighbors) = node_value["connections"].as_object(){ + for (neighbor, _) in neighbors { + + // if line not already rendered + if already_rendered.get(&(neighbor.to_owned() + node)) == None{ + + // mark line as rendered + already_rendered.insert(node.to_owned() + neighbor, true); + + let node_pathtype = nodes[node]["pathType"].as_str().unwrap(); + let neighbor_pathtype = nodes[neighbor]["pathType"].as_str().unwrap(); + + let path_type = if node_pathtype == neighbor_pathtype{ + node_pathtype + } else{ + "normal" + }; + + path_lines.push(PathLine{ + point1: (nodes[node]["x"].as_f64().unwrap() as f32, nodes[node]["z"].as_f64().unwrap() as f32), + point2: (nodes[neighbor]["x"].as_f64().unwrap() as f32, nodes[neighbor]["z"].as_f64().unwrap() as f32), + color: pathtype_to_color(path_type), + }); + } + } + if neighbors.len() > 2{ + + + intersections.push(Intersection{ + point: (nodes[node]["x"].as_f64().unwrap() as f32, nodes[node]["z"].as_f64().unwrap() as f32), + color: pathtype_to_color(nodes[node]["pathType"].as_str().unwrap()), + }); + } + } + } + + (path_lines, intersections) +} + +fn render_lines(path_lines: &[PathLine], camera: &CameraSettings){ + for line in path_lines{ + let coords1 = coord_to_screen_pos(line.point1.0 + 0.5, line.point1.1 + 0.5, &camera); + let coords2 = coord_to_screen_pos(line.point2.0 + 0.5, line.point2.1 + 0.5, &camera); + + if point_on_screen(coords1) || point_on_screen(coords2){ + draw_line(coords1.0, coords1.1, coords2.0, coords2.1, 5.0, line.color); + } + + } +} + +fn render_intersections(intersections: &[Intersection], camera: &CameraSettings){ + for intersection in intersections{ + let intersection_coords = coord_to_screen_pos(intersection.point.0 + 0.5, intersection.point.1 + 0.5, &camera); + if point_on_screen(intersection_coords){ + draw_circle(intersection_coords.0, intersection_coords.1, 8.0, intersection.color); + } + } +} + +struct PathLine { + point1: (f32,f32), + point2: (f32,f32), + color: Color, +} + +struct Intersection{ + point: (f32,f32), + color: Color, +} + struct CameraSettings { x_offset: f32, y_offset: f32, @@ -243,6 +339,14 @@ async fn main() { let mut pool = LocalPool::new(); let spawner = pool.spawner(); + // retrieve paths from json + let mut file = File::open("./paths/nodes.json").expect("Failed to open file"); + let mut contents = String::new(); + file.read_to_string(&mut contents).expect("Failed to read to string"); + let path_data: serde_json::Value = serde_json::from_str(&contents).expect("JSON was not well-formatted"); + + let (path_lines, intersections) = get_path_lines(&path_data); + loop { clear_background(GRAY); @@ -522,6 +626,9 @@ async fn main() { // } //< + render_lines(&path_lines, &camera); + render_intersections(&intersections, &camera); + draw_text( &("fps: ".to_owned() + &get_fps().to_string()), 20.0, From cb81c2e917221ab2409739898b0a215364d59bc0 Mon Sep 17 00:00:00 2001 From: Logan King Date: Wed, 22 Jun 2022 00:47:23 -0400 Subject: [PATCH 2/8] better types --- src/main.rs | 175 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 134 insertions(+), 41 deletions(-) diff --git a/src/main.rs b/src/main.rs index 70b20e9..3951c48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,24 +81,30 @@ async fn get_textures_for_zoom_level( sector_to_texture } -fn coord_to_screen_pos(x: f32, y: f32, camera: &CameraSettings) -> (f32, f32) { +fn coord_to_screen_pos(x: f32, y: f32, camera: &CameraSettings) -> Point { let out_x = screen_width() / 2. + ((camera.x_offset + x) * camera.zoom_multiplier); let out_y = screen_height() / 2. + ((camera.y_offset + y) * camera.zoom_multiplier); - (out_x, out_y) + Point{ + x: out_x, + y: out_y + } } -fn screen_pos_to_coord(x: f32, y: f32, camera: &CameraSettings) -> (f32, f32) { +fn screen_pos_to_coord(x: f32, y: f32, camera: &CameraSettings) -> Point { let x_out = -camera.x_offset + (x as f32 - screen_width() / 2.) / camera.zoom_multiplier; let y_out = -camera.y_offset + (y as f32 - screen_height() / 2.) / camera.zoom_multiplier; - (x_out, y_out) + Point{ + x: x_out, + y: y_out, + } } -// struct Rectangle { -// x: f32, -// y: f32, -// width: f32, -// height: f32, -// } +struct Rectangle { + x: f32, + y: f32, + width: f32, + height: f32, +} // fn value_in_range(value: f32, min: f32, max: f32) -> bool { // (value >= min) && (value <= max) @@ -133,18 +139,18 @@ fn sector_at_screen_pos( // get sector x let tile_world_x_size = tile_dimensions.0 as f32 * two.powf(lod as f32); - let screen_point_sector_x = if screen_point_coords.0 < 0.0 { - (screen_point_coords.0 / tile_world_x_size) as i32 - 1 + let screen_point_sector_x = if screen_point_coords.x < 0. { + (screen_point_coords.x / tile_world_x_size) as i32 - 1 } else { - (screen_point_coords.0 / tile_world_x_size) as i32 + (screen_point_coords.x / tile_world_x_size) as i32 }; // get sector y let tile_world_y_size = tile_dimensions.1 as f32 * two.powf(lod as f32); - let screen_point_sector_y = if screen_point_coords.1 < 0.0 { - (screen_point_coords.1 / tile_world_y_size) as i32 - 1 + let screen_point_sector_y = if screen_point_coords.y < 0.0 { + (screen_point_coords.y / tile_world_y_size) as i32 - 1 } else { - (screen_point_coords.1 / tile_world_y_size) as i32 + (screen_point_coords.y / tile_world_y_size) as i32 }; (screen_point_sector_x, screen_point_sector_y) @@ -195,8 +201,8 @@ fn pathtype_to_color(pathtype: &str) -> Color{ } } -fn point_on_screen(point: (f32,f32)) -> bool { - !(point.0 < 0. || point.0 > screen_width() - 0. || point.1 < 0. || point.1 > screen_height() - 0.) +fn point_on_screen(point: &Point) -> bool { + !(point.x < 0. || point.x > screen_width() - 0. || point.y < 0. || point.y > screen_height() - 0.) } fn get_path_lines(path_data: &serde_json::Value) -> (Vec, Vec){ @@ -229,8 +235,8 @@ fn get_path_lines(path_data: &serde_json::Value) -> (Vec, Vec (Vec, Vec (Vec, Vec bool { + // let uA: f32 = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); + // let uB: f32 = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); + + let u_a: f32 = ((line1.point2.x-line2.point1.x)*(line1.point1.y-line2.point1.y) - (line1.point2.y-line2.point1.y)*(line1.point1.x-line2.point1.x)) / ((line1.point2.y-line2.point1.y)*(line1.point2.x-line1.point1.x) - (line1.point2.x-line2.point1.x)*(line1.point2.y-line1.point1.y)); + let u_b: f32 = ((line1.point2.x-line1.point1.x)*(line1.point1.y-line2.point1.y) - (line1.point2.y-line1.point1.y)*(line1.point1.x-line2.point1.x)) / ((line1.point2.y-line2.point1.y)*(line1.point2.x-line1.point1.x) - (line1.point2.x-line2.point1.x)*(line1.point2.y-line1.point1.y)); + + u_a >= 0.0 && u_a <= 1.0 && u_b >= 0.0 && u_b <= 1.0 +} + +fn line_intersects_rectangle(line: &Line, rectangle: &Rectangle) -> bool { + let top_line = Line{ + point1: Point{ + x: rectangle.x, + y: rectangle.y, + }, + point2: Point{ + x: rectangle.x + rectangle.width, + y: rectangle.y, + }, + }; + + let left_line = Line{ + point1: Point{ + x: rectangle.x, + y: rectangle.y, + }, + point2: Point{ + x: rectangle.x, + y: rectangle.y + rectangle.height, + }, + }; + + let bottom_line = Line{ + point1: Point{ + x: rectangle.x, + y: rectangle.y + rectangle.height, + }, + point2: Point{ + x: rectangle.x + rectangle.width, + y: rectangle.y + rectangle.height, + }, + }; + + let right_line = Line{ + point1: Point{ + x: rectangle.x + rectangle.width, + y: rectangle.y, + }, + point2: Point{ + x: rectangle.x + rectangle.width, + y: rectangle.y + rectangle.height, + }, + }; + + let left = lines_intersect(&left_line, line); + let right = lines_intersect(&right_line, line); + let bottom = lines_intersect(&bottom_line, line); + let top = lines_intersect(&top_line, line); + + left || right || bottom || top +} + +struct Point{ + x: f32, + y: f32, +} + +struct Line { + point1: Point, + point2: Point, +} + struct PathLine { - point1: (f32,f32), - point2: (f32,f32), + point1: Point, + point2: Point, color: Color, } struct Intersection{ - point: (f32,f32), + point: Point, color: Color, } @@ -410,8 +503,8 @@ async fn main() { camera.zoom_multiplier = camera.zoom_multiplier.clamp(min_zoom, 20.); // center camera on where mouse was in world - camera.x_offset = -mouse_world_pos.0; - camera.y_offset = -mouse_world_pos.1; + camera.x_offset = -mouse_world_pos.x; + camera.y_offset = -mouse_world_pos.y; let screen_x_to_change = mouse_screen_pos.0 - screen_width() / 2.; let screen_y_to_change = mouse_screen_pos.1 - screen_height() / 2.; @@ -432,8 +525,8 @@ async fn main() { camera.zoom_multiplier = camera.zoom_multiplier.clamp(min_zoom, 20.); // center camera on where mouse was in world - camera.x_offset = -mouse_world_pos.0; - camera.y_offset = -mouse_world_pos.1; + camera.x_offset = -mouse_world_pos.x; + camera.y_offset = -mouse_world_pos.y; let screen_x_to_change = mouse_screen_pos.0 - screen_width() / 2.; let screen_y_to_change = mouse_screen_pos.1 - screen_height() / 2.; @@ -509,8 +602,8 @@ async fn main() { let mut rendered_tiles = 0; // for all sectors to render - for sector_y in top_left_sector.1..=bottom_right_sector.1 { - for sector_x in top_left_sector.0..=bottom_right_sector.0 { + for sector_y in top_left_sector.1+1..=bottom_right_sector.1-1 { + for sector_x in top_left_sector.0+1..=bottom_right_sector.0-1 { // determine texture let texture_option = { let arc_mutex_hdd_texture_cache2 = arc_mutex_hdd_texture_cache.clone(); @@ -555,7 +648,7 @@ async fn main() { let tile_world_x = tile_world_width * sector_x as f32; let tile_world_y = tile_world_height * sector_y as f32; - let (tile_screen_x, tile_screen_y) = + let tile_screen_point = coord_to_screen_pos(tile_world_x, tile_world_y, &camera); let params = DrawTextureParams { @@ -567,7 +660,7 @@ async fn main() { pivot: None, }; - draw_texture_ex(texture, tile_screen_x, tile_screen_y, WHITE, params); + draw_texture_ex(texture, tile_screen_point.x, tile_screen_point.y, WHITE, params); rendered_tiles += 1; } } @@ -664,7 +757,7 @@ async fn main() { let mouse = mouse_position(); let mouse_coord = screen_pos_to_coord(mouse.0, mouse.1, &camera); draw_text( - &("mouse.x: ".to_owned() + &mouse_coord.0.to_string()), + &("mouse.x: ".to_owned() + &mouse_coord.x.to_string()), 20.0, 100.0, 30.0, @@ -672,7 +765,7 @@ async fn main() { ); draw_text( - &("mouse.y: ".to_owned() + &mouse_coord.1.to_string()), + &("mouse.y: ".to_owned() + &mouse_coord.y.to_string()), 20.0, 120.0, 30.0, From 6e4815c6874433d198eaf7cde764dea33afb3ae1 Mon Sep 17 00:00:00 2001 From: Logan King Date: Wed, 22 Jun 2022 03:59:26 -0400 Subject: [PATCH 3/8] fix lines_intersect --- src/main.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3951c48..2aea172 100644 --- a/src/main.rs +++ b/src/main.rs @@ -266,15 +266,13 @@ fn render_lines(path_lines: &[PathLine], camera: &CameraSettings){ }; let screen_rectangle = Rectangle{ - x: 100., - y: 100., - width: screen_width() - 200., - height: screen_height() - 200., + x: 0., + y: 0., + width: screen_width() - 0., + height: screen_height() - 0., }; - // || line_intersects_rectangle(&line_line, &screen_rectangle) - - if point_on_screen(&coords1) || point_on_screen(&coords2) { + if point_on_screen(&coords1) || point_on_screen(&coords2) || line_intersects_rectangle(&line_line, &screen_rectangle) { draw_line(coords1.x, coords1.y, coords2.x, coords2.y, 5.0, line.color); } @@ -291,11 +289,19 @@ fn render_intersections(intersections: &[Intersection], camera: &CameraSettings) } fn lines_intersect(line1: &Line, line2: &Line) -> bool { - // let uA: f32 = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); - // let uB: f32 = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); - let u_a: f32 = ((line1.point2.x-line2.point1.x)*(line1.point1.y-line2.point1.y) - (line1.point2.y-line2.point1.y)*(line1.point1.x-line2.point1.x)) / ((line1.point2.y-line2.point1.y)*(line1.point2.x-line1.point1.x) - (line1.point2.x-line2.point1.x)*(line1.point2.y-line1.point1.y)); - let u_b: f32 = ((line1.point2.x-line1.point1.x)*(line1.point1.y-line2.point1.y) - (line1.point2.y-line1.point1.y)*(line1.point1.x-line2.point1.x)) / ((line1.point2.y-line2.point1.y)*(line1.point2.x-line1.point1.x) - (line1.point2.x-line2.point1.x)*(line1.point2.y-line1.point1.y)); + let x1 = line1.point1.x; + let x2 = line1.point2.x; + let x3 = line2.point1.x; + let x4 = line2.point2.x; + + let y1 = line1.point1.y; + let y2 = line1.point2.y; + let y3 = line2.point1.y; + let y4 = line2.point2.y; + + let u_a: f32 = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); + let u_b: f32 = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); u_a >= 0.0 && u_a <= 1.0 && u_b >= 0.0 && u_b <= 1.0 } @@ -602,8 +608,8 @@ async fn main() { let mut rendered_tiles = 0; // for all sectors to render - for sector_y in top_left_sector.1+1..=bottom_right_sector.1-1 { - for sector_x in top_left_sector.0+1..=bottom_right_sector.0-1 { + for sector_y in top_left_sector.1..=bottom_right_sector.1 { + for sector_x in top_left_sector.0..=bottom_right_sector.0 { // determine texture let texture_option = { let arc_mutex_hdd_texture_cache2 = arc_mutex_hdd_texture_cache.clone(); From 13b01253e0b309ea74e967ae1c6791e58ac4919e Mon Sep 17 00:00:00 2001 From: Logan King Date: Wed, 22 Jun 2022 04:07:27 -0400 Subject: [PATCH 4/8] distance_between_points() --- src/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.rs b/src/main.rs index 2aea172..0ee3b71 100644 --- a/src/main.rs +++ b/src/main.rs @@ -359,6 +359,10 @@ fn line_intersects_rectangle(line: &Line, rectangle: &Rectangle) -> bool { left || right || bottom || top } +fn distance_between_points(point1: Point, point2: Point) -> f32 { + ((point1.x - point2.x).abs().powf(2.) + (point1.y - point2.y).abs().powf(2.)).sqrt() +} + struct Point{ x: f32, y: f32, From 4fdcd3827ea40dc36dd89ec0fff5c39ae4f2c790 Mon Sep 17 00:00:00 2001 From: Logan King Date: Wed, 22 Jun 2022 04:23:46 -0400 Subject: [PATCH 5/8] point_on_line() --- src/main.rs | 67 +++++++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0ee3b71..9b29d0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,34 +53,6 @@ fn get_files_in_dir(path: &str, filetype: &str) -> Result, GlobErro const TILE_DIR: &str = "./tile_images/terrain/"; -async fn get_textures_for_zoom_level( - level: u32, - directory: &str, - tile_dimensions: (f32, f32), -) -> HashMap<(i32, i32), Texture2D> { - let files = get_files_in_dir(&(directory.to_owned() + &level.to_string()), "").unwrap(); - - let mut sector_to_texture = HashMap::new(); - - for file in files { - // get sector from filename - let file_name = file.file_stem().unwrap().to_str().unwrap(); - let split: Vec<&str> = file_name.split(',').collect(); - let x: i32 = split[0].parse().unwrap(); - let z: i32 = split[1].parse().unwrap(); - - // map sector to texture - let texture: Texture2D = load_texture(file.to_str().unwrap()).await.unwrap(); - texture.set_filter(FilterMode::Nearest); - if texture.width() != tile_dimensions.0 || texture.height() != tile_dimensions.1 { - panic!("File: \"{}\" has differing dimensions", file_name) - } - sector_to_texture.insert((x, z), texture); - } - - sector_to_texture -} - fn coord_to_screen_pos(x: f32, y: f32, camera: &CameraSettings) -> Point { let out_x = screen_width() / 2. + ((camera.x_offset + x) * camera.zoom_multiplier); let out_y = screen_height() / 2. + ((camera.y_offset + y) * camera.zoom_multiplier); @@ -234,9 +206,13 @@ fn get_path_lines(path_data: &serde_json::Value) -> (Vec, Vec (Vec, Vec bool { left || right || bottom || top } -fn distance_between_points(point1: Point, point2: Point) -> f32 { +fn distance_between_points(point1: &Point, point2: &Point) -> f32 { ((point1.x - point2.x).abs().powf(2.) + (point1.y - point2.y).abs().powf(2.)).sqrt() } +fn point_on_line(point: &Point, line: &Line, buffer: f32) -> bool { + let line_len = distance_between_points(&line.point1, &line.point2); + + let d1: f32 = distance_between_points(&point, &line.point1); + let d2: f32 = distance_between_points(&point, &line.point2); + + d1+d2 >= line_len-buffer && d1+d2 <= line_len+buffer +} + struct Point{ x: f32, y: f32, @@ -374,8 +367,7 @@ struct Line { } struct PathLine { - point1: Point, - point2: Point, + line: Line, color: Color, } @@ -436,7 +428,6 @@ async fn main() { Arc::new(Mutex::new(HashMap::new())); use futures::executor::LocalPool; - use futures::future::{pending, ready}; use futures::task::LocalSpawnExt; let mut pool = LocalPool::new(); From 1eab90f2d1399cdb239d44c488014f0cd625c5cc Mon Sep 17 00:00:00 2001 From: Logan King Date: Wed, 22 Jun 2022 05:07:38 -0400 Subject: [PATCH 6/8] closest_point_on_line_strict() --- src/main.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 9b29d0a..791b26f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -173,10 +173,12 @@ fn pathtype_to_color(pathtype: &str) -> Color{ } } +/// Determins if screen point is currently on the screen fn point_on_screen(point: &Point) -> bool { !(point.x < 0. || point.x > screen_width() - 0. || point.y < 0. || point.y > screen_height() - 0.) } +/// Extracts lines from json path data for easier rendering fn get_path_lines(path_data: &serde_json::Value) -> (Vec, Vec){ let mut path_lines = Vec::new(); @@ -250,7 +252,13 @@ fn render_lines(path_lines: &[PathLine], camera: &CameraSettings){ let mouse = mouse_position(); let mouse_coord = screen_pos_to_coord(mouse.0, mouse.1, &camera); - let color = if point_on_line(&Point{x: mouse_coord.x, y: mouse_coord.y}, &path_line.line, 0.2){ + let color = if point_on_line(&Point{x: mouse_coord.x, y: mouse_coord.y}, &path_line.line, 10.){ + + if let Some(closest_point) = closest_point_on_line_strict(&Point{x: mouse_coord.x, y: mouse_coord.y}, &path_line.line){ + let intersection_coords = coord_to_screen_pos(closest_point.x + 0.5, closest_point.y + 0.5, &camera); + draw_circle(intersection_coords.x, intersection_coords.y, 10.0, RED); + } + RED } else { path_line.color @@ -272,6 +280,7 @@ fn render_intersections(intersections: &[Intersection], camera: &CameraSettings) } } +/// Returns true when two line segments intersect eachother fn lines_intersect(line1: &Line, line2: &Line) -> bool { let x1 = line1.point1.x; @@ -290,6 +299,7 @@ fn lines_intersect(line1: &Line, line2: &Line) -> bool { u_a >= 0.0 && u_a <= 1.0 && u_b >= 0.0 && u_b <= 1.0 } +/// Tells if a line segment intersects a rectangle. Does not return true if line is inside rectangle but not intersecting it's sides. fn line_intersects_rectangle(line: &Line, rectangle: &Rectangle) -> bool { let top_line = Line{ point1: Point{ @@ -343,10 +353,12 @@ fn line_intersects_rectangle(line: &Line, rectangle: &Rectangle) -> bool { left || right || bottom || top } +/// Determins distance between two 2d points fn distance_between_points(point1: &Point, point2: &Point) -> f32 { ((point1.x - point2.x).abs().powf(2.) + (point1.y - point2.y).abs().powf(2.)).sqrt() } +/// Determins if point is on line. Increase `buffer` will increase the distance considered a detection. fn point_on_line(point: &Point, line: &Line, buffer: f32) -> bool { let line_len = distance_between_points(&line.point1, &line.point2); @@ -356,11 +368,30 @@ fn point_on_line(point: &Point, line: &Line, buffer: f32) -> bool { d1+d2 >= line_len-buffer && d1+d2 <= line_len+buffer } + +/// returns closest point on line semgent, if the closest point, were the line infinite and not a segment, is on the line segment. +fn closest_point_on_line_strict(point: &Point, line: &Line) -> Option { + let line_len = distance_between_points(&line.point1, &line.point2); + + let dot: f32 = ( ((point.x-line.point1.x)*(line.point2.x-line.point1.x)) + ((point.y-line.point1.y)*(line.point2.y-line.point1.y)) ) / line_len.powf(2.); + + let closest_x: f32 = line.point1.x + (dot * (line.point2.x-line.point1.x)); + let closest_y: f32 = line.point1.y + (dot * (line.point2.y-line.point1.y)); + + if point_on_line(&Point{x: closest_x, y: closest_y}, line, 0.1){ + Some(Point{x: closest_x, y: closest_y}) + } else { + None + } +} + +// A 2d point struct Point{ x: f32, y: f32, } +// A 2d line segment struct Line { point1: Point, point2: Point, From 900b96297f4f4b8091e493a7d0e7e77653c526b7 Mon Sep 17 00:00:00 2001 From: Logan King Date: Wed, 22 Jun 2022 22:00:02 -0400 Subject: [PATCH 7/8] closest_point_on_line() --- src/main.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 791b26f..2704825 100644 --- a/src/main.rs +++ b/src/main.rs @@ -234,6 +234,8 @@ fn get_path_lines(path_data: &serde_json::Value) -> (Vec, Vec Option { } } +/// returns closest point on line semgent. +fn closest_point_on_line(point: &Point, line: &Line) -> Point { + let line_len = distance_between_points(&line.point1, &line.point2); + + let dot: f32 = ( ((point.x-line.point1.x)*(line.point2.x-line.point1.x)) + ((point.y-line.point1.y)*(line.point2.y-line.point1.y)) ) / line_len.powf(2.); + + let closest_x: f32 = line.point1.x + (dot * (line.point2.x-line.point1.x)); + let closest_y: f32 = line.point1.y + (dot * (line.point2.y-line.point1.y)); + + if point_on_line(&Point{x: closest_x, y: closest_y}, line, 0.1){ + Point{x: closest_x, y: closest_y} + } else { + if distance_between_points(point, &line.point1) < distance_between_points(point, &line.point2){ + line.point1.clone() + } else { + line.point2.clone() + } + } +} + + +#[derive(Clone)] // A 2d point struct Point{ x: f32, From f5c297274be69388722d1b4a96fa9a2a5e976bb3 Mon Sep 17 00:00:00 2001 From: Logan King Date: Sat, 1 Oct 2022 19:57:12 -0400 Subject: [PATCH 8/8] ignore images --- .gitignore | 4 +++- src/main.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8056e7c..4f94bb3 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ input/ .vscode/ -*.json \ No newline at end of file +*.json + +tile_images/ \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2704825..f0005e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,7 @@ fn get_files_in_dir(path: &str, filetype: &str) -> Result, GlobErro } -const TILE_DIR: &str = "./tile_images/terrain/"; +const TILE_DIR: &str = "./tile_images/world1/terrain/"; fn coord_to_screen_pos(x: f32, y: f32, camera: &CameraSettings) -> Point { let out_x = screen_width() / 2. + ((camera.x_offset + x) * camera.zoom_multiplier);