1use crate::units::*;
2use once_cell::sync::Lazy;
3use std::sync::Mutex;
4
5#[derive(Debug, Copy, Clone)]
6pub enum CapType {
7 Butt,
8 Round,
9 Square,
10}
11
12impl CapType {
13 pub fn to_int(&self) -> i32 {
14 match self {
15 CapType::Butt => 0,
16 CapType::Round => 1,
17 CapType::Square => 2,
18 }
19 }
20}
21
22#[derive(Debug, Clone, Copy)]
23pub enum Anchor {
24 Center,
25 North,
26 South,
27 East,
28 West,
29 NorthEast,
30 NorthWest,
31 SouthEast,
32 SouthWest,
33 Point(f64, f64),
34}
35
36impl Default for Anchor {
37 fn default() -> Self {
38 Anchor::SouthWest
39 }
40}
41
42#[derive(Debug, Clone, Copy)]
43pub enum ShapeType {
44 Line,
45 Circle,
46 Rectangle,
47 Polygon,
48 Unknown,
49}
50
51impl Default for ShapeType {
52 fn default() -> Self {
53 ShapeType::Unknown
54 }
55}
56
57#[derive(Debug, Default)]
62pub struct Shape<'a> {
63 pub enum_type: ShapeType,
64 pub content_stream: Option<&'a mut Vec<u8>>,
65 pub x: Vec<f64>,
66 pub y: Vec<f64>,
67 pub width: Option<f64>,
68 pub radius: Option<f64>,
69 pub angle: Option<f64>, pub anchor: Option<Anchor>,
71 pub cap_type: Option<CapType>,
72 pub color: Option<(f64, f64, f64)>,
73}
74
75static DEFAULT_WIDTH: Lazy<Mutex<f64>> = Lazy::new(|| Pt(1.).to_points().into());
76static DEFAULT_CAP_TYPE: Lazy<Mutex<CapType>> = Lazy::new(|| CapType::Butt.into());
77static DEFAULT_COLOR: Lazy<Mutex<(f64, f64, f64)>> =
78 Lazy::new(|| NamedColor("black").to_rgb().into());
79static DEFAULT_ANGLE: Lazy<Mutex<f64>> = Lazy::new(|| Degree(0.).to_degrees().into());
80static DEFAULT_ANCHOR: Lazy<Mutex<Anchor>> = Lazy::new(|| Anchor::SouthWest.into());
81
82impl<'a> Shape<'a> {
83 pub fn draw(&mut self) {
84 if let Some(content) = self.content_stream.as_mut() {
85 let (r, g, b) = self.color.unwrap_or(*DEFAULT_COLOR.lock().unwrap());
86 let width = self.width.unwrap_or(*DEFAULT_WIDTH.lock().unwrap());
87 let cap_type = self
88 .cap_type
89 .unwrap_or(*DEFAULT_CAP_TYPE.lock().unwrap())
90 .to_int();
91 match self.enum_type {
92 ShapeType::Line => {
93 content.extend_from_slice(format!("{} {} {} RG\n", r, g, b).as_bytes());
94 content.extend_from_slice(
95 format!(
96 "{} w\n{} J\n{} {} m\n{} {} l\nS\n",
97 width, cap_type, self.x[0], self.y[0], self.x[1], self.y[1]
98 )
99 .as_bytes(),
100 );
101 }
102 ShapeType::Circle => {
103 content.extend_from_slice(format!("{} {} {} RG\n", r, g, b).as_bytes());
104 content.extend_from_slice(
105 format!(
107 "{} w\n1 J\n{} {} m\n{} {} l\nS\n",
108 self.radius.unwrap() * 2.0,
109 self.x[0],
110 self.y[0],
111 self.x[0],
112 self.y[0]
113 )
114 .as_bytes(),
115 );
116 }
117 ShapeType::Rectangle => {
118 content.extend_from_slice(format!("{} {} {} rg\n", r, g, b).as_bytes());
119 let angle = self.angle.unwrap_or(*DEFAULT_ANGLE.lock().unwrap());
120 let cos_theta = angle.cos();
121 let sin_theta = angle.sin();
122 let (width, height) = (self.x[1], self.y[1]);
123 let (cx, cy) = (self.x[0], self.y[0]);
125 let (x0, y0) = match self.anchor.unwrap_or(*DEFAULT_ANCHOR.lock().unwrap()) {
127 Anchor::Center => (self.x[0] - width / 2.0, self.y[0] - height / 2.0),
128 Anchor::North => (self.x[0] - width / 2.0, self.y[0] - height),
129 Anchor::South => (self.x[0] - width / 2.0, self.y[0]),
130 Anchor::East => (self.x[0] - width, self.y[0] - height / 2.0),
131 Anchor::West => (self.x[0], self.y[0] - height / 2.0),
132 Anchor::NorthEast => (self.x[0] - width, self.y[0] - height),
133 Anchor::NorthWest => (self.x[0], self.y[0] - height),
134 Anchor::SouthEast => (self.x[0] - width, self.y[0]),
135 Anchor::SouthWest => (self.x[0], self.y[0]),
136 Anchor::Point(px, py) => (px, py),
137 };
138 let translate_x = cx - cos_theta * cx + sin_theta * cy;
139 let translate_y = cy - sin_theta * cx - cos_theta * cy;
140 content.extend_from_slice(
141 format!(
142 "{} {} {} {} {} {} cm\n{} {} {} {} re f\n",
143 cos_theta,
144 sin_theta,
145 -sin_theta,
146 cos_theta,
147 translate_x,
148 translate_y,
149 x0,
150 y0,
151 width,
152 height
153 )
154 .as_bytes(),
155 );
156 }
157 _ => {}
158 };
159 }
160 }
161
162 pub fn with_width(&mut self, width: impl Length) -> &mut Self {
164 self.width = Some(width.to_points());
165 self
166 }
167
168 pub fn with_angle(&mut self, angle: impl Angle) -> &mut Self {
169 self.angle = Some(angle.to_radians());
170 self
171 }
172
173 pub fn with_anchor(&mut self, anchor: Anchor) -> &mut Self {
174 self.anchor = Some(anchor);
175 self
176 }
177
178 pub fn with_cap_type(&mut self, cap_type: CapType) -> &mut Self {
179 self.cap_type = Some(cap_type);
180 self
181 }
182
183 pub fn with_color(&mut self, color: impl Color) -> &mut Self {
184 self.color = Some(color.to_rgb());
185 self
186 }
187
188 pub fn get_default_width() -> Pt {
189 Pt(*DEFAULT_WIDTH.lock().unwrap())
190 }
191
192 pub fn set_default_width(width: impl Length) {
193 *DEFAULT_WIDTH.lock().unwrap() = width.to_points();
194 }
195
196 pub fn get_default_cap_type() -> CapType {
197 *DEFAULT_CAP_TYPE.lock().unwrap()
198 }
199
200 pub fn set_default_cap_type(cap_type: CapType) {
201 *DEFAULT_CAP_TYPE.lock().unwrap() = cap_type;
202 }
203
204 pub fn get_default_color() -> Rgb {
205 let (r, g, b) = *DEFAULT_COLOR.lock().unwrap();
206 Rgb(r, g, b)
207 }
208
209 pub fn set_default_color(color: impl Color) {
210 *DEFAULT_COLOR.lock().unwrap() = color.to_rgb();
211 }
212
213 pub fn get_default_angle() -> Degree {
214 Degree(*DEFAULT_ANGLE.lock().unwrap())
215 }
216
217 pub fn set_default_angle(angle: impl Angle) {
218 *DEFAULT_ANGLE.lock().unwrap() = angle.to_radians();
219 }
220
221 pub fn get_default_anchor() -> Anchor {
222 *DEFAULT_ANCHOR.lock().unwrap()
223 }
224
225 pub fn set_default_anchor(anchor: Anchor) {
226 *DEFAULT_ANCHOR.lock().unwrap() = anchor;
227 }
228}