1use super::{Point3,TargetRef,WorkOffset};
3use serde::{Deserialize,Serialize};
4#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
5#[derive(Clone,Copy,Debug,PartialEq,Eq,Serialize,Deserialize)]
6#[serde(rename_all="camelCase")]
7pub enum ProbeKind {SingleSurface,OutsideCorner,InsideCorner,Web,Pocket,Bore,Boss,Rectangle,Angle,Inspection}
8impl ProbeKind {
9 pub const VARIANTS: &'static [&'static str] = &["singleSurface","outsideCorner","insideCorner","web","pocket","bore","boss","rectangle","angle","inspection"];
11}
12#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
13#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)]
14#[serde(rename_all="camelCase")]
15pub struct ProbePoint {
16 pub id:String,
17 pub face:TargetRef,
18 pub position:Point3,
19 pub normal:Point3,
21 pub lower_tolerance:f64,
22 pub upper_tolerance:f64,
23}
24#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
25#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)]
26#[serde(rename_all="camelCase",default)]
27pub struct ProbeSettings {
28 pub stylus_radius:f64,
29 pub shank_radius:f64,
30 pub shank_length:f64,
32 pub approach_distance:f64,
33 pub overtravel:f64,
35 pub feed:f64,
36 pub result_prefix:String,
37}
38impl Default for ProbeSettings {fn default()->Self {Self {stylus_radius:1.,shank_radius:0.25,shank_length:20.,approach_distance:2.,overtravel:0.5,feed:100.,result_prefix:"probe".into()}}}
39#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
40#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)]
41#[serde(rename_all="camelCase",default)]
42pub struct ProbeWcsParams {
43 #[serde(rename="probeKind")]
45 pub kind:ProbeKind,
46 pub points:Vec<ProbePoint>,pub settings:ProbeSettings,pub wcs:WorkOffset}
47impl Default for ProbeWcsParams {fn default()->Self {Self {kind:ProbeKind::SingleSurface,points:Vec::new(),settings:ProbeSettings::default(),wcs:WorkOffset::default()}}}
48#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
49#[derive(Clone,Debug,PartialEq,Default,Serialize,Deserialize)]
50#[serde(rename_all="camelCase",default)]
51pub struct ProbeGeometryParams {pub points:Vec<ProbePoint>,pub settings:ProbeSettings}
52#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
55#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)]
56#[serde(rename_all="camelCase")]
57pub struct ProbeCycle {
58 pub target:Point3,
59 pub approach:Point3,
60 pub nominal:ProbePoint,
61 pub stylus_radius:f64,
62 pub overtravel:f64,
63 pub feed:f64,
64 pub kind:ProbeKind,
65 pub result_var:String,
66 pub point_index:u32,
67 pub point_count:u32,
68 pub wcs:Option<WorkOffset>,
70}
71impl ProbeSettings {
72 pub fn validate(&self)->Result<(),String> {
73 for v in [self.stylus_radius,self.shank_radius,self.shank_length,self.approach_distance,self.overtravel,self.feed] {if !v.is_finite()||v<=0. {return Err("probe dimensions, travel and feed must be finite and positive".into());}}
74 if self.shank_radius>=self.stylus_radius || self.shank_length<=self.stylus_radius || self.result_prefix.is_empty() || !self.result_prefix.bytes().all(|c|c.is_ascii_alphanumeric()||c==b'_') {return Err("invalid probe shank or result prefix".into());}Ok(())
75 }
76}
77impl ProbePoint {
78 pub fn validate(&self)->Result<(),String> {
79 if self.id.is_empty() || !self.id.bytes().all(|c|c.is_ascii_alphanumeric()||c==b'_') || self.face.solid.is_empty() || !self.position.is_finite() || !self.normal.is_finite() || (self.normal.length()-1.).abs()>1e-6 || !self.lower_tolerance.is_finite() || !self.upper_tolerance.is_finite() || self.lower_tolerance>self.upper_tolerance {return Err("invalid probe nominal point, normal, identity or tolerance".into());}Ok(())
80 }
81}
82impl ProbeWcsParams {pub fn validate(&self)->Result<(),String> {self.settings.validate()?;if self.kind==ProbeKind::Inspection || self.wcs.number==0 || !self.wcs.origin.is_finite() {return Err("invalid probing WCS intent".into());}validate_points(&self.points)}}
83impl ProbeGeometryParams {pub fn validate(&self)->Result<(),String> {self.settings.validate()?;validate_points(&self.points)}}
84fn validate_points(points:&[ProbePoint])->Result<(),String> {if points.is_empty()||points.len()>10000 {return Err("probe needs 1..10000 nominal points".into());}let mut ids=std::collections::BTreeSet::new();for p in points {p.validate()?;if !ids.insert(&p.id) {return Err("duplicate probe point identity".into());}}Ok(())}
85impl ProbeCycle {pub fn is_finite(&self)->bool {self.target.is_finite()&&self.approach.is_finite()&&self.nominal.validate().is_ok()&&self.stylus_radius.is_finite()&&self.stylus_radius>0.&&self.overtravel.is_finite()&&self.overtravel>0.&&self.feed.is_finite()&&self.feed>0.}}