1use std::io;
2
3pub mod hp7470a;
4
5pub trait PlotterWriteable {
6 fn write<W>(&self, sink: &mut W) -> io::Result<()>
7 where
8 W: io::Write;
9}
10
11#[derive(Debug)]
12pub struct HpglProgram(Vec<HpglCommand>);
13impl HpglProgram {
14 pub fn new(commands: Vec<HpglCommand>) -> Self {
15 Self(commands)
16 }
17}
18
19impl PlotterWriteable for HpglProgram {
20 fn write<W>(&self, sink: &mut W) -> io::Result<()>
21 where
22 W: io::Write,
23 {
24 self.0
25 .iter()
26 .map(|command| command.write(sink))
27 .collect::<_>()
28 }
29}
30
31impl From<Vec<HpglCommand>> for HpglProgram {
32 fn from(inner: Vec<HpglCommand>) -> Self {
33 Self(inner)
34 }
35}
36
37#[derive(Clone, Copy, Debug)]
41pub struct Coordinate {
42 pub x: f32,
43 pub y: f32,
44}
45impl Coordinate {
46 pub const MAX_X_A4: f32 = 10900.;
47 pub const MAX_X_US: f32 = 10300.;
48 pub const MAX_Y: f32 = 7650.;
49}
50
51#[derive(Debug)]
52pub struct CoordinateChain(pub Vec<Coordinate>);
53
54impl CoordinateChain {
55 pub fn write<W>(&self, sink: &mut W) -> io::Result<()>
56 where
57 W: io::Write,
58 {
59 let mut iter = self.0.iter().peekable();
60 while let Some(coord) = iter.next() {
61 write!(sink, "{},{}", coord.x, coord.y)?;
62 if let Some(_) = iter.peek() {
63 write!(sink, ",")?;
64 }
65 }
66
67 Ok(())
68 }
69}
70
71impl From<Vec<Coordinate>> for CoordinateChain {
72 fn from(inner: Vec<Coordinate>) -> Self {
73 Self(inner)
74 }
75}
76
77impl From<Coordinate> for CoordinateChain {
78 fn from(inner: Coordinate) -> Self {
79 Self(vec![inner])
80 }
81}
82
83#[derive(Debug)]
84pub enum HpglCommand {
85 DefaultSettings,
86 InitializePlotter,
87 SelectPen {
88 pen: usize,
89 },
90 VelocitySelect {
91 velocity: f32,
92 },
93 PenUp,
95 PenDown,
97 PlotAbsolute(CoordinateChain),
98}
99
100impl PlotterWriteable for HpglCommand {
101 fn write<W>(&self, sink: &mut W) -> io::Result<()>
102 where
103 W: io::Write,
104 {
105 use HpglCommand::*;
106 match self {
107 DefaultSettings => {
108 sink.write(b"DF;")?;
109 }
110 InitializePlotter => {
111 sink.write(b"IN;")?;
112 }
113 SelectPen { pen } => {
114 sink.write(b"SP")?;
115 write!(sink, "{}", pen)?;
116 sink.write(b";")?;
117 }
118 VelocitySelect { velocity } => {
119 sink.write(b"VS")?;
120 write!(sink, "{}", velocity)?;
121 sink.write(b";")?;
122 }
123 PenUp => {
124 sink.write(b"PU;")?;
125 }
126 PenDown => {
127 sink.write(b"PD;")?;
128 }
129 PlotAbsolute(coord) => {
130 sink.write(b"PA")?;
131 coord.write(sink)?;
132 sink.write(b";")?;
133 }
134 }
135
136 Ok(())
137 }
138}
139
140#[cfg(test)]
141mod test {
142 use super::*;
143
144 #[test]
145 fn single_point_in_chain() {
146 let chain: CoordinateChain = vec![Coordinate { x: 69., y: 420. }].into();
147 let mut buf: Vec<u8> = Vec::new();
148
149 chain.write(&mut buf).unwrap();
150 assert_eq!(buf, b"69,420");
151 }
152
153 #[test]
154 fn multipoint_in_chain() {
155 let chain: CoordinateChain = vec![
156 Coordinate { x: 69., y: 420. },
157 Coordinate { x: 666., y: 69. },
158 ]
159 .into();
160 let mut buf: Vec<u8> = Vec::new();
161
162 chain.write(&mut buf).unwrap();
163 assert_eq!(buf, b"69,420,666,69");
164 }
165}