First things first
Started the typing up of a turning function and path generator
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Cargo.lock
|
||||||
|
target
|
||||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "redoal"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
approx = "0.5.1"
|
||||||
|
lyon = "1.0.1"
|
||||||
20
ReadMe.md
Normal file
20
ReadMe.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Redoal
|
||||||
|
|
||||||
|
A library to quantize input path data as a search tree enabling the core functionality of a DHT based path lookup.
|
||||||
|
|
||||||
|
# What it does
|
||||||
|
|
||||||
|
1. Optionally we preprocess input data, normalize, center weight and ensure it's not out of bounds, as a turning function.
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Deserialize and Serialize
|
||||||
|
To encode and decode path data from
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
|
||||||
|
Visual tests can render and offer manual input data input that renders using the lyon crate.
|
||||||
129
src/lib.rs
Normal file
129
src/lib.rs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
use lyon::math::point;
|
||||||
|
use lyon::path::Path;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct TurningFunction {
|
||||||
|
steps: Vec<i32>,
|
||||||
|
turns: Vec<f32>,
|
||||||
|
trajectory: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TurningFunction {
|
||||||
|
fn new(trajectory: f32) -> Self {
|
||||||
|
TurningFunction {
|
||||||
|
steps: Vec::new(),
|
||||||
|
turns: Vec::new(),
|
||||||
|
trajectory,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update current trajectory and add increment
|
||||||
|
fn add_increment(&mut self, step: i32, direction: f32) {
|
||||||
|
let radian_diff = direction - self.trajectory;
|
||||||
|
self.steps.push(step);
|
||||||
|
self.turns.push(radian_diff);
|
||||||
|
self.trajectory = self.trajectory + radian_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_coordinates(&self) -> Vec<[f32; 2]> {
|
||||||
|
let mut coordinates = Vec::new();
|
||||||
|
let mut x = 0.0;
|
||||||
|
let mut y = 0.0;
|
||||||
|
let mut tracking_trajectory = 0.0;
|
||||||
|
|
||||||
|
for (turn, step) in self.turns.iter().zip(self.steps.iter()) {
|
||||||
|
tracking_trajectory += *turn as f64;
|
||||||
|
|
||||||
|
// Calculate the new position based on current position and angle of rotation
|
||||||
|
let dx = (tracking_trajectory.sin() as i32 * step) as f64;
|
||||||
|
let dy = (tracking_trajectory.cos() as i32 * step) as f64;
|
||||||
|
|
||||||
|
x += dx;
|
||||||
|
y += dy;
|
||||||
|
|
||||||
|
coordinates.push([x as f32, y as f32]);
|
||||||
|
}
|
||||||
|
|
||||||
|
coordinates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PathGenerator {
|
||||||
|
from: [f32; 2],
|
||||||
|
turning_function: TurningFunction,
|
||||||
|
to: [f32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathGenerator {
|
||||||
|
// A function to calculate the path based on the turning function
|
||||||
|
fn generate_path(&self) -> Path {
|
||||||
|
let mut builder = lyon::path::Path::builder();
|
||||||
|
|
||||||
|
// Start at the from point
|
||||||
|
builder.begin(point(self.from[0], self.from[1]));
|
||||||
|
|
||||||
|
// Draw lines between each coordinate point and transpose with starting point
|
||||||
|
for coord in self.turning_function.clone().to_coordinates() {
|
||||||
|
builder.line_to(point(coord[0] + self.from[0], coord[1] + self.from[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build and return the path
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Euclidian distance between two points in 2-dimensional space
|
||||||
|
pub fn euclidean_distance(a: &[f64], b: &[f64]) -> f64 {
|
||||||
|
a.into_iter()
|
||||||
|
.zip(b)
|
||||||
|
.map(|(x, y)| (x - y).powi(2))
|
||||||
|
.sum::<f64>()
|
||||||
|
.sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use approx::assert_relative_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_euclidean_distance() {
|
||||||
|
let p1 = [1.0, 2.0];
|
||||||
|
let p2 = [3.0, 4.0];
|
||||||
|
|
||||||
|
assert_relative_eq!(2.8, euclidean_distance(&p1, &p2), epsilon = 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_path_generator() {
|
||||||
|
// let from = [0.0, 0.0];
|
||||||
|
// let tf = TurningFunction::new(0.0);
|
||||||
|
// let to = [1.5, 2.3];
|
||||||
|
|
||||||
|
// let pg = PathGenerator {
|
||||||
|
// from,
|
||||||
|
// turning_function: tf,
|
||||||
|
// to,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let path = pg.generate_path();
|
||||||
|
|
||||||
|
// // Test that the generated path starts at the "from" point
|
||||||
|
// assert_eq!(path.iter().first(), Some(&point(from[0], from[1])));
|
||||||
|
|
||||||
|
// // Test that the generated path ends at the "to" point
|
||||||
|
// assert_eq!(path.iter().last(), Some(&point(to[0], to[1])));
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_turning_function_to_coords() {
|
||||||
|
let mut tf = TurningFunction::new(0.0);
|
||||||
|
tf.add_increment(1, 0.5);
|
||||||
|
tf.add_increment(2, -0.3);
|
||||||
|
let coords = tf.to_coordinates();
|
||||||
|
|
||||||
|
println!("{:?}", coords);
|
||||||
|
|
||||||
|
assert_eq!(coords.len(), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user