From d19c63e531f70e968ff6126ed47c9d83797e70b3 Mon Sep 17 00:00:00 2001 From: skybldev Date: Fri, 30 Aug 2024 10:39:00 -0400 Subject: [PATCH] backup commit --- Cargo.lock | 129 ++----------- Cargo.toml | 2 +- src/main.rs | 521 ++++++++++++++++++++++++++++++++++----------------- src/types.rs | 41 +++- test2.gcode | 37 +--- 5 files changed, 410 insertions(+), 320 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61c93c0..cdea6ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,25 +101,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" -[[package]] -name = "codespan" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3362992a0d9f1dd7c3d0e89e0ab2bb540b7a95fea8cd798090e758fda2899b5e" -dependencies = [ - "codespan-reporting", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "diff" version = "0.1.13" @@ -144,19 +125,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "g-code" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6261d157241cc6ec7e015a19f2b8ea37e2018a32980a60d65bda6c7b336349fc" -dependencies = [ - "codespan", - "codespan-reporting", - "paste", - "peg", - "rust_decimal", -] - [[package]] name = "getrandom" version = "0.2.12" @@ -205,6 +173,16 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "kurbo" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1618d4ebd923e97d67e7cd363d80aef35fe961005cbbbb3d2dad8bdd1bc63440" +dependencies = [ + "arrayvec", + "smallvec", +] + [[package]] name = "libc" version = "0.2.152" @@ -268,44 +246,11 @@ dependencies = [ name = "osubot" version = "0.1.0" dependencies = [ - "g-code", + "kurbo", "osu-file-parser", "rust_decimal", ] -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "peg" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "400bcab7d219c38abf8bd7cc2054eb9bbbd4312d66f6a5557d572a203f646f61" -dependencies = [ - "peg-macros", - "peg-runtime", -] - -[[package]] -name = "peg-macros" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e61cce859b76d19090f62da50a9fe92bab7c2a5f09e183763559a2ac392c90" -dependencies = [ - "peg-runtime", - "proc-macro2", - "quote", -] - -[[package]] -name = "peg-runtime" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36bae92c60fa2398ce4678b98b2c4b5a7c61099961ca1fa305aec04a9ad28922" - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -547,6 +492,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + [[package]] name = "strum" version = "0.24.1" @@ -606,15 +557,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.56" @@ -673,12 +615,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - [[package]] name = "uuid" version = "1.7.0" @@ -697,37 +633,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "winnow" version = "0.5.34" diff --git a/Cargo.toml b/Cargo.toml index 87d8763..2a0c121 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,6 @@ edition = "2021" [dependencies] osu-file-parser = "1.1.0" -g-code = "0.3.6" #matrix = "0.22.0" rust_decimal = { version = "1.33.1", features = ["maths"] } +kurbo = "0.10.4" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index fd9850f..130e87b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,76 +1,18 @@ use osu_file_parser::{ - osu_file::{ - hitobjects::{ - CurveType::*, - HitObjectParams::* - } - }, - OsuFile + hitobjects::{HitObject, HitObjectParams::*, SlideParams, CurveType}, + osu_file::hitobjects, + Decimal as OsuDecimal, + OsuFile, + Position }; use rust_decimal::{Decimal, prelude::ToPrimitive}; +use kurbo::{BezPath, PathEl, Point, QuadSpline}; mod types; use types::*; -/* - The input file. -*/ -const OSU: &str = include_str!("../osu/test2/test2.osu"); - -/* - Machine's maximum acceleration in mm/s². -*/ -const MAX_ACCEL: f64 = 110_000.0; -/* - The default acceleration to use for max_v calculation. -*/ -const DEFAULT_ACCEL: f64 = MAX_ACCEL / 2.0; -/* - The acceleration to use for groups of hitobjects. This should be higher as - groups of hitobjects usually have to be traveled with "linear" velocity - across all the hitobjects. -*/ -const GROUP_ACCEL: f64 = MAX_ACCEL; -/* - How much to increase the acceleration if the current acceleration doesn't - produce a result. -*/ -const ACCEL_RETRY_STEP: f64 = 5_000.0; -/* - Since hitobjects' times are rounded to the nearest millisecond, linear - velocity calculations aren't very precise, leading to hitobjects with linear - velocities perceived to be identical not counted for grouping. To compensate - for this, a threshold is set, and any difference between linear velocities - under this threshold are counted. -*/ -const GROUP_VEL_LENIENCY: f64 = 0.2; - -/* - Size of the bounding box for the beatmap in storage. Do not change. -*/ -const BOUNDING_BOX_SIZE: (f64, f64) = (512.0, 384.0); // lazer default ig -/* - Physical limits of the machine -*/ -const PHYSICAL_MAX: (f64, f64) = (105.0, 110.0); -/* - Active area -*/ -const AREA_ORIGIN: (f64, f64) = (10.0, 10.0); -const AREA_MAX: (f64, f64) = (95.0, 95.0); -/* - Rotation in degrees anteclockwise -*/ -const ROTATION: f64 = 90.0; - -const AREA_SIZE: (f64, f64) = ( - AREA_MAX.0 - AREA_ORIGIN.0, - AREA_MAX.1 - AREA_ORIGIN.1 -); -const BOX_TO_AREA_OFFSET: (f64, f64) = ( - AREA_SIZE.0 / 2.0 - BOUNDING_BOX_SIZE.0 / 2.0, - AREA_SIZE.1 / 2.0 - BOUNDING_BOX_SIZE.1 / 2.0 -); +mod config; +use config as cfg; /* Calculates the maximum velocity (mm/ms) given the the start and end @@ -142,8 +84,8 @@ fn solve_feedrate_and_accel( loop { max_v = max_velocity(p1, p2, accel, ms); if !max_v.is_nan() { break } - accel += ACCEL_RETRY_STEP; - if accel >= MAX_ACCEL { + accel += cfg::ACCEL_RETRY_STEP; + if accel >= cfg::MAX_ACCEL { panic!("couldn't calculate max_v for dist {} within {}ms", p1 >> p2, ms); } } @@ -163,141 +105,366 @@ fn solve_feedrate_and_accel( (feedrate, accel) } +fn generate_gcode_move( + destination: PositionF64, + accel: f64, + last_accel: f64, + feedrate: f64 +) -> String { + let mut output = String::new(); + if accel != last_accel { + output = format!("M204 S{}\n", accel); + } + + output = format!( + "{}G0 F{:.4}\nG0 X{} Y{}", + output, + feedrate, + destination.x, destination.y + ); + + println!("{}", output); + output +} + +fn osu_position_to_kurbo_point(pos: &Position) -> Point { + Point { + x: pos.x.get().clone().expect_left("why").to_f64().expect("why"), + y: pos.y.get().clone().expect_left("why").to_f64().expect("why") + } +} + fn main() -> Result<(), Box> { - /* Steps - 1. Read beatmap and hitcircles - a. convert curves to lines - b. apply scaling for every point - c. apply rotation for every point - 2. Convert to gcode paths - a. add preliminary gcode - b. calculate F for a given movement - c. write movements to file - */ - - let src = OSU.parse::()?; + /* + # Calculating moves and optimizing + + The way this system works is by iterating through the hitobjects and + "accumulating" state, then creating *moves* from said state. On each + iteration, we don't "move to the next point", instead, we decide whether + or not to generate gcode to move to the last point. This also means that + every move starts at a point in the past. Here is a pseudocode + representation: + + start of the move = the last bounding box corner + last point = the last bounding box corner + + if it's the first point: + tell the machine to pause + otherwise: + if this point is in the same location as the last point: + enable stack mode + otherwise: + if stack mode is on: + generate gcode to move to the first point in the stack + generate gcode to dwell for the duration of the stack + disable stack mode + otherwise, if the hitobject qualifies for grouping: + increment the group size + otherwise: + generate gcode to move to the last point + store the last point as the start of the move + store the current point as the last point + increment total time + + Keep in mind that a line of gcode only tells the pen to move to another + position, and the starting location is based on its current position, + which was the destination of the last move. + */ + + let src = cfg::OSU.parse::()?; let binding = src.hitobjects.expect("Beatmap has no hit objects!"); - let mut hitobjects = binding.0.iter(); + let scale_fac = find_bbox_scale_factor( - BOUNDING_BOX_SIZE, - AREA_SIZE, - ROTATION + cfg::BOUNDING_BOX_SIZE, + cfg::AREA_SIZE, + cfg::ROTATION ); println!("G90\nG0 Z0"); let corners = [ - AREA_ORIGIN, - (AREA_ORIGIN.0, AREA_MAX.1), - (AREA_MAX.0, AREA_MAX.1), - (AREA_MAX.0, AREA_ORIGIN.1) + cfg::AREA_ORIGIN, + (cfg::AREA_ORIGIN.0, cfg::AREA_MAX.1), + (cfg::AREA_MAX.0, cfg::AREA_MAX.1), + (cfg::AREA_MAX.0, cfg::AREA_ORIGIN.1) ]; + for corner in corners { println!("G0 X{} Y{} F7500", corner.0, corner.1); } - let mut total_time: f64 = 0.0; + let final_corner = PositionF64::from_tuple(corners[corners.len() - 1]); + + // An extra element is needed at the end of the hitobjects vec + let temp_binding = binding.0.clone(); + let mut last_hitobject = temp_binding.last().unwrap().clone(); + last_hitobject.position = Position { + x: OsuDecimal::new(Decimal::from_f64_retain(final_corner.x).unwrap()), + y: OsuDecimal::new(Decimal::from_f64_retain(final_corner.y).unwrap()), + }; + + let mut hitobjects = binding.0; + hitobjects.push(last_hitobject.clone()); + let hitobjects = hitobjects.iter(); + + let mut s = IteratorState { + total_time: 0, + + last_point: final_corner, + last_point_ms: 0, + last_accel: 0.0, + + move_start: final_corner, + move_start_ms: 0, + + group_linear_vel: 0.0, + group_slope: 0.0, + group_size: 0, + + stack: false, + stack_start_ms: 0, + + osu_file: src + }; + + for (idx, obj) in hitobjects.enumerate() { + iteration(idx, obj, scale_fac, &mut s); + } + + eprintln!("total time should be {}ms", s.total_time); + + Ok(()) +} + +fn iteration( + idx: usize, + obj: &HitObject, + scale_fac: f64, + s: &mut IteratorState +) { + let current_ms = obj.time.get().clone().unwrap_left().to_u32().unwrap(); + let ms_since_last_point = current_ms - s.last_point_ms; + + let current_point = PositionF64 + ::from_position(obj.position.clone()) + .unwrap() + .convert_to_machine_space( + scale_fac, + cfg::BOUNDING_BOX_SIZE, + cfg::AREA_ORIGIN, + cfg::AREA_SIZE, + cfg::ROTATION + ); + + eprintln!("point {}", idx); + + if idx == 0 { + // Pause right before the first move + println!("PAUSE"); + } else if let HitCircle = obj.obj_params { + handle_hitcircle(current_ms, ms_since_last_point, current_point, s); + } else { + if s.stack { + end_stack(s); + } else { + end_move(s); + } + + match &obj.obj_params { + Slider(params) => { + handle_slider(obj.position.clone(), ¶ms, s); + }, + _ => {} + } + } + + s.total_time += ms_since_last_point; + s.last_point = current_point; + s.last_point_ms = current_ms; +} + +fn handle_hitcircle( + current_ms: u32, + ms_since_last_point: u32, + current_point: PositionF64, + s: &mut IteratorState +) { + if s.last_point == current_point && !s.stack { + // Begin stacking if the last point is the same as the current one + s.stack = true; + s.stack_start_ms = s.last_point_ms; + } else if s.last_point != current_point { + let linear_vel = (s.last_point >> current_point) / ms_since_last_point as f64; + let slope = s.last_point / current_point; + let can_group = s.group_linear_vel < cfg::GROUP_VEL_LENIENCY + && slope == s.group_slope; + + if s.stack { + end_stack(s); + } else if can_group { + println!("; !! adding point to group"); + s.group_size += 1; + } else { + end_move(s); + s.group_linear_vel = linear_vel; + s.group_slope = slope; + } + } +} - let mut p1 = PositionF64::new(0.0, 0.0); - let mut p1_ms: Decimal = 0.into(); - let mut last_accel: f64 = 0.0; +/* + This essentially works the same way as the base iteration. It creates + subpaths out of a set of control points by "accumulating" previous points + and deciding on whether or not to create a new subpath based on the next + point. + + Sliders are saved as different types if they have multiple types of curves. + Essentially, a path becomes a bézier if it isn't completely linear. Perfect + circle subpaths get approximated as béziers, too. +*/ +fn handle_slider( + pos: Position, + params: &SlideParams, + s: &mut IteratorState +) { + if params.curve_points.len() == 0 as usize { return; } + + let points = ¶ms.curve_points + .iter() + .map(|p| osu_position_to_kurbo_point(&p.0)); + + let ticks = match params.curve_type { + CurveType::Linear => { }, + CurveType::PerfectCircle => { }, + _ => { } + } +} + +fn calculate_linear_ticks( + pos: Position, + points: Vec, - /* - These are used for merging notes that share the same angle and linear - velocity into one move. Linear velocity is plainly (dist / ms_delta). +) -> Vec { + if points.len() == 0 { panic!("wtf") } - move_p1 is the starting point of a g-code move. - */ - let mut move_p1: PositionF64 = p1; - let mut move_p1_ms: Decimal = 0.into(); - let mut group_linear_vel = 0.0; - let mut group_slope = 0.0; - let mut group_size = 0; - let mut dwell_state = false; - - for (count, obj) in hitobjects.enumerate() { - let p2_ms = obj.time.get().clone().unwrap_left(); - let p1_to_p2_ms = p2_ms - .checked_sub(p1_ms) - .unwrap() - .to_f64() - .unwrap(); + let mut dist = 0.0; + let dist_between_ticks = - let p2 = PositionF64 - ::from_position(obj.position.clone()) - .unwrap() - .convert_to_machine_space( - scale_fac, - BOUNDING_BOX_SIZE, - AREA_ORIGIN, - AREA_SIZE, - ROTATION - ); - - eprintln!("point {}", count); - - if count == 0 { - println!("PAUSE"); - } else if p1 == p2 && !dwell_state { - dwell_state = true; - } else if p1 != p2 { - let move_p1_to_p1_ms = p1_ms - .checked_sub(move_p1_ms) - .unwrap() - .to_f64() - .unwrap(); - - let linear_vel = (p1 >> p2) / p1_to_p2_ms; - let slope = p1 / p2; - - println!("; linear_vel {:.4}, slope {:.4}", linear_vel, slope); - - if - linear_vel - group_linear_vel < GROUP_VEL_LENIENCY - && slope == group_slope - { - println!("; !! merging point"); - group_size += 1; - } else { - let (feedrate, accel) = solve_feedrate_and_accel( - move_p1, - p1, - if group_size > 0 { - GROUP_ACCEL - } else { - DEFAULT_ACCEL - }, - move_p1_to_p1_ms - ); + let mut ticks = Vec::::new(); - if accel != last_accel { - println!("M204 S{}", accel); - } + let mut dist_remainder = dist; + let mut point_iter = points.iter(); + let mut p1 = PositionF64::from_point(*point_iter.next().unwrap()); - println!("G0 F{:.4}\nG0 X{} Y{}", feedrate, p1.x, p1.y); + 'each_tick: while { - last_accel = accel; - group_linear_vel = linear_vel; - group_slope = slope; - group_size = 0; - } + } + loop { + let next_point = point_iter.next(); + let p2 = PositionF64::from_point(*point_iter.next().unwrap()); + let dist = p1 >> p2; + + if dist_remainder < dist { + let fac = dist_remainder / dist; + + ticks.push(PositionF64 { + x: (p2.x - p1.x) * fac, + y: (p2.y - p1.y) * fac + }); + break; + } else if dist_remainder == dist { + ticks.push(p2); + break; + } else { + dist_remainder -= dist; + p1 = p2; + } + } - if dwell_state { - println!("G4 P{}", move_p1_to_p1_ms); - dwell_state = false; + ticks +} + +fn calculate_bezier_ticks( + pos: Position, + points: Vec, + slider_mul: f64, + slider_ticks: u8 +) -> Vec { + let last_point: Point; + let mut segment_vertices = Vec::::new(); + segment_vertices.push(last_point); + + let mut split_path = BezPath::from_vec(vec![PathEl::MoveTo(last_point)]); + + for point in points.iter() { + // Previous path ended, new subpath begins + if *point == last_point { + match segment_vertices.len() { + 0 => { panic!("bruhhhhhh {:?}", pos) }, + 1 => { split_path.line_to(last_point) }, + _ => { + QuadSpline + ::new(segment_vertices) + .to_quads() + .for_each(|quad| split_path.quad_to(quad.p1, quad.p2)); + } } - move_p1_ms = p1_ms; - move_p1 = p1; + segment_vertices = Vec::::new(); + segment_vertices.push(last_point); + segment_vertices.push(*point); + } else { + segment_vertices.push(*point); } - - p1 = p2; - p1_ms = p2_ms; - total_time += p1_to_p2_ms; } + vec![PositionF64::new(10.0, 10.0)] +} + +fn end_stack(s: &mut IteratorState) { + // Generates gcode to move to the stack and wait there for the + // totkal duration of its hitobjects, and resets the stack state. + let (feedrate, accel) = solve_feedrate_and_accel( + s.move_start, + s.last_point, + cfg::DEFAULT_ACCEL, + (s.stack_start_ms - s.move_start_ms) as f64 + ); - eprintln!("total time should be {}ms", total_time); + generate_gcode_move(s.last_point, accel, s.last_accel, feedrate); + println!("G4 P{}", s.last_point_ms - s.stack_start_ms); - Ok(()) + s.last_accel = accel; + + s.move_start_ms = s.last_point_ms; + s.move_start = s.last_point; + + s.stack = false; +} + +fn end_move(s: &mut IteratorState) { + // Generates gcode for a move and starts a new one. + + // Use higher acceleration when moving across a group + let accel = if s.group_size > 0 { + cfg::GROUP_ACCEL + } else { + cfg::DEFAULT_ACCEL + }; + + let (feedrate, accel) = solve_feedrate_and_accel( + s.move_start, + s.last_point, + accel, + (s.last_point_ms - s.move_start_ms) as f64 + ); + + generate_gcode_move(s.last_point, accel, s.last_accel, feedrate); + + s.last_accel = accel; + + s.move_start_ms = s.last_point_ms; + s.move_start = s.last_point; + + s.group_size = 0; } /* diff --git a/src/types.rs b/src/types.rs index 17f59db..8ac5307 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,6 @@ -use osu_file_parser::Position; +use osu_file_parser::{osu_file, timingpoints::TimingPoint, Position, Decimal as RetardedDecimal}; use rust_decimal::{Decimal, prelude::ToPrimitive}; +use kurbo::{Point}; pub type DecimalTuple = (Decimal, Decimal); @@ -28,6 +29,13 @@ impl PositionF64 { }) } + pub fn from_point(a: Point) -> Self { + Self { + x: a.x, + y: a.y + } + } + pub fn scale(mut self, fac: f64) -> Self { self.x *= fac; self.y *= fac; @@ -127,3 +135,34 @@ impl std::ops::Div for PositionF64 { diff.y / diff.x } } + +pub struct IteratorState { + pub total_time: u32, + + pub last_point: PositionF64, + pub last_point_ms: u32, + pub last_accel: f64, + + pub move_start: PositionF64, + pub move_start_ms: u32, + + pub group_linear_vel: f64, + pub group_slope: f64, + pub group_size: u32, + + pub stack: bool, + pub stack_start_ms: u32, + + pub osu_file: osu_file::OsuFile +} + +impl IteratorState { + fn get_timing_point_at_ms(&self, ms: u32) -> &TimingPoint { + for t_point in self.osu_file.timing_points.unwrap().0.iter() { + if ms >= t_point.time().try_into().expect() { + return t_point; + } + } + &self.osu_file.timing_points.unwrap().0[0] + } +} \ No newline at end of file diff --git a/test2.gcode b/test2.gcode index c4f5c2c..703add0 100644 --- a/test2.gcode +++ b/test2.gcode @@ -5,74 +5,53 @@ G0 X10 Y95 F7500 G0 X95 Y95 F7500 G0 X95 Y10 F7500 PAUSE -; linear_vel 0.1064, slope 5.3750 M204 S55000 -G0 F14734.6525 +G0 F11960.7600 G0 X51.171875 Y35.8984375 -; linear_vel 0.0818, slope -2.3846 G0 F6429.3272 G0 X56.484375 Y64.453125 -; linear_vel 0.1392, slope 2.5238 -G0 F982.1545 +G0 F4933.1169 G0 X65.1171875 Y43.8671875 -G4 P1364 -; linear_vel 0.0584, slope -inf +G4 P1091 G0 F8430.0676 G0 X79.0625 Y79.0625 -; linear_vel 0.0590, slope -inf -; !! merging point -; linear_vel 0.0584, slope -inf -; !! merging point -; linear_vel 0.0334, slope 0.3735 +; !! adding point to group +; !! adding point to group M204 S110000 -G0 F3509.5833 +G0 F3517.1981 G0 X79.0625 Y31.083984375 -; linear_vel 0.5068, slope 13.0312 M204 S55000 G0 F2005.8322 G0 X36.396484375 Y15.146484375000004 -; linear_vel 0.4223, slope -2.4884 G0 F32785.7872 G0 X41.70898437500001 Y84.375 -; linear_vel 0.2518, slope -1.2481 G0 F26957.4090 G0 X63.125 Y31.083984375000004 -; linear_vel 0.2373, slope -0.1710 G0 F15656.4508 G0 X41.708984375 Y57.8125 -; linear_vel 0.1172, slope -0.0000 G0 F14715.1658 G0 X73.75 Y52.333984375 -; linear_vel 0.1614, slope 3.8788 G0 F7145.0001 G0 X57.8125 Y52.333984375 -; linear_vel 0.4009, slope 1.7950 G0 F9899.9328 G0 X52.333984375 Y31.083984375000004 -; linear_vel 0.4309, slope -inf G0 F25490.3308 G0 X79.0625 Y79.0625 -; linear_vel 0.1953, slope -1.3333 G0 F27545.0689 G0 X79.0625 Y20.458984375 -; linear_vel 0.2371, slope -6.0313 G0 F12041.8473 G0 X63.125 Y41.708984375 -; linear_vel 0.1758, slope -2.0156 G0 F14702.2521 G0 X57.81250000000001 Y73.75 -; linear_vel 0.2491, slope 1.2403 G0 F10807.3775 G0 X68.4375 Y52.333984375 -; linear_vel 0.3923, slope 0.7510 G0 F15472.8573 G0 X47.021484375 Y25.771484375000004 -; linear_vel 0.2509, slope 0.8063 G0 F24924.2159 G0 X89.6875 Y57.8125 -; linear_vel 0.2838, slope -3.4615 G0 F15595.0898 G0 X63.125 Y36.396484375 -; linear_vel 0.1622, slope 4.0312 G0 F17722.9324 G0 X52.33398437500001 Y73.75 +G0 F9955.4352 +G0 X47.021484375 Y52.333984375