1use std::f64::EPSILON;
4
5use {Adjust, Bound, BoundingBox};
6
7pub use layout::NetName;
8
9use checkfix::{CheckFix, CheckFixData, Config};
10
11use symbolic_expressions::SexpError;
12
13pub trait Flip {
15 fn flip(&mut self);
17}
18
19pub trait Rotate {
21 fn rotate(&mut self, rot: f64);
23}
24
25#[derive(Debug, Clone)]
27pub struct Module {
28 pub name: String,
30 pub elements: Vec<Element>,
32}
33
34trait Named {
35 fn name(&self) -> &'static str;
36}
37
38impl Module {
39 pub fn new(name: String) -> Module {
41 Module {
42 name: name,
43 elements: vec![],
44 }
45 }
46 pub fn append(&mut self, e: Element) {
48 self.elements.push(e)
49 }
50 pub fn is_reference_with_name(&self, reference: &str) -> bool {
52 for element in &self.elements {
53 if let Element::FpText(ref fp_text) = *element {
54 if fp_text.name == "reference" && fp_text.value == *reference {
55 return true;
56 }
57 }
58 }
59 false
60 }
61
62 pub fn get_reference(&self) -> Option<&String> {
64 self.get_reference_text().map(|a| &a.value)
65 }
66
67 pub fn get_text(&self, which: &'static str) -> Option<&FpText> {
69 for element in &self.elements {
70 if let Element::FpText(ref fp_text) = *element {
71 if fp_text.name == which {
72 return Some(fp_text);
73 }
74 }
75 }
76 None
77 }
78
79 pub fn get_text_mut(&mut self, which: &'static str) -> Option<&mut FpText> {
81 for element in &mut self.elements {
82 if let Element::FpText(ref mut fp_text) = *element {
83 if fp_text.name == which {
84 return Some(fp_text);
85 }
86 }
87 }
88 None
89 }
90
91 pub fn get_reference_text(&self) -> Option<&FpText> {
93 self.get_text("reference")
94 }
95
96 pub fn get_reference_text_mut(&mut self) -> Option<&mut FpText> {
98 self.get_text_mut("reference")
99 }
100
101 pub fn get_reference2_text(&self) -> Option<&FpText> {
103 self.get_text("user")
104 }
105
106 pub fn get_reference2_text_mut(&mut self) -> Option<&mut FpText> {
108 self.get_text_mut("user")
109 }
110
111 pub fn get_value_text_mut(&mut self) -> Option<&mut FpText> {
113 self.get_text_mut("value")
114 }
115
116
117 pub fn has_smd_attr(&self) -> bool {
119 for element in &self.elements {
120 if let Element::Attr(ref attr) = *element {
121 if attr.as_str() == "smd" {
122 return true;
123 }
124 }
125 }
126 false
127 }
128
129 pub fn get_value_text(&self) -> Option<&FpText> {
131 self.get_text("value")
132 }
133
134 pub fn get_tstamp(&self) -> Option<i64> {
136 for element in &self.elements {
137 if let Element::TStamp(stamp) = *element {
138 return Some(stamp);
139 }
140 }
141 None
142 }
143
144 pub fn get_tedit(&self) -> Option<i64> {
146 for element in &self.elements {
147 if let Element::TEdit(stamp) = *element {
148 return Some(stamp);
149 }
150 }
151 None
152 }
153
154 pub fn set_reference(&mut self, reference: &str, reference2: &str) {
156 for element in &mut self.elements {
158 if let Element::FpText(ref mut fp_text) = *element {
159 if fp_text.name == "reference" && fp_text.value == *reference {
160 fp_text.value.clear();
161 fp_text.value.push_str(reference2);
162 }
163 }
164 }
165 }
166 pub fn at(&self) -> (f64, f64) {
169 for element in &self.elements {
170 if let Element::At(ref at) = *element {
171 return (at.x, at.y);
172 }
173 }
174 (0.0, 0.0)
175 }
176
177 pub fn get_rotation(&self) -> f64 {
180 for element in &self.elements {
181 if let Element::At(ref at) = *element {
182 return at.rot;
183 }
184 }
185 0.0
186 }
187
188 pub fn adjust_at(&mut self, x: f64, y: f64) {
190 for element in &mut self.elements {
191 if let Element::At(ref mut at) = *element {
192 at.x += x;
193 at.y += y;
194 }
195 }
196 }
197
198 pub fn is_front(&self) -> bool {
200 for element in &self.elements {
201 if let Element::Layer(ref layer) = *element {
202 return layer.side == LayerSide::Front;
203 }
204 }
205 true
206 }
207
208 pub fn rename_net(&mut self, old_name: &str, new_name: &str) {
210 for element in &mut self.elements {
211 if let Element::Pad(ref mut pad) = *element {
212 pad.rename_net(old_name, new_name)
213 }
214 }
215 }
216
217 pub fn pads(&self) -> Vec<&Pad> {
219 let mut v = vec![];
220 for element in &self.elements {
221 if let Element::Pad(ref pad) = *element {
222 v.push(pad)
223 }
224 }
225 v
226 }
227
228 pub fn lines(&self) -> Vec<&FpLine> {
230 let mut v = vec![];
231 for element in &self.elements {
232 if let Element::FpLine(ref line) = *element {
233 v.push(line)
234 }
235 }
236 v
237 }
238}
239
240impl BoundingBox for Module {
241 fn bounding_box(&self) -> Bound {
242 let (x, y) = self.at();
243 let mut b = Bound::new(x, y, x, y);
244 for element in self.elements.iter().filter(|&x| x.is_graphics()) {
245 if element.is_fab() || element.is_pad() {
246 let mut b2 = element.bounding_box();
247 b2.x1 += x;
249 b2.y1 += y;
250 b2.x2 += x;
251 b2.y2 += y;
252 b.update(&b2);
254 }
255 }
256 b.swap_if_needed();
257 b
259 }
260}
261
262impl Adjust for Module {
263 fn adjust(&mut self, x: f64, y: f64) {
264 self.adjust_at(x, y)
265 }
266}
267
268impl Flip for Module {
269 fn flip(&mut self) {
270 for e in &mut self.elements {
271 e.flip()
272 }
273 }
274}
275
276impl Rotate for Module {
277 fn rotate(&mut self, rot: f64) {
278 for e in &mut self.elements {
279 e.rotate(rot)
280 }
281 }
282}
283
284#[derive(Debug, Clone, PartialEq)]
286pub enum Element {
287 SolderMaskMargin(f64),
289 Layer(Layer),
291 Descr(String),
293 Tags(String),
295 Attr(String),
297 FpText(FpText),
299 Pad(Pad),
301 FpPoly(FpPoly),
303 FpLine(FpLine),
305 FpCircle(FpCircle),
307 FpArc(FpArc),
309 TEdit(i64),
311 TStamp(i64),
313 Path(String),
315 At(At),
317 Model(Model),
319 Clearance(f64),
321 Locked,
323}
324
325impl BoundingBox for Element {
326 fn bounding_box(&self) -> Bound {
327 match *self {
328 Element::Pad(ref x) => x.bounding_box(),
329 Element::FpPoly(ref x) => x.bounding_box(),
330 Element::FpLine(ref x) => x.bounding_box(),
331 Element::FpCircle(ref x) => x.bounding_box(),
332 Element::FpText(ref x) => x.bounding_box(),
333 Element::FpArc(ref x) => x.bounding_box(),
334 Element::At(_) |
335 Element::Layer(_) |
336 Element::TEdit(_) |
337 Element::Descr(_) |
338 Element::Path(_) |
339 Element::Model(_) |
340 Element::Attr(_) |
341 Element::SolderMaskMargin(_) |
342 Element::Clearance(_) |
343 Element::Tags(_) |
344 Element::Locked |
345 Element::TStamp(_) => Bound::default(),
346 }
347 }
348}
349
350impl Named for Element {
351 fn name(&self) -> &'static str {
352 match *self {
353 Element::Pad(_) => "Pad",
354 Element::FpPoly(_) => "FpPoly",
355 Element::FpLine(_) => "FpLine",
356 Element::FpCircle(_) => "FpCircle",
357 Element::FpArc(_) => "FpArc",
358 Element::FpText(_) => "FpText",
359 Element::At(_) => "At",
360 Element::Layer(_) => "Layer",
361 Element::TEdit(_) => "TEdit",
362 Element::Descr(_) => "Descr",
363 Element::Path(_) => "Path",
364 Element::Model(_) => "Model",
365 Element::TStamp(_) => "Tstamp",
366 Element::SolderMaskMargin(_) => "SolderMaskMargin",
367 Element::Clearance(_) => "Clearance",
368 Element::Tags(_) => "Tags",
369 Element::Attr(_) => "Attr",
370 Element::Locked => "Locked",
371 }
372 }
373}
374
375impl Flip for Element {
376 fn flip(&mut self) {
377 match *self {
378 Element::Pad(ref mut p) => p.flip(),
379 Element::FpPoly(ref mut p) => p.flip(),
380 Element::FpLine(ref mut p) => p.flip(),
381 Element::FpCircle(ref mut p) => p.flip(),
382 Element::FpArc(ref mut p) => p.flip(),
383 Element::FpText(ref mut p) => p.flip(),
384 Element::At(ref mut p) => p.flip(),
385 Element::Layer(ref mut p) => p.flip(),
386 Element::TEdit(_) |
387 Element::Descr(_) |
388 Element::Path(_) |
389 Element::Model(_) |
390 Element::TStamp(_) |
391 Element::SolderMaskMargin(_) |
392 Element::Clearance(_) |
393 Element::Tags(_) |
394 Element::Attr(_) |
395 Element::Locked => (),
396 }
397 }
398}
399
400impl Rotate for Element {
401 fn rotate(&mut self, rot: f64) {
402 match *self {
403 Element::Pad(ref mut p) => p.rotate(rot),
404 Element::FpText(ref mut p) => p.rotate(rot),
405 Element::At(ref mut p) => p.rotate(rot),
406 Element::FpPoly(_) |
407 Element::FpLine(_) |
408 Element::FpCircle(_) |
409 Element::FpArc(_) |
410 Element::Layer(_) |
411 Element::TEdit(_) |
412 Element::Descr(_) |
413 Element::Path(_) |
414 Element::Model(_) |
415 Element::TStamp(_) |
416 Element::SolderMaskMargin(_) |
417 Element::Clearance(_) |
418 Element::Tags(_) |
419 Element::Attr(_) |
420 Element::Locked => (),
421 }
422 }
423}
424
425impl Element {
426 fn is_graphics(&self) -> bool {
427 match *self {
428 Element::Pad(_) |
429 Element::FpPoly(_) |
430 Element::FpLine(_) |
431 Element::FpCircle(_) |
432 Element::FpArc(_) => true,
433 Element::FpText(_) |
434 Element::At(_) |
435 Element::Layer(_) |
436 Element::TEdit(_) |
437 Element::Descr(_) |
438 Element::Path(_) |
439 Element::Model(_) |
440 Element::TStamp(_) |
441 Element::SolderMaskMargin(_) |
442 Element::Clearance(_) |
443 Element::Tags(_) |
444 Element::Attr(_) |
445 Element::Locked => false,
446 }
447 }
448
449 fn is_fab(&self) -> bool {
450 match *self {
451 Element::FpPoly(ref e) => e.is_fab(),
452 Element::FpLine(ref e) => e.is_fab(),
453 Element::FpCircle(ref e) => e.is_fab(),
454 Element::FpArc(ref e) => e.is_fab(),
455 Element::Pad(_) |
456 Element::FpText(_) |
457 Element::At(_) |
458 Element::Layer(_) |
459 Element::TEdit(_) |
460 Element::Descr(_) |
461 Element::Path(_) |
462 Element::Model(_) |
463 Element::TStamp(_) |
464 Element::SolderMaskMargin(_) |
465 Element::Clearance(_) |
466 Element::Tags(_) |
467 Element::Attr(_) |
468 Element::Locked => false,
469 }
470 }
471
472 fn is_pad(&self) -> bool {
473 if let Element::Pad(_) = *self {
474 true
475 } else {
476 false
477 }
478 }
479}
480
481#[derive(Debug, Clone)]
483pub struct FpText {
484 pub name: String,
486 pub value: String,
488 pub at: At,
490 pub layer: Layer,
492 pub effects: Effects,
494 pub hide: bool,
496}
497
498impl Flip for FpText {
499 fn flip(&mut self) {
500 self.at.flip();
501 self.layer.flip();
502 self.effects.flip();
503 }
504}
505
506impl Rotate for FpText {
507 fn rotate(&mut self, rot: f64) {
508 self.at.rotate(rot)
509 }
510}
511
512impl PartialEq for FpText {
513 fn eq(&self, other: &FpText) -> bool {
514 if self.name == "reference" && other.name == "reference" {
515 return true;
516 }
517 if self.name == "value" && other.name == "value" {
518 return true;
519 }
520 if self.at != other.at {
521 return false;
522 }
523 if self.name != other.name {
524 return false;
525 }
526 if self.value != other.value {
527 return false;
528 }
529 if self.at != other.at {
530 return false;
531 }
532 if self.layer != other.layer {
533 return false;
534 }
535 if self.effects != other.effects {
536 return false;
537 }
538 if self.hide != other.hide {
539 return false;
540 }
541 true
542 }
543}
544
545impl BoundingBox for FpText {
546 fn bounding_box(&self) -> Bound {
547 let (x, y) = (self.at.x, self.at.y);
548 debug!("bound for FpText is poor");
549 Bound::new(x, y, x, y)
550 }
551}
552
553impl FpText {
554 pub fn new(name: String, value: String) -> FpText {
556 FpText {
557 name: name,
558 value: value,
559 at: At::default(),
560 layer: Layer::default(),
561 effects: Effects::default(),
562 hide: false,
563 }
564 }
565 pub fn set_effects(&mut self, effects: &Effects) {
567 self.effects.clone_from(effects)
568 }
569 pub fn set_layer(&mut self, layer: &Layer) {
571 self.layer.clone_from(layer)
572 }
573}
574
575#[derive(Debug, Clone, Default, PartialEq)]
577pub struct At {
578 pub x: f64,
580 pub y: f64,
582 pub rot: f64,
584}
585
586impl Flip for At {
587 fn flip(&mut self) {
588 self.y = -self.y;
589 self.rot = 360.0 - self.rot;
590 }
591}
592
593impl Adjust for At {
594 fn adjust(&mut self, x: f64, y: f64) {
595 self.x += x;
596 self.y += y
597 }
598}
599
600impl At {
601 pub fn new(x: f64, y: f64, rot: f64) -> At {
603 At {
604 x: x,
605 y: y,
606 rot: rot,
607 }
608 }
609}
610
611impl Rotate for At {
612 fn rotate(&mut self, rot: f64) {
613 self.rot += rot;
614 if self.rot >= 360.0 {
615 self.rot -= 360.0
616 }
617 if self.rot < 0.0 {
618 self.rot += 360.0
619 }
620 }
621}
622
623#[derive(Debug, Clone, Default, PartialEq)]
625pub struct Font {
626 pub size: Xy,
628 pub thickness: f64,
630 pub italic: bool,
632}
633
634#[derive(Debug, Clone, Default, PartialEq)]
636pub struct Effects {
637 pub font: Font,
639 pub justify: Option<Justify>,
641}
642
643impl Flip for Effects {
644 fn flip(&mut self) {
645 self.justify = match self.justify {
646 None => Some(Justify::Mirror),
647 Some(_) => None,
648 }
649 }
650}
651
652impl Effects {
653 pub fn from_font(font: Font, justify: Option<Justify>) -> Effects {
655 Effects {
656 font: font,
657 justify: justify,
658 }
659 }
660}
661
662#[derive(Debug, Clone, PartialEq)]
664pub enum Justify {
665 Mirror,
667 Left,
669 Right,
671}
672
673#[derive(Debug, Clone, PartialEq)]
675pub enum XyType {
676 Xy,
678 Start,
680 End,
682 Size,
684 Center,
686 RectDelta,
688}
689
690impl Default for XyType {
691 fn default() -> XyType {
692 XyType::Xy
693 }
694}
695
696#[derive(Debug, Clone, Default, PartialEq)]
698pub struct Xy {
699 pub x: f64,
701 pub y: f64,
703 pub t: XyType,
705}
706
707impl Flip for Xy {
708 fn flip(&mut self) {
709 self.y = -self.y;
710 }
711}
712
713impl Adjust for Xy {
714 fn adjust(&mut self, x: f64, y: f64) {
715 self.x += x;
716 self.y += y
717 }
718}
719
720impl Xy {
721 pub fn new(x: f64, y: f64, t: XyType) -> Xy {
723 Xy { x: x, y: y, t: t }
724 }
725 pub fn new_empty(t: XyType) -> Xy {
727 Xy {
728 x: 0.0,
729 y: 0.0,
730 t: t,
731 }
732 }
733}
734
735#[derive(Debug, Clone, Default, PartialEq)]
737pub struct Pts {
738 pub elements: Vec<Xy>,
740}
741
742impl Flip for Pts {
743 fn flip(&mut self) {
744 for e in &mut self.elements {
745 e.flip()
746 }
747 }
748}
749
750impl Adjust for Pts {
751 fn adjust(&mut self, x: f64, y: f64) {
752 for e in &mut self.elements {
753 e.adjust(x, y)
754 }
755 }
756}
757
758impl BoundingBox for Pts {
759 fn bounding_box(&self) -> Bound {
760 let mut b = Bound::default();
761 for e in &self.elements {
762 let b2 = Bound::new(e.x, e.y, e.x, e.y);
763 b.update(&b2);
764 }
765 b.swap_if_needed();
766 b
767 }
768}
769
770#[derive(Clone, Debug, Default, PartialEq)]
772pub struct Drill {
773 pub shape: Option<String>,
775 pub width: f64,
777 pub height: f64,
779 pub offset_x: f64,
781 pub offset_y: f64,
783}
784
785#[derive(Debug, Clone, PartialEq)]
787pub enum PadType {
788 Smd,
790 Pth,
792 NpPth,
794}
795
796impl PadType {
797 pub fn from_string(s: &str) -> Result<PadType,SexpError> {
799 match s {
800 "smd" => Ok(PadType::Smd),
801 "thru_hole" => Ok(PadType::Pth),
802 "np_thru_hole" => Ok(PadType::NpPth),
803 x => Err(format!("unknown PadType {}", x).into()),
804 }
805 }
806}
807
808#[derive(Debug, Clone, PartialEq)]
810pub enum PadShape {
811 Rect,
813 Circle,
815 Oval,
817 Trapezoid, }
820
821impl PadShape {
822 pub fn from_string(s: &str) -> Result<PadShape, SexpError> {
824 match s {
825 "rect" => Ok(PadShape::Rect),
826 "circle" => Ok(PadShape::Circle),
827 "oval" => Ok(PadShape::Oval),
828 "trapezoid" => Ok(PadShape::Trapezoid),
829 x => Err(format!("unknown PadShape: {}", x).into()),
830 }
831 }
832}
833
834#[derive(Debug, Clone, PartialEq)]
836pub enum LayerSide {
837 Front,
839 Back,
841 Dwgs,
843 Cmts,
845 Eco1,
847 Eco2,
849 Edge,
851 Both,
853 In1,
855 In2,
857 None,
859}
860
861impl Flip for LayerSide {
862 fn flip(&mut self) {
863 let n = match *self {
864 LayerSide::Front => LayerSide::Back,
865 LayerSide::Back => LayerSide::Front,
866 ref x => x.clone(),
867 };
868 *self = n;
869 }
870}
871
872impl Default for LayerSide {
873 fn default() -> LayerSide {
874 LayerSide::Front
875 }
876}
877
878#[derive(Debug, Clone, PartialEq)]
880pub enum LayerType {
881 Cu,
883 Paste,
885 Mask,
887 SilkS,
889 User,
891 Adhes,
893 Cuts,
895 CrtYd,
897 Fab,
899 Margin,
901 Other(String),
903}
904
905impl Default for LayerType {
906 fn default() -> LayerType {
907 LayerType::Cu
908 }
909}
910
911#[derive(Debug, Clone, Default)]
913pub struct Layer {
914 pub side: LayerSide,
916 pub t: LayerType,
918}
919
920impl Flip for Layer {
921 fn flip(&mut self) {
922 self.side.flip()
923 }
924}
925
926impl PartialEq for Layer {
927 fn eq(&self, other: &Layer) -> bool {
928 self.t == other.t
929 }
930}
931
932impl Layer {
933 pub fn from_string(s: &str) -> Result<Layer, SexpError> {
935 let sp: Vec<&str> = s.split('.').collect();
936 let mut side = LayerSide::None;
937 let s_t = if sp.len() == 2 {
938 side = match sp[0] {
939 "F" => LayerSide::Front,
940 "B" => LayerSide::Back,
941 "Dwgs" => LayerSide::Dwgs,
942 "Cmts" => LayerSide::Cmts,
943 "Eco1" => LayerSide::Eco1,
944 "Eco2" => LayerSide::Eco2,
945 "Edge" => LayerSide::Edge,
946 "In1" => LayerSide::In1,
947 "In2" => LayerSide::In2,
948 "*" => LayerSide::Both,
949 x => return Err(format!("unknown layer side {}", x).into()),
950 };
951 sp[1]
952 } else {
953 sp[0]
954 };
955
956 let t = match s_t {
957 "Cu" => LayerType::Cu,
958 "Paste" => LayerType::Paste,
959 "Mask" => LayerType::Mask,
960 "SilkS" => LayerType::SilkS,
961 "User" => LayerType::User,
962 "Adhes" => LayerType::Adhes,
963 "Cuts" => LayerType::Cuts,
964 "CrtYd" => LayerType::CrtYd,
965 "Fab" => LayerType::Fab,
966 "Margin" => LayerType::Margin,
967 x => LayerType::Other(String::from(x)),
968 };
969 Ok(Layer { side: side, t: t })
970 }
971}
972
973#[derive(Debug, Clone, Default, PartialEq)]
975pub struct Layers {
976 pub layers: Vec<Layer>,
978}
979
980impl Flip for Layers {
981 fn flip(&mut self) {
982 for layer in &mut self.layers {
983 layer.flip()
984 }
985 }
986}
987
988impl Layers {
989 pub fn append(&mut self, layer: Layer) {
991 self.layers.push(layer)
992 }
993}
994
995#[derive(Debug, Clone)]
997pub struct Pad {
998 pub name: String,
1000 pub t: PadType,
1002 pub shape: PadShape,
1004 pub size: Xy,
1006 pub rect_delta: Option<Xy>,
1008 pub at: At,
1010 pub layers: Layers,
1012 pub net: Option<Net>,
1014 pub zone_connect: Option<i64>,
1016 pub drill: Option<Drill>,
1018 pub solder_paste_margin: Option<f64>,
1020 pub solder_mask_margin: Option<f64>,
1022 pub clearance: Option<f64>,
1024 pub thermal_gap: Option<f64>,
1026}
1027
1028impl Flip for Pad {
1029 fn flip(&mut self) {
1030 self.at.flip();
1031 self.layers.flip();
1032 }
1033}
1034
1035impl Rotate for Pad {
1036 fn rotate(&mut self, rot: f64) {
1037 self.at.rotate(rot)
1038 }
1039}
1040
1041impl PartialEq for Pad {
1042 fn eq(&self, other: &Pad) -> bool {
1043 if self.at != other.at {
1044 return false;
1045 }
1046 if self.name != other.name {
1047 return false;
1048 }
1049 if self.t != other.t {
1050 return false;
1051 }
1052 if self.shape != other.shape {
1053 return false;
1054 }
1055 if self.size != other.size {
1056 return false;
1057 }
1058 if self.rect_delta != other.rect_delta {
1059 return false;
1060 }
1061 if self.layers != other.layers {
1062 return false;
1063 }
1064 if self.zone_connect != other.zone_connect {
1065 return false;
1066 }
1067 if self.drill != other.drill {
1068 return false;
1069 }
1070 if self.solder_paste_margin != other.solder_paste_margin {
1071 return false;
1072 }
1073 if self.solder_mask_margin != other.solder_mask_margin {
1074 return false;
1075 }
1076 if self.clearance != other.clearance {
1077 return false;
1078 }
1079 if self.thermal_gap != other.thermal_gap {
1080 return false;
1081 }
1082 true
1083 }
1084}
1085
1086impl Pad {
1087 pub fn new(name: String, t: PadType, shape: PadShape) -> Pad {
1089 Pad {
1090 name: name,
1091 t: t,
1092 shape: shape,
1093 size: Xy::new_empty(XyType::Size),
1094 rect_delta: None,
1095 at: At::default(),
1096 layers: Layers::default(),
1097 net: None,
1098 zone_connect: None,
1099 drill: None,
1100 solder_paste_margin: None,
1101 solder_mask_margin: None,
1102 clearance: None,
1103 thermal_gap: None,
1104 }
1105 }
1106
1107 pub fn rename_net(&mut self, old_name: &str, new_name: &str) {
1109 let new_net = if let Some(ref net) = self.net {
1110 if net.name.0 == old_name {
1111 Some(Net {
1112 name: new_name.into(),
1113 ..*net
1114 })
1115 } else {
1116 Some(net.clone())
1117 }
1118 } else {
1119 None
1120 };
1121 self.net = new_net
1122 }
1123
1124 pub fn set_net(&mut self, net: Net) {
1126 self.net = Some(net)
1127 }
1128
1129 pub fn set_drill(&mut self, drill: Drill) {
1131 self.drill = Some(drill)
1132 }
1133}
1134
1135impl BoundingBox for Pad {
1136 fn bounding_box(&self) -> Bound {
1137 let x = self.at.x;
1138 let y = self.at.y;
1139 let (dx, dy) = if (self.at.rot - 90.0).abs() < 0.1 || (self.at.rot + 90.0).abs() < 0.1
1140 || (self.at.rot - 270.0).abs() < 0.1
1141 || (self.at.rot + 270.0).abs() < 0.1
1142 {
1143 (self.size.y, self.size.x)
1144 } else {
1145 (self.size.x, self.size.y)
1146 };
1147 Bound::new(x - dx / 2.0, y - dy / 2.0, x + dx / 2.0, y + dy / 2.0)
1148 }
1149}
1150
1151#[derive(Debug, Clone, Default, PartialEq)]
1153pub struct FpPoly {
1154 pub pts: Pts,
1156 pub width: f64,
1158 pub layer: Layer,
1160}
1161
1162impl Flip for FpPoly {
1163 fn flip(&mut self) {
1164 self.pts.flip();
1165 self.layer.flip()
1166 }
1167}
1168
1169impl BoundingBox for FpPoly {
1170 fn bounding_box(&self) -> Bound {
1171 let mut b = Bound::default();
1172 for p in &self.pts.elements {
1173 let b2 = Bound::new(p.x, p.y, p.x, p.y);
1174 b.update(&b2);
1175 }
1176 b.swap_if_needed();
1177 b
1178 }
1179}
1180
1181impl FpPoly {
1182 fn is_fab(&self) -> bool {
1183 self.layer.t == LayerType::Fab
1184 }
1185}
1186
1187#[derive(Debug, Clone, PartialEq)]
1189pub struct FpLine {
1190 pub start: Xy,
1192 pub end: Xy,
1194 pub layer: Layer,
1196 pub width: f64,
1198}
1199
1200impl Flip for FpLine {
1201 fn flip(&mut self) {
1202 self.start.flip();
1203 self.end.flip();
1204 self.layer.flip()
1205 }
1206}
1207
1208impl Default for FpLine {
1209 fn default() -> FpLine {
1210 FpLine {
1211 start: Xy::new_empty(XyType::Start),
1212 end: Xy::new_empty(XyType::End),
1213 layer: Layer::default(),
1214 width: 0.0,
1215 }
1216 }
1217}
1218
1219impl BoundingBox for FpLine {
1220 fn bounding_box(&self) -> Bound {
1221 Bound::new(self.start.x, self.start.y, self.end.x, self.end.y)
1222 }
1223}
1224
1225impl FpLine {
1226 fn make(x1: f64, y1: f64, x2: f64, y2: f64, t: LayerType, width: f64) -> FpLine {
1227 let mut line1 = FpLine::default();
1228 line1.start.x = x1;
1229 line1.start.y = y1;
1230 line1.end.x = x2;
1231 line1.end.y = y2;
1232 line1.layer.t = t;
1233 line1.width = width;
1234 line1
1235 }
1236
1237 fn is_fab(&self) -> bool {
1238 self.layer.t == LayerType::Fab
1239 }
1240}
1241
1242#[derive(Debug, Clone, PartialEq)]
1244pub struct FpCircle {
1245 pub center: Xy,
1247 pub end: Xy,
1249 pub layer: Layer,
1251 pub width: f64,
1253}
1254
1255impl Default for FpCircle {
1256 fn default() -> FpCircle {
1257 FpCircle {
1258 center: Xy::new_empty(XyType::Center),
1259 end: Xy::new_empty(XyType::End),
1260 layer: Layer::default(),
1261 width: 0.0,
1262 }
1263 }
1264}
1265
1266impl Flip for FpCircle {
1267 fn flip(&mut self) {
1268 self.center.flip();
1269 self.end.flip();
1270 self.layer.flip()
1271 }
1272}
1273
1274impl BoundingBox for FpCircle {
1275 fn bounding_box(&self) -> Bound {
1276 let dx = self.center.x - self.end.x;
1277 let dy = self.center.y - self.end.y;
1278 let d2 = dx * dx + dy * dy;
1279 let d = d2.sqrt();
1280 Bound::new(
1281 self.center.x - d,
1282 self.center.y - d,
1283 self.center.x + d,
1284 self.center.y + d,
1285 )
1286 }
1287}
1288
1289impl FpCircle {
1290 fn is_fab(&self) -> bool {
1291 self.layer.t == LayerType::Fab
1292 }
1293}
1294
1295#[derive(Debug, Clone, PartialEq)]
1297pub struct FpArc {
1298 pub start: Xy,
1300 pub end: Xy,
1302 pub angle: f64,
1304 pub layer: Layer,
1306 pub width: f64,
1308}
1309
1310impl Flip for FpArc {
1311 fn flip(&mut self) {
1312 self.start.flip();
1313 self.end.flip();
1314 self.layer.flip()
1315 }
1316}
1317
1318impl BoundingBox for FpArc {
1319 fn bounding_box(&self) -> Bound {
1320 Bound::new(self.start.x, self.start.y, self.end.x, self.end.y)
1322 }
1323}
1324
1325impl Default for FpArc {
1326 fn default() -> FpArc {
1327 FpArc {
1328 start: Xy::new_empty(XyType::Start),
1329 end: Xy::new_empty(XyType::End),
1330 angle: 0.0,
1331 layer: Layer::default(),
1332 width: 0.0,
1333 }
1334 }
1335}
1336
1337impl FpArc {
1338 fn is_fab(&self) -> bool {
1339 self.layer.t == LayerType::Fab
1340 }
1341}
1342
1343#[derive(Debug, Clone, PartialEq)]
1345pub struct Net {
1346 pub num: i64,
1348 pub name: NetName,
1350}
1351
1352#[derive(Debug, Clone, PartialEq)]
1354pub struct Model {
1355 pub name: String,
1357 pub at: Xyz,
1359 pub scale: Xyz,
1361 pub rotate: Xyz,
1363}
1364
1365#[derive(Debug, Clone, PartialEq)]
1367pub struct Xyz {
1368 pub x: f64,
1370 pub y: f64,
1372 pub z: f64,
1374}
1375
1376impl Xyz {
1377 pub fn new(x: f64, y: f64, z: f64) -> Xyz {
1379 Xyz { x: x, y: y, z: z }
1380 }
1381}
1382
1383impl CheckFix for Module {
1384 fn check(&self, config: &Config) -> Vec<CheckFixData> {
1385 let mut v = vec![];
1386 let name = &self.name;
1387 let font_size = config.m.font_size;
1388 let font_thickness = config.m.font_thickness;
1389
1390 if let Some(reference) = self.get_reference_text() {
1391 if reference.value.as_str() != "REF**" {
1393 v.push(CheckFixData::new(
1394 7,
1395 3,
1396 name.clone(),
1397 "reference should be REF**",
1398 ));
1399 }
1400 if reference.layer.t != LayerType::SilkS {
1402 v.push(CheckFixData::new(
1403 7,
1404 3,
1405 name.clone(),
1406 "reference should be on SilkS layertype",
1407 ));
1408 }
1409 if reference.hide {
1411 v.push(CheckFixData::new(
1412 7,
1413 3,
1414 name.clone(),
1415 "reference should not be hidden",
1416 ));
1417 }
1418 if (reference.effects.font.size.x - reference.effects.font.size.y).abs() > EPSILON {
1420 v.push(CheckFixData::new(
1421 7,
1422 3,
1423 name.clone(),
1424 "reference label font aspect ratio should be 1:1",
1425 ));
1426 }
1427 if (reference.effects.font.size.y - font_size).abs() > EPSILON {
1430 v.push(CheckFixData::info(
1431 7,
1432 3,
1433 name.clone(),
1434 format!("reference label should have height {}", font_size),
1435 ));
1436 }
1437 if (reference.effects.font.size.x - font_size).abs() > EPSILON {
1440 v.push(CheckFixData::info(
1441 7,
1442 3,
1443 name.clone(),
1444 format!("reference label should have width {}", font_size),
1445 ));
1446 }
1447 if (reference.effects.font.thickness - font_thickness).abs() > EPSILON {
1449 v.push(CheckFixData::info(
1450 7,
1451 3,
1452 name.clone(),
1453 format!("reference label thickness should be {}", font_thickness),
1454 ))
1455 }
1456 } else {
1459 v.push(CheckFixData::new(7, 3, name.clone(), "reference missing"));
1461 }
1462
1463 if let Some(value) = self.get_value_text() {
1464 if value.value.as_str() != name.as_str() {
1466 v.push(CheckFixData::new(
1467 7,
1468 4,
1469 name.clone(),
1470 "value text has to match footprint name",
1471 ));
1472 }
1473 if value.layer.t != LayerType::Fab {
1475 v.push(CheckFixData::new(
1476 7,
1477 4,
1478 name.clone(),
1479 "value text has to be on Fab layer",
1480 ));
1481 }
1482 if value.hide {
1484 v.push(CheckFixData::new(
1485 7,
1486 4,
1487 name.clone(),
1488 "value text should not be hidden",
1489 ));
1490 }
1491 if (value.effects.font.size.y - font_size).abs() > EPSILON {
1494 v.push(CheckFixData::info(
1495 7,
1496 3,
1497 name.clone(),
1498 format!("value label should have height {}", font_size),
1499 ));
1500 }
1501 if (value.effects.font.size.x - font_size).abs() > EPSILON {
1504 v.push(CheckFixData::info(
1505 7,
1506 3,
1507 name.clone(),
1508 format!("value label should have width {}", font_size),
1509 ));
1510 }
1511 if (value.effects.font.thickness - font_thickness).abs() > EPSILON {
1513 v.push(CheckFixData::info(
1514 7,
1515 3,
1516 name.clone(),
1517 format!("value label thickness should be {}", font_thickness),
1518 ))
1519 }
1520 } else {
1522 v.push(CheckFixData::new(7, 4, name.clone(), "value missing"));
1524 }
1525
1526 if let Some(reference) = self.get_reference2_text() {
1527 if reference.value.as_str() != "%R" {
1529 v.push(CheckFixData::new(
1530 7,
1531 4,
1532 name.clone(),
1533 "reference 2 should be %R",
1534 ));
1535 }
1536 if reference.layer.t != LayerType::Fab {
1538 v.push(CheckFixData::new(
1539 7,
1540 4,
1541 name.clone(),
1542 "reference 2 should be on Fab layertype",
1543 ));
1544 }
1545 if (reference.effects.font.size.x - reference.effects.font.size.y).abs() > EPSILON {
1547 v.push(CheckFixData::new(
1548 7,
1549 4,
1550 name.clone(),
1551 "reference 2 label font aspect ratio should be 1:1",
1552 ));
1553 }
1554 if (reference.effects.font.size.y - font_size).abs() > EPSILON {
1557 v.push(CheckFixData::info(
1558 7,
1559 3,
1560 name.clone(),
1561 format!("reference 2 label should have height {}", font_size),
1562 ));
1563 }
1564 if (reference.effects.font.size.x - font_size).abs() > EPSILON {
1567 v.push(CheckFixData::info(
1568 7,
1569 3,
1570 name.clone(),
1571 format!("reference 2 label should have width {}", font_size),
1572 ));
1573 }
1574 if (reference.effects.font.thickness - font_thickness).abs() > EPSILON {
1576 v.push(CheckFixData::info(
1577 7,
1578 3,
1579 name.clone(),
1580 format!("reference 2 label thickness should be {}", font_thickness),
1581 ))
1582 }
1583 } else {
1586 v.push(CheckFixData::new(7, 4, name.clone(), "reference 2 missing"));
1588 }
1589 let mut c = 0;
1592 for line in self.lines() {
1593 if line.layer.t == LayerType::CrtYd {
1594 c += 1;
1595 }
1596 }
1597 if c < 4 {
1598 v.push(CheckFixData::new(
1599 7,
1600 5,
1601 name.clone(),
1602 "missing courtyard on CrtYd layer",
1603 ));
1604 }
1605 let mut smd = 0;
1607 let mut pth = 0;
1608 for pad in self.pads() {
1609 if pad.t == PadType::Smd {
1610 smd += 1;
1611 } else if pad.t == PadType::Pth {
1612 pth += 1;
1613 }
1614 }
1615 if pth == 0 && smd > 0 {
1616 if !self.has_smd_attr() {
1617 v.push(CheckFixData::new(
1618 8,
1619 1,
1620 name.clone(),
1621 "SMD components need to have placement Smd (Normal+Insert in Properties)",
1622 ));
1623 }
1624 } else if pth > 0 && smd == 0 {
1625 if self.has_smd_attr() {
1627 v.push(CheckFixData::new(
1628 9,
1629 1,
1630 name.clone(),
1631 "SMD components need to have placement Smd (Normal+Insert in Properties)",
1632 ));
1633 }
1634 }
1639 v
1646 }
1647
1648 fn fix(&mut self, config: &Config) {
1649 let name = self.name.clone();
1650 if let Some(reference) = self.get_reference_text_mut() {
1652 reference.value.clear();
1653 reference.value.push_str("REF**");
1654 reference.layer.t = LayerType::SilkS;
1655 reference.hide = false;
1656 reference.effects.font.size.x = config.m.font_size;
1657 reference.effects.font.size.y = config.m.font_size;
1658 reference.effects.font.thickness = config.m.font_thickness;
1659 } else {
1660 }
1662 if let Some(value) = self.get_value_text_mut() {
1664 value.value.clear();
1665 value.value.push_str(&name);
1666 value.layer.t = LayerType::Fab;
1667 value.hide = false;
1668 value.effects.font.size.x = config.m.font_size;
1669 value.effects.font.size.y = config.m.font_size;
1670 value.effects.font.thickness = config.m.font_thickness;
1671 } else {
1672 }
1674 {
1676 if self.get_reference2_text().is_none() {
1677 let size = Xy {
1678 x: config.m.font_size,
1679 y: config.m.font_size,
1680 t: XyType::default(),
1681 };
1682 let font = Font {
1683 size: size,
1684 thickness: config.m.font_thickness,
1685 italic: false,
1686 };
1687 let ref2 = FpText {
1688 name: "user".into(),
1689 value: "%R".into(),
1690 at: At::new(0.0, 0.0, 0.0),
1691 layer: Layer::from_string("F.Fab").unwrap(),
1692 effects: Effects::from_font(font, None),
1693 hide: false,
1694 };
1695 self.elements.push(Element::FpText(ref2));
1696 };
1697 let ref2 = self.get_reference2_text_mut().unwrap();
1698 ref2.value.clear();
1699 ref2.value.push_str("%R");
1700 ref2.layer.t = LayerType::Fab;
1701 ref2.hide = false;
1702 ref2.effects.font.size.x = config.m.font_size;
1703 ref2.effects.font.size.y = config.m.font_size;
1704 ref2.effects.font.thickness = config.m.font_thickness;
1705 }
1706 {
1708 let mut smd = 0;
1709 let mut pth = 0;
1710 for pad in self.pads() {
1711 if pad.t == PadType::Smd {
1712 smd += 1;
1713 } else if pad.t == PadType::Pth {
1714 pth += 1;
1715 }
1716 }
1717 if pth == 0 && smd > 0 {
1718 if !self.has_smd_attr() {
1719 self.elements.push(Element::Attr("smd".into()))
1720 }
1721 }
1722 }
1723 let mut c = 0;
1725 for line in self.lines() {
1726 if line.layer.t == LayerType::CrtYd {
1727 c += 1;
1728 }
1729 }
1730 if c < 4 {
1731 let bound = self.bounding_box();
1733 debug!("bound: {:?}", bound);
1734 let (x, y) = self.at();
1735 debug!("at: {:?}", (x, y));
1736 let offset = if bound.width() < 2.0 && bound.height() < 2.0 {
1737 0.15
1738 } else if self.name.starts_with("BGA") {
1739 0.1
1740 } else {
1741 0.25
1742 };
1743 let x1a = bound.x1 - x;
1745 let y1a = bound.y1 - y;
1746 let x2a = bound.x2 - x;
1747 let y2a = bound.y2 - y;
1748 debug!("a: {:?}", ((x1a, y1a), (x2a, y2a)));
1749 let x1 = x1a.min(x2a) - offset;
1750 let y1 = y1a.min(y2a) - offset;
1751 let x2 = x1a.max(x2a) + offset;
1752 let y2 = y1a.max(y2a) + offset;
1753 info!("Creating courtyard: {},{} -> {},{}", x1, y1, x2, y2);
1754 let line1 = FpLine::make(x1, y1, x2, y1, LayerType::CrtYd, 0.05);
1755 let line2 = FpLine::make(x2, y1, x2, y2, LayerType::CrtYd, 0.05);
1756 let line3 = FpLine::make(x2, y2, x1, y2, LayerType::CrtYd, 0.05);
1757 let line4 = FpLine::make(x1, y2, x1, y1, LayerType::CrtYd, 0.05);
1758 self.elements.push(Element::FpLine(line1));
1759 self.elements.push(Element::FpLine(line2));
1760 self.elements.push(Element::FpLine(line3));
1761 self.elements.push(Element::FpLine(line4));
1762 }
1763 }
1764}
1765
1766#[cfg(test)]
1767mod test {
1768 use std::f64::EPSILON;
1769
1770 use super::*;
1771 #[test]
1772 fn pad_bound() {
1773 let mut pad = Pad::new("hello".into(), PadType::Smd, PadShape::Rect);
1774 pad.at.x = 1.4;
1775 pad.at.y = 0.95;
1776 pad.at.rot = 0.0;
1777 pad.size.x = 1.2;
1778 pad.size.y = 0.6;
1779 let bound = pad.bounding_box();
1780 println!("bound: {:?}", bound);
1781 assert!((bound.x2 - pad.at.x - pad.size.x / 2.0).abs() < EPSILON);
1782 assert!((bound.y2 - pad.at.y - pad.size.y / 2.0).abs() < EPSILON);
1783 assert!((bound.x1 - pad.at.x + pad.size.x / 2.0).abs() < EPSILON);
1784 assert!((bound.y1 - pad.at.y + pad.size.y / 2.0).abs() < EPSILON);
1785 }
1786
1787 #[test]
1788 fn pad_bound_180() {
1789 let mut pad = Pad::new("hello".into(), PadType::Smd, PadShape::Rect);
1790 pad.at.x = 1.4;
1791 pad.at.y = 0.95;
1792 pad.at.rot = 180.0;
1793 pad.size.x = 1.2;
1794 pad.size.y = 0.6;
1795 let bound = pad.bounding_box();
1796 println!("180 bound: {:?}", bound);
1797 assert!((bound.x2 - pad.at.x - pad.size.x / 2.0).abs() < EPSILON);
1798 assert!((bound.y2 - pad.at.y - pad.size.y / 2.0).abs() < EPSILON);
1799 assert!((bound.x1 - pad.at.x + pad.size.x / 2.0).abs() < EPSILON);
1800 assert!((bound.y1 - pad.at.y + pad.size.y / 2.0).abs() < EPSILON);
1801 }
1802
1803 #[test]
1804 fn bound_fail_cy() {
1805 let cy = include_str!("../../tests/data/cy.kicad_mod");
1806 let module = ::footprint::parse(cy).unwrap();
1807 let bound = module.bounding_box();
1808 println!("cy bound: {:?}", bound);
1809 assert!((bound.x2 - 2.95).abs() < EPSILON);
1810 assert!((bound.y2 - 2.95).abs() < EPSILON);
1811 assert!((bound.x1 + 2.95).abs() < EPSILON);
1812 assert!((bound.y1 + 2.95).abs() < EPSILON);
1813 }
1814}