2025-04-09 16:34:48 +03:00
|
|
|
use sdl3::event::Event;
|
|
|
|
|
use sdl3::keyboard::Keycode;
|
|
|
|
|
use sdl3::pixels::Color;
|
2025-04-12 15:36:12 +03:00
|
|
|
use sdl3::rect::Point;
|
2025-04-09 16:34:48 +03:00
|
|
|
use sdl3::render::{FPoint, WindowCanvas};
|
|
|
|
|
use std::f32::consts::PI;
|
2025-04-09 18:38:19 +03:00
|
|
|
use std::ops;
|
2025-04-12 15:36:12 +03:00
|
|
|
use std::ops::{AddAssign, Mul, Rem, Sub};
|
|
|
|
|
use std::time::{Duration, Instant};
|
2025-04-09 16:34:48 +03:00
|
|
|
|
|
|
|
|
const SIZE: u32 = 400;
|
2025-04-09 23:10:04 +03:00
|
|
|
const SIZE_F: f32 = 400.0;
|
2025-04-12 15:36:12 +03:00
|
|
|
|
2025-04-09 16:34:48 +03:00
|
|
|
pub fn main() {
|
2025-04-12 15:36:12 +03:00
|
|
|
let mut point_a = Point2D::new(-5.0, 0.0);
|
|
|
|
|
let mut point_b = Point2D::new(5.0, 0.0);
|
|
|
|
|
|
|
|
|
|
let line = Line2D::new(&mut point_a, &mut point_b);
|
2025-04-09 16:34:48 +03:00
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
let mut selection = 1;
|
2025-04-09 19:14:50 +03:00
|
|
|
|
2025-04-09 16:34:48 +03:00
|
|
|
let sdl_context = sdl3::init().unwrap();
|
|
|
|
|
let video_subsystem = sdl_context.video().unwrap();
|
|
|
|
|
|
|
|
|
|
let window = video_subsystem
|
|
|
|
|
.window("Point interaction", SIZE * 2, SIZE * 2)
|
|
|
|
|
.position_centered()
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
let mut canvas = window.clone().into_canvas();
|
|
|
|
|
|
|
|
|
|
sdl_context.mouse().show_cursor(false);
|
|
|
|
|
sdl_context.mouse().capture(true);
|
|
|
|
|
sdl_context
|
|
|
|
|
.mouse()
|
|
|
|
|
.warp_mouse_in_window(&window, SIZE_F, SIZE_F);
|
2025-04-09 16:34:48 +03:00
|
|
|
|
|
|
|
|
canvas.set_draw_color(Color::RGB(0, 0, 0));
|
|
|
|
|
canvas.clear();
|
|
|
|
|
canvas.present();
|
|
|
|
|
let mut event_pump = sdl_context.event_pump().unwrap();
|
2025-04-09 23:10:04 +03:00
|
|
|
let time = Instant::now();
|
|
|
|
|
let mut count = 0;
|
2025-04-09 16:34:48 +03:00
|
|
|
'running: loop {
|
2025-04-09 18:38:19 +03:00
|
|
|
canvas.set_draw_color(Color::RGB(0, 0, 0));
|
|
|
|
|
canvas.clear();
|
2025-04-09 16:34:48 +03:00
|
|
|
for event in event_pump.poll_iter() {
|
|
|
|
|
match event {
|
|
|
|
|
Event::Quit { .. }
|
|
|
|
|
| Event::KeyDown {
|
|
|
|
|
keycode: Some(Keycode::Escape),
|
|
|
|
|
..
|
|
|
|
|
} => break 'running,
|
2025-04-12 15:36:12 +03:00
|
|
|
Event::KeyDown {
|
|
|
|
|
keycode: Some(Keycode::_1),
|
|
|
|
|
..
|
|
|
|
|
} => {
|
|
|
|
|
selection = 1;
|
|
|
|
|
}
|
|
|
|
|
Event::KeyDown {
|
|
|
|
|
keycode: Some(Keycode::_2),
|
|
|
|
|
..
|
|
|
|
|
} => {
|
|
|
|
|
selection = 2;
|
|
|
|
|
}
|
|
|
|
|
Event::KeyDown {
|
|
|
|
|
keycode: Some(Keycode::D),
|
|
|
|
|
..
|
|
|
|
|
} => {
|
|
|
|
|
println!("Debug")
|
|
|
|
|
}
|
|
|
|
|
Event::MouseMotion { .. } => {
|
|
|
|
|
if let Event::MouseMotion {
|
|
|
|
|
timestamp: _,
|
|
|
|
|
window_id: _,
|
|
|
|
|
which: _,
|
|
|
|
|
mousestate: _,
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
xrel,
|
|
|
|
|
yrel,
|
|
|
|
|
} = event
|
|
|
|
|
{
|
|
|
|
|
let mut cursor: &mut Point2D;
|
|
|
|
|
if selection == 1 {
|
|
|
|
|
cursor = line.a;
|
|
|
|
|
} else {
|
|
|
|
|
cursor = line.b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursor += (xrel, yrel);
|
|
|
|
|
cursor.optimize();
|
|
|
|
|
cursor = &mut cursor.abs();
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-09 16:34:48 +03:00
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-09 23:10:04 +03:00
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
sdl_context
|
|
|
|
|
.mouse()
|
|
|
|
|
.warp_mouse_in_window(&window, SIZE_F, SIZE_F);
|
|
|
|
|
// The rest of the game loop goes here...
|
2025-04-09 23:10:04 +03:00
|
|
|
|
|
|
|
|
count += 1;
|
2025-04-09 19:14:50 +03:00
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
line.draw(&mut canvas, 1.0);
|
2025-04-09 16:34:48 +03:00
|
|
|
|
|
|
|
|
canvas.present();
|
2025-04-09 19:14:50 +03:00
|
|
|
|
2025-04-09 23:10:04 +03:00
|
|
|
if count == 10000 {
|
|
|
|
|
println!("Time for 10000 is {} ms", time.elapsed().as_millis());
|
|
|
|
|
}
|
2025-04-09 19:14:50 +03:00
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 600));
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct Point2D {
|
|
|
|
|
x: f32,
|
|
|
|
|
y: f32,
|
2025-04-09 18:38:19 +03:00
|
|
|
spin: bool,
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Point2D {
|
|
|
|
|
pub fn new(x: f32, y: f32) -> Point2D {
|
2025-04-09 18:38:19 +03:00
|
|
|
Point2D { x, y, spin: false }
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
pub fn new_with_spin(x: f32, y: f32, spin: bool) -> Point2D {
|
|
|
|
|
Point2D { x, y, spin }
|
|
|
|
|
}
|
|
|
|
|
pub fn distance_abs(&self, point: &Point2D) -> f32 {
|
|
|
|
|
let a_abs = self.optimized().abs();
|
|
|
|
|
let b_abs = point.optimized().abs();
|
|
|
|
|
(a_abs.x - b_abs.x).hypot(a_abs.y - b_abs.y)
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn distance_sq(&self, point: &Point2D) -> f32 {
|
|
|
|
|
(self.x - point.x).powi(2) + (self.y - point.y).powi(2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn alt_distance(&self, point: &Point2D) -> f32 {
|
2025-04-12 15:36:12 +03:00
|
|
|
2.0 * SIZE_F - self.distance_abs(point)
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn to_cartesian(&self) -> Point2D {
|
2025-04-09 23:10:04 +03:00
|
|
|
let angle = (self.x / SIZE_F) * PI;
|
2025-04-09 16:34:48 +03:00
|
|
|
let cos = angle.cos();
|
|
|
|
|
let sin = angle.sin();
|
2025-04-09 23:10:04 +03:00
|
|
|
let scale = (SIZE_F + self.y) / 2.0;
|
2025-04-09 16:34:48 +03:00
|
|
|
Point2D::new(cos * scale, sin * scale)
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 23:10:04 +03:00
|
|
|
pub fn to_super_space(&self) -> Point2D {
|
|
|
|
|
let len = self.x.hypot(self.y);
|
|
|
|
|
let y = len * 2.0 - SIZE_F;
|
|
|
|
|
|
|
|
|
|
let cos = self.x / len;
|
|
|
|
|
|
|
|
|
|
let acos = cos.acos();
|
|
|
|
|
|
|
|
|
|
let mut x = acos * SIZE_F / PI;
|
|
|
|
|
|
|
|
|
|
if self.y < 0.0 {
|
|
|
|
|
x = -x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Point2D::new(x, y)
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 16:34:48 +03:00
|
|
|
pub fn to_sdl(&self) -> FPoint {
|
2025-04-09 23:10:04 +03:00
|
|
|
FPoint::new(self.x + SIZE_F, self.y + SIZE_F)
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn from_sdl(x: f32, y: f32) -> Point2D {
|
2025-04-09 23:10:04 +03:00
|
|
|
Point2D::new(x - SIZE_F, y - SIZE_F)
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn draw(&self, canvas: &mut WindowCanvas) {
|
2025-04-09 23:10:04 +03:00
|
|
|
let polar = self.to_cartesian();
|
2025-04-09 16:34:48 +03:00
|
|
|
let sdl_point = polar.to_sdl();
|
|
|
|
|
canvas.draw_point(sdl_point).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn lapped(l: f32) -> f32 {
|
2025-04-09 23:10:04 +03:00
|
|
|
let mut remainder = l.rem(SIZE_F * 2.0);
|
|
|
|
|
|
|
|
|
|
if remainder.abs() > SIZE_F {
|
|
|
|
|
let out_delta = remainder.abs() - SIZE_F;
|
|
|
|
|
let re_new = SIZE_F - out_delta;
|
|
|
|
|
remainder = -re_new * l.signum()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remainder
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
pub fn normalized(&self) -> Point2D {
|
|
|
|
|
let len = self.x.hypot(self.y);
|
|
|
|
|
Point2D::new_with_spin(self.x / len, self.y / len, self.spin)
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 16:34:48 +03:00
|
|
|
pub fn optimize(&mut self) {
|
2025-04-09 23:10:04 +03:00
|
|
|
if self.x.abs() > SIZE_F {
|
2025-04-09 16:34:48 +03:00
|
|
|
self.x = Self::lapped(self.x);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 23:10:04 +03:00
|
|
|
if self.y.abs() > SIZE_F {
|
2025-04-09 18:38:19 +03:00
|
|
|
let side = self.y.signum();
|
2025-04-09 23:10:04 +03:00
|
|
|
self.y += -side * 2.0 * (self.y.abs() - SIZE_F);
|
|
|
|
|
self.x = self.x + SIZE_F;
|
2025-04-09 18:38:19 +03:00
|
|
|
self.spin = !self.spin;
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-09 18:38:19 +03:00
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
pub fn optimized(&self) -> Point2D {
|
|
|
|
|
let mut x: f32 = self.x;
|
|
|
|
|
let mut y: f32 = self.y;
|
|
|
|
|
let mut spin: bool = self.spin;
|
|
|
|
|
if self.x.abs() > SIZE_F {
|
|
|
|
|
x = Self::lapped(self.x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self.y.abs() > SIZE_F {
|
|
|
|
|
let side = self.y.signum();
|
|
|
|
|
y += -side * 2.0 * (self.y.abs() - SIZE_F);
|
|
|
|
|
x = self.x + SIZE_F;
|
|
|
|
|
spin = !spin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Point2D::new_with_spin(x, y, spin)
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 18:38:19 +03:00
|
|
|
pub fn draw_point(canvas: &mut WindowCanvas, points: &Vec<FPoint>) {
|
|
|
|
|
// canvas.draw_points(&points).unwrap()
|
|
|
|
|
canvas.draw_points(&points[..]).unwrap();
|
|
|
|
|
}
|
2025-04-09 23:10:04 +03:00
|
|
|
|
|
|
|
|
pub fn eq(&self, point: &Point2D) -> bool {
|
|
|
|
|
(self.x.abs() - point.x.abs()).abs() < 0.1 && (self.y.abs() - point.y.abs()).abs() < 0.1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn eq_spin(&self, point: &Point2D) -> bool {
|
|
|
|
|
self.eq(point) && self.spin == point.spin
|
|
|
|
|
}
|
2025-04-12 15:36:12 +03:00
|
|
|
|
|
|
|
|
pub fn abs(&self) -> Point2D {
|
|
|
|
|
let x: f32;
|
|
|
|
|
let y: f32;
|
|
|
|
|
if self.x < 0.0 {
|
|
|
|
|
x = self.x.rem_euclid(SIZE_F * 2.0);
|
|
|
|
|
} else {
|
|
|
|
|
x = self.x;
|
|
|
|
|
}
|
|
|
|
|
if self.y < 0.0 {
|
|
|
|
|
y = self.y.rem_euclid(SIZE_F * 2.0);
|
|
|
|
|
} else {
|
|
|
|
|
y = self.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Point2D::new(x, y)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn relative(&self) -> Point2D {
|
|
|
|
|
Point2D::new(Self::lapped(self.x), Self::lapped(self.y))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add(&mut self, x: f32, y: f32) {
|
|
|
|
|
self.x += x;
|
|
|
|
|
self.y += y;
|
|
|
|
|
}
|
2025-04-09 18:38:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ops::AddAssign for Point2D {
|
|
|
|
|
fn add_assign(&mut self, rhs: Self) {
|
|
|
|
|
self.x += rhs.x * bool_to_int(self.spin) as f32;
|
|
|
|
|
self.y += rhs.y * bool_to_int(self.spin) as f32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-12 15:36:12 +03:00
|
|
|
impl AddAssign<(f32, f32)> for Point2D {
|
2025-04-09 18:38:19 +03:00
|
|
|
fn add_assign(&mut self, rhs: (f32, f32)) {
|
|
|
|
|
self.x += rhs.0 * bool_to_int(self.spin) as f32;
|
|
|
|
|
self.y += rhs.1 * bool_to_int(self.spin) as f32;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-12 15:36:12 +03:00
|
|
|
|
|
|
|
|
impl AddAssign<(f32, f32)> for &mut Point2D {
|
|
|
|
|
fn add_assign(&mut self, rhs: (f32, f32)) {
|
|
|
|
|
self.x += rhs.0 * bool_to_int(self.spin) as f32;
|
|
|
|
|
self.y += rhs.1 * bool_to_int(self.spin) as f32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 18:38:19 +03:00
|
|
|
fn bool_to_int(flag: bool) -> i32 {
|
|
|
|
|
if !flag { 1 } else { -1 }
|
2025-04-09 16:34:48 +03:00
|
|
|
}
|
2025-04-12 15:36:12 +03:00
|
|
|
|
|
|
|
|
impl Clone for Point2D {
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Point2D::new_with_spin(self.x, self.y, self.spin)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Line2D<'a> {
|
|
|
|
|
a: &'a mut Point2D,
|
|
|
|
|
b: &'a mut Point2D,
|
|
|
|
|
ending: Color,
|
|
|
|
|
fill: Color,
|
|
|
|
|
segments: u32,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Sub for Point2D {
|
|
|
|
|
type Output = Self;
|
|
|
|
|
fn sub(self, rhs: Self) -> Self::Output {
|
|
|
|
|
Point2D::new_with_spin(self.x - rhs.x, self.y - rhs.y, self.spin)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Mul<f32> for Point2D {
|
|
|
|
|
type Output = Point2D;
|
|
|
|
|
|
|
|
|
|
fn mul(self, rhs: f32) -> Self::Output {
|
|
|
|
|
Point2D::new_with_spin(self.x * rhs, self.y * rhs, self.spin)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Line2D<'a> {
|
|
|
|
|
pub fn new(a: &'a mut Point2D, b: &'a mut Point2D) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
a,
|
|
|
|
|
b,
|
|
|
|
|
ending: Color::WHITE,
|
|
|
|
|
fill: Color::YELLOW,
|
|
|
|
|
segments: 13,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn draw<'b>(&'a self, canvas: &mut WindowCanvas, pow: f32) {
|
|
|
|
|
let distance: f32;
|
|
|
|
|
if pow < 0.0 {
|
|
|
|
|
distance = self.a.alt_distance(self.b);
|
|
|
|
|
} else {
|
|
|
|
|
distance = self.b.distance_abs(self.a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let a_abs = self.a.abs();
|
|
|
|
|
let b_abs = self.b.abs();
|
|
|
|
|
let vec = (b_abs - a_abs).normalized() * (distance / self.segments as f32) * pow;
|
|
|
|
|
let mut cursor = self.a.clone();
|
|
|
|
|
canvas.set_draw_color(self.fill);
|
|
|
|
|
for i in 1..self.segments {
|
|
|
|
|
cursor.add(vec.x, vec.y);
|
|
|
|
|
cursor.optimize();
|
|
|
|
|
cursor.draw(canvas);
|
|
|
|
|
}
|
|
|
|
|
canvas.set_draw_color(self.ending);
|
|
|
|
|
self.a.draw(canvas);
|
|
|
|
|
self.b.draw(canvas);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn draw_alt<'b>(&'a self, canvas: &mut WindowCanvas) {
|
|
|
|
|
let mut local_a = self.a.clone().abs();
|
|
|
|
|
let mut local_b = self.b.clone().abs();
|
|
|
|
|
|
|
|
|
|
let x_step = (local_a.x - local_b.x) / self.segments as f32;
|
|
|
|
|
let y_step = (local_a.y - local_b.y) / self.segments as f32;
|
|
|
|
|
canvas.set_draw_color(self.fill);
|
|
|
|
|
for i in 1..self.segments {
|
|
|
|
|
let pt = Point2D::new(local_b.x + x_step * i as f32, local_b.y + y_step * i as f32);
|
|
|
|
|
pt.draw(canvas);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
canvas.set_draw_color(self.ending);
|
|
|
|
|
local_b.draw(canvas);
|
|
|
|
|
local_a.draw(canvas);
|
|
|
|
|
}
|
|
|
|
|
}
|