use std::f32::consts::FRAC_PI_2; use crate::states::linear::*; use crate::{FACTOR}; use bevy::prelude::*; use bevy::reflect::List; pub const CENTER_X: f32 = 0.0; pub const CENTER_Y: f32 = 0.0; // pub const FACTOR_RADIUS: f32 = FACTOR as f32 / 2.0; pub const STEP: f32 = FACTOR as f32 / SCALE; pub const SCALE: f32 = 2.0; pub fn setup_linear_track() -> Track { println!("Построение трека начато"); Track { start_point: Vec2 { x: CENTER_X - FACTOR as f32 * 7.0, y: CENTER_Y - FACTOR as f32 * 4.0, }, start_direction: Vec2::X, segments: vec![ PathSegment::Line { length: STEP * 6.0 }, PathSegment::Turn { radius: STEP, left: true }, PathSegment::Line { length: STEP }, PathSegment::Turn { radius: STEP, left: false }, PathSegment::Line { length: STEP * 18.0 }, PathSegment::Turn { radius: STEP, left: true }, PathSegment::Line { length: STEP * 4.0 }, PathSegment::Turn { radius: STEP, left: true }, PathSegment::Turn { radius: STEP, left: false }, PathSegment::Line { length: STEP * 4.0 }, PathSegment::Turn { radius: STEP, left: true }, PathSegment::Line { length: STEP * 20.0 }, PathSegment::Turn { radius: STEP, left: true }, PathSegment::Line { length: STEP * 5.0 }, PathSegment::Turn { radius: STEP, left: true }, PathSegment::Line { length: STEP * 10.0 }, PathSegment::Turn { radius: STEP, left: false }, PathSegment::Line { length: STEP * 2.0 }, ], } } pub fn precalculate_track(track: &Track) -> PrecalculatedTrack { let mut pt = PrecalculatedTrack { segments: vec![] }; let mut cumulative_length: Vec = vec![0.0]; let mut current_pos = track.start_point; let mut current_dir = track.start_direction; // на первом проходе заполняем все, кроме t_start и t_end, // потому что мы не можем посчитать их без общей длины for seg in track.segments.iter(){ match seg { PathSegment::Line { length } => { let calc_seg = PTSegment { t_start: 0.0, t_end: 0.0, segment_type: SegementType::Line, start_pos: current_pos, direction: current_dir, center: Vec2::ZERO, radius: 0.0, start_angle: 0.0, sweep_sign: 0.0, }; pt.segments.push(calc_seg); // сдвигаем позицию для следующего сегмента current_pos = current_pos + length * current_dir; // направление не меняем, пропуск // накапливаем длину cumulative_length.push(cumulative_length[cumulative_length.len() -1] + *length); } PathSegment::Turn {radius, left } => { let arc = helper_arc_calculator(current_pos, current_dir, *left, *radius); let calc_seg = PTSegment { t_start: 0.0, t_end: 0.0, segment_type: SegementType::Turn, start_pos: current_pos, direction: current_dir, center: arc.center, radius: *radius, start_angle: arc.start_angle, sweep_sign: arc.sweep_sign, }; pt.segments.push(calc_seg); // сдвигаем позицию для следующего сегмента current_pos = arc.end_pos; current_dir = arc.normal; // накапливаем длину cumulative_length.push(cumulative_length[cumulative_length.len() -1] + (FRAC_PI_2 * radius)); } } } let last_index = cumulative_length.len() - 1; let total_length = cumulative_length[last_index]; // итерируемся уже по прекалькулированному вектору // заполняем точки на треке в пересчете на общую длину println!("Precalculated track:"); for (i, seg) in pt.segments.iter_mut().enumerate() { seg.t_start = cumulative_length[i] / total_length; if i < last_index { seg.t_end = cumulative_length[i+1] / total_length; } else { seg.t_end = 1.0; } println!("{:?}", seg); } pt } pub fn helper_arc_calculator(pos: Vec2, dir: Vec2, turn_to: bool, radius: f32) -> ArcCalculation{ let (normal, sign): (Vec2, f32) = if turn_to { (Vec2::new(-dir.y, dir.x), -1.0) } else { (Vec2::new(dir.y, -dir.x), 1.0) }; let center = pos + normal * radius; let start_vec = pos - center; let initial_vec = if turn_to { -start_vec.perp() } else { -start_vec }; let angle = initial_vec.to_angle(); ArcCalculation{ normal, center, start_angle: angle, sweep_sign: sign, end_pos: center + normal.perp() * radius * sign, } }