use serde::{Deserialize, Serialize};
use crate::CalcError;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ThruHoleInput {
pub hole_diameter_mils: f64,
pub annular_ring_mils: f64,
pub isolation_width_mils: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ThruHoleResult {
pub pad_external_mils: f64,
pub pad_internal_signal_mils: f64,
pub pad_internal_plane_mils: f64,
}
pub fn thru_hole(input: &ThruHoleInput) -> Result<ThruHoleResult, CalcError> {
if input.hole_diameter_mils <= 0.0 {
return Err(CalcError::NegativeDimension {
name: "hole_diameter_mils",
value: input.hole_diameter_mils,
});
}
if input.annular_ring_mils < 0.0 {
return Err(CalcError::NegativeDimension {
name: "annular_ring_mils",
value: input.annular_ring_mils,
});
}
if input.isolation_width_mils < 0.0 {
return Err(CalcError::NegativeDimension {
name: "isolation_width_mils",
value: input.isolation_width_mils,
});
}
let pad_external_mils =
input.hole_diameter_mils + 2.0 * input.annular_ring_mils;
let pad_internal_signal_mils = pad_external_mils;
let pad_internal_plane_mils =
pad_external_mils + 2.0 * input.isolation_width_mils;
Ok(ThruHoleResult {
pad_external_mils,
pad_internal_signal_mils,
pad_internal_plane_mils,
})
}
pub fn corner_to_corner(a_mils: f64, b_mils: f64) -> Result<f64, CalcError> {
if a_mils < 0.0 {
return Err(CalcError::NegativeDimension {
name: "a_mils",
value: a_mils,
});
}
if b_mils < 0.0 {
return Err(CalcError::NegativeDimension {
name: "b_mils",
value: b_mils,
});
}
Ok((a_mils * a_mils + b_mils * b_mils).sqrt())
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
#[test]
fn saturn_page23_thru_hole_vector() {
let input = ThruHoleInput {
hole_diameter_mils: 32.0,
annular_ring_mils: 12.0,
isolation_width_mils: 12.0,
};
let result = thru_hole(&input).unwrap();
assert_relative_eq!(result.pad_external_mils, 56.0, epsilon = 1e-10);
assert_relative_eq!(result.pad_internal_signal_mils, 56.0, epsilon = 1e-10);
assert_relative_eq!(result.pad_internal_plane_mils, 80.0, epsilon = 1e-10);
}
#[test]
fn corner_to_corner_3_4_5() {
let d = corner_to_corner(3.0, 4.0).unwrap();
assert_relative_eq!(d, 5.0, epsilon = 1e-10);
}
#[test]
fn corner_to_corner_zero() {
let d = corner_to_corner(0.0, 0.0).unwrap();
assert_relative_eq!(d, 0.0, epsilon = 1e-10);
}
#[test]
fn error_on_zero_hole() {
let input = ThruHoleInput {
hole_diameter_mils: 0.0,
annular_ring_mils: 12.0,
isolation_width_mils: 12.0,
};
assert!(thru_hole(&input).is_err());
}
#[test]
fn error_on_negative_annular_ring() {
let input = ThruHoleInput {
hole_diameter_mils: 32.0,
annular_ring_mils: -1.0,
isolation_width_mils: 12.0,
};
assert!(thru_hole(&input).is_err());
}
#[test]
fn error_on_negative_corner_dimension() {
assert!(corner_to_corner(-1.0, 4.0).is_err());
assert!(corner_to_corner(3.0, -1.0).is_err());
}
}