1use dyn_clone::DynClone;
4use geo::{Coordinate, MultiPolygon};
5use std::fmt;
6
7mod array;
8mod circle;
9mod mechanical_solder_point;
10mod negative;
11mod pos;
12mod r_mount;
13mod rect;
14pub mod repeating;
15mod rotate;
16mod screw_hole;
17mod smiley;
18mod triangle;
19mod unit;
20pub use array::Column;
21pub use circle::Circle;
22pub use mechanical_solder_point::MechanicalSolderPoint;
23pub use negative::Negative;
24pub use pos::{AtPos, Positioning};
25pub use r_mount::RMount;
26pub use rect::Rect;
27pub use rotate::Rotate;
28pub use screw_hole::ScrewHole;
29pub use smiley::Smiley;
30pub use triangle::Triangle;
31pub use unit::Unit;
32
33pub trait InnerFeature: fmt::Display + DynClone + fmt::Debug {
35 fn name(&self) -> &'static str;
36 fn translate(&mut self, v: Coordinate<f64>);
37 fn atoms(&self) -> Vec<InnerAtom>;
38}
39
40dyn_clone::clone_trait_object!(InnerFeature);
41
42impl<'a> InnerFeature for Box<dyn InnerFeature + 'a> {
43 fn name(&self) -> &'static str {
44 self.as_ref().name()
45 }
46
47 fn translate(&mut self, v: Coordinate<f64>) {
48 self.as_mut().translate(v)
49 }
50
51 fn atoms(&self) -> Vec<InnerAtom> {
52 self.as_ref().atoms()
53 }
54}
55
56pub trait Feature: fmt::Display + DynClone + fmt::Debug {
58 fn name(&self) -> &'static str;
60 fn translate(&mut self, v: Coordinate<f64>);
64
65 fn edge_union(&self) -> Option<MultiPolygon<f64>>;
69
70 fn interior(&self) -> Vec<InnerAtom>;
73
74 fn edge_subtract(&self) -> Option<MultiPolygon<f64>> {
78 None
79 }
80}
81
82dyn_clone::clone_trait_object!(Feature);
83
84impl<'a> Feature for Box<dyn Feature + 'a> {
85 fn name(&self) -> &'static str {
86 self.as_ref().name()
87 }
88
89 fn translate(&mut self, v: Coordinate<f64>) {
90 self.as_mut().translate(v)
91 }
92
93 fn edge_union(&self) -> Option<MultiPolygon<f64>> {
94 self.as_ref().edge_union()
95 }
96
97 fn interior(&self) -> Vec<InnerAtom> {
98 self.as_ref().interior()
99 }
100
101 fn edge_subtract(&self) -> Option<MultiPolygon<f64>> {
102 self.as_ref().edge_subtract()
103 }
104}
105
106#[derive(Debug, Clone)]
108pub enum InnerAtom {
109 Drill {
110 center: Coordinate<f64>,
111 radius: f64,
112 plated: bool,
113 },
114 Circle {
115 center: Coordinate<f64>,
116 radius: f64,
117 layer: super::Layer,
118 },
119 Rect {
120 rect: geo::Rect<f64>,
121 layer: super::Layer,
122 },
123 VScoreH(f64),
124 VScoreV(f64),
125}
126
127impl InnerAtom {
128 pub fn stroke(&self) -> Option<usvg::Stroke> {
129 match self {
130 InnerAtom::VScoreH(_) | InnerAtom::VScoreV(_) => Some(usvg::Stroke {
131 paint: usvg::Paint::Color(usvg::Color::new(0x6, 0x6, 0x6)),
132 width: usvg::StrokeWidth::new(0.1),
133 opacity: usvg::Opacity::new(0.5),
134 dasharray: Some(vec![0.8, 0.8]),
135 ..usvg::Stroke::default()
136 }),
137 _ => None,
138 }
139 }
140
141 pub fn fill(&self) -> Option<usvg::Fill> {
142 match self {
143 InnerAtom::Drill { .. } => Some(usvg::Fill {
144 paint: usvg::Paint::Color(usvg::Color::new(0x25, 0x25, 0x25)),
145 ..usvg::Fill::default()
146 }),
147 InnerAtom::Circle { layer, .. } => Some(usvg::Fill {
148 paint: usvg::Paint::Color(layer.color()),
149 ..usvg::Fill::default()
150 }),
151 InnerAtom::Rect { layer, .. } => Some(usvg::Fill {
152 paint: usvg::Paint::Color(layer.color()),
153 ..usvg::Fill::default()
154 }),
155 InnerAtom::VScoreH(_) | InnerAtom::VScoreV(_) => None,
156 }
157 }
158
159 pub fn bounds(&self) -> Option<geo::Rect<f64>> {
160 match self {
161 InnerAtom::Drill { center, radius, .. } => Some(geo::Rect::new(
162 Coordinate {
163 x: center.x - radius,
164 y: center.y - radius,
165 },
166 Coordinate {
167 x: center.x + radius,
168 y: center.y + radius,
169 },
170 )),
171 InnerAtom::Circle { center, radius, .. } => Some(geo::Rect::new(
172 Coordinate {
173 x: center.x - radius,
174 y: center.y - radius,
175 },
176 Coordinate {
177 x: center.x + radius,
178 y: center.y + radius,
179 },
180 )),
181 InnerAtom::Rect { rect, .. } => Some(rect.clone()),
182 InnerAtom::VScoreH(_) | InnerAtom::VScoreV(_) => None,
183 }
184 }
185
186 pub fn translate(&mut self, x: f64, y: f64) {
187 match self {
188 InnerAtom::Drill { ref mut center, .. } => {
189 *center = *center + Coordinate { x, y };
190 }
191 InnerAtom::Circle { center, .. } => {
192 *center = *center + Coordinate { x, y };
193 }
194 InnerAtom::Rect { rect, .. } => {
195 use geo::algorithm::translate::Translate;
196 rect.translate_inplace(x, y);
197 }
198 InnerAtom::VScoreH(ref mut y2) => {
199 *y2 = *y2 + y;
200 }
201 InnerAtom::VScoreV(ref mut x2) => {
202 *x2 = *x2 + x;
203 }
204 }
205 }
206}