1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! Shared types used by cnccoder, such as Vector2, Vector3, Units, Direction, Axis and Bounds.

use std::fmt;

use serde::{Deserialize, Serialize};

mod vector;
pub use vector::*;

/// Represents an area in 3D space from one min and one max [Vector3](struct.Vector3.html) point.
#[derive(Default, Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
pub struct Bounds {
    /// Minimum 3D point of the boundary.
    pub min: Vector3,
    /// Maximum 3D point of the boundary.
    pub max: Vector3,
}

impl Bounds {
    /// Create a `Bounds` struct starting at xyz 0.0 and ending at the given xyz coordinates.
    #[must_use]
    pub fn new(x: f64, y: f64, z: f64) -> Self {
        Self {
            min: Vector3::new(0.0, 0.0, 0.0),
            max: Vector3::new(x, y, z),
        }
    }

    /// Create a `Bounds` struct using xyz `f64::MIN` as min and `f64::MAX` for max.
    #[must_use]
    pub fn minmax() -> Self {
        Self {
            min: Vector3::max(),
            max: Vector3::min(),
        }
    }

    /// Return the size of the bounds area as a [Vector3](struct.Vector3.html).
    #[must_use]
    pub fn size(&self) -> Vector3 {
        Vector3::new(
            self.max.x - self.min.x,
            self.max.y - self.min.y,
            self.max.z - self.min.z,
        )
    }
}

/// Indicates if metric or imperial units should be used. This is used as a setting both for a
/// [Program](../program/struct.Program.html) and [tools](../tools/).
#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
#[serde(rename_all = "lowercase")]
pub enum Units {
    /// Indicates that measurements are given using millimeters.
    #[default]
    Metric,
    /// Indicates that measurements are given using inches.
    Imperial,
}

impl Units {
    /// Converts from millimeters to inches
    pub fn mm_to_inch(mm: f64) -> f64 {
        mm * 25.4
    }

    /// Converts a measurement from the selected unit to millimeters
    pub fn measurement_from_mm(self, value: f64) -> f64 {
        match self {
            Self::Metric => value,
            Self::Imperial => Self::mm_to_inch(value),
        }
    }

    /// Provides default z_end value, what the CNC should consider as the vertical bottom value
    /// by default, either as millimeters or inches.
    pub fn default_z_end(self) -> f64 {
        match self {
            Self::Metric => 0.1,
            Self::Imperial => Self::mm_to_inch(0.1),
        }
    }

    /// Provides default z_max_step value. As the CNC machine cuts a path it will often be
    /// instructed to cut the path in several passes instead of cutting the full depth at once.
    /// This function provides a default value as millimeters or inches.
    pub fn default_z_max_step(self) -> f64 {
        match self {
            Self::Metric => 1.0,
            Self::Imperial => Self::mm_to_inch(1.0),
        }
    }
}

impl fmt::Display for Units {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "{}",
            match self {
                Units::Metric => "mm",
                Units::Imperial => "\"",
            }
        )
    }
}

/// Indicates a rotation direction, this is used by the [tools](../tools/), but also when cutting [arcs](../cuts/struct.Arc.html).
#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
#[serde(rename_all = "lowercase")]
pub enum Direction {
    /// Clockwise direction.
    #[default]
    Clockwise,
    /// Counter clockwise direction.
    Counterclockwise,
}

impl fmt::Display for Direction {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "{}",
            match self {
                Direction::Clockwise => "clockwise",
                Direction::Counterclockwise => "counterclockwise",
            }
        )
    }
}

/// Indicates one specific axis, mainy when cutting [arcs](../cuts/struct.Arc.html).
#[derive(Debug, Clone)]
pub enum Axis {
    /// Indicates X axis.
    X,
    /// Indicates Y axis.
    Z,
    /// Indicates Z axis.
    Y,
}

impl fmt::Display for Axis {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "{}",
            match self {
                Axis::X => "X",
                Axis::Y => "Y",
                Axis::Z => "Z",
            }
        )
    }
}

/// Indicates how a path should be compensated by the radius of the tool.
#[derive(Debug, Clone, Default)]
pub enum ToolPathCompensation {
    /// The tool will cut at the specified path, without compensating for the radius. This is the default value.
    #[default]
    None,
    /// The tool will cut at the inside of the path, this is useful for pocket cuts.
    Inner,
    /// The tool will cut at the outside of the path, this is useful for contour/frame cuts.
    Outer,
}

impl fmt::Display for ToolPathCompensation {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "{}",
            match self {
                ToolPathCompensation::None => "none",
                ToolPathCompensation::Inner => "inner",
                ToolPathCompensation::Outer => "outer",
            }
        )
    }
}