#![deny(clippy::all)]
#![warn(clippy::cargo)]
#![warn(clippy::complexity)]
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
#![warn(clippy::perf)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![allow(clippy::many_single_char_names)]
use core::f64;
use crate::arc::ArcVal;
use crate::arc::Form as ArcForm;
pub static MM_PER_ARC_SEGMENT: f64 = 1_f64;
pub mod binary;
pub mod command;
mod double;
pub mod params;
pub mod arc;
#[derive(Default, Debug, Eq, PartialEq)]
pub enum PositionMode {
#[default]
Absolute,
Relative,
}
#[derive(Debug)]
pub struct ArcParams {
pub center: (f64, f64),
pub radius: f64,
pub theta_start: f64,
pub theta_end: f64,
}
#[must_use] pub fn compute_arc(current_x: f64, current_y: f64, form: &ArcForm) -> ArcParams {
let mut i: f64 = 0_f64;
let mut j: f64 = 0_f64;
let mut x: f64 = f64::NAN;
let mut y: f64 = f64::NAN;
let radius: f64;
let center: (f64, f64);
let mut theta_start: f64;
let mut theta_end: f64;
match form {
ArcForm::IJ(arc_values) => {
for val in arc_values {
match val {
ArcVal::X(val) => x = *val,
ArcVal::Y(val) => y = *val,
ArcVal::I(val) => i = *val,
ArcVal::J(val) => j = *val,
_ => {}
}
}
debug_assert!(x.is_finite());
debug_assert!(y.is_finite());
radius = i.hypot(j);
center = (current_x + i, current_y + j);
let delta_start_x = current_x - center.0;
let delta_start_y = current_y - center.1;
theta_start = (delta_start_y).atan2(delta_start_x);
if theta_start < 0_f64 {
theta_start += 2_f64 * f64::consts::PI;
}
let delta_end_x = x - center.0;
let delta_end_y = y - center.1;
theta_end = (delta_end_y).atan2(delta_end_x);
if theta_end < 0_f64 {
theta_end += 2_f64 * f64::consts::PI;
}
}
ArcForm::R(arc_values) => {
let mut radius: f64 = f64::NAN;
for val in arc_values {
match val {
ArcVal::X(val) => x = *val,
ArcVal::Y(val) => y = *val,
ArcVal::R(val) => radius = *val,
_ => {
}
}
}
debug_assert!(x.is_finite());
debug_assert!(y.is_finite());
debug_assert!(radius.is_finite());
todo!();
}
}
ArcParams {
center,
radius,
theta_start,
theta_end,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn round_to_two_decimals(x: f64) -> f64 {
(x * 100.0).round() / 100.0
}
#[test]
fn compute_arc_ij() {
let arc = compute_arc(
9.0,
6.0,
&ArcForm::IJ(
[
ArcVal::X(2.0),
ArcVal::Y(7.0),
ArcVal::I(-4.0),
ArcVal::J(-3.0),
]
.into(),
),
);
assert_eq!(arc.center, (5.0, 3.0));
assert_eq!(arc.radius, 5.0);
assert_eq!(
round_to_two_decimals(arc.theta_start.to_degrees()),
36.87_f64
);
assert_eq!(
round_to_two_decimals(arc.theta_end.to_degrees()),
126.87_f64
);
}
#[test]
fn troublesome_arc_ij() {
let arc = compute_arc(
0.0,
5.0,
&ArcForm::IJ(
[
ArcVal::X(5.0),
ArcVal::Y(0.0),
ArcVal::I(5.0),
ArcVal::J(0.0),
]
.into(),
),
);
assert_eq!(arc.center, (5.0, 5.0));
assert_eq!(arc.radius, 5.0);
assert_eq!(round_to_two_decimals(arc.theta_start.to_degrees()), 180_f64);
assert_eq!(round_to_two_decimals(arc.theta_end.to_degrees()), 270_f64);
}
#[ignore]
#[test]
fn compute_arc_r() {
let arc = compute_arc(
9.0,
6.0,
&ArcForm::R([ArcVal::X(2.0), ArcVal::Y(7.0), ArcVal::R(5.0)].into()),
);
assert_eq!(arc.center, (5.0, 3.0));
assert_eq!(arc.radius, 5.0);
}
}