1 #include "canvas_gerber.hpp"
2 #include "gerber_export.hpp"
3 #include "common/keepout.hpp"
4 #include "board/plane.hpp"
5 #include "board/board_layers.hpp"
6 #include "util/clipper_util.hpp"
7 #include "util/geom_util.hpp"
8
9 namespace horizon {
CanvasGerber(GerberExporter & exp)10 CanvasGerber::CanvasGerber(GerberExporter &exp) : Canvas::Canvas(), exporter(exp)
11 {
12 img_mode = true;
13 }
request_push()14 void CanvasGerber::request_push()
15 {
16 }
17
img_net(const Net * n)18 void CanvasGerber::img_net(const Net *n)
19 {
20 }
21
img_polygon(const Polygon & ipoly,bool tr)22 void CanvasGerber::img_polygon(const Polygon &ipoly, bool tr)
23 {
24 if (padstack_mode)
25 return;
26 auto poly = ipoly.remove_arcs(16);
27 if (ipoly.layer == BoardLayers::L_OUTLINE || ipoly.layer == BoardLayers::OUTLINE_NOTES) { // outline, convert poly
28 // to draws
29 const auto &vertices = ipoly.vertices;
30 for (auto it = vertices.cbegin(); it < vertices.cend(); it++) {
31 auto it_next = it + 1;
32 if (it_next == vertices.cend()) {
33 it_next = vertices.cbegin();
34 }
35 if (it->type == Polygon::Vertex::Type::LINE) {
36 img_line(it->position, it_next->position, outline_width, ipoly.layer);
37 }
38 else if (it->type == Polygon::Vertex::Type::ARC) {
39 if (GerberWriter *wr = exporter.get_writer_for_layer(ipoly.layer)) {
40 Coordi from = it->position;
41 Coordi to = it_next->position;
42 Coordd centerd = project_onto_perp_bisector(from, to, it->arc_center);
43 Coordi center(centerd.x, centerd.y);
44 if (tr) {
45 from = transform.transform(from);
46 to = transform.transform(to);
47 center = transform.transform(center);
48 }
49 wr->draw_arc(from, to, center, it->arc_reverse, outline_width);
50 }
51 }
52 }
53 }
54 else if (auto plane = dynamic_cast<const Plane *>(ipoly.usage.ptr)) {
55 if (GerberWriter *wr = exporter.get_writer_for_layer(ipoly.layer)) {
56 for (const auto &frag : plane->fragments) {
57 bool dark = true; // first path ist outline, the rest are holes
58 for (const auto &path : frag.paths) {
59 wr->draw_region(transform_path(transform, path), dark, plane->priority);
60 dark = false;
61 }
62 }
63 }
64 }
65 else if (dynamic_cast<const Keepout *>(ipoly.usage.ptr)) {
66 // nop
67 }
68 else {
69 if (GerberWriter *wr = exporter.get_writer_for_layer(ipoly.layer)) {
70 ClipperLib::Path path;
71 std::transform(poly.vertices.begin(), poly.vertices.end(), std::back_inserter(path),
72 [&tr, this](const Polygon::Vertex &v) {
73 Coordi p;
74 if (tr) {
75 p = transform.transform(v.position);
76 }
77 else {
78 p = v.position;
79 }
80 return ClipperLib::IntPoint(p.x, p.y);
81 });
82 wr->draw_region(path, true, -1);
83 }
84 }
85 }
86
img_line(const Coordi & p0,const Coordi & p1,const uint64_t width,int layer,bool tr)87 void CanvasGerber::img_line(const Coordi &p0, const Coordi &p1, const uint64_t width, int layer, bool tr)
88 {
89 if (GerberWriter *wr = exporter.get_writer_for_layer(layer)) {
90 if (tr)
91 wr->draw_line(transform.transform(p0), transform.transform(p1), width);
92 else
93 wr->draw_line(p0, p1, width);
94 }
95 }
96
img_padstack(const Padstack & padstack)97 void CanvasGerber::img_padstack(const Padstack &padstack)
98 {
99 std::set<int> layers;
100 for (const auto &it : padstack.polygons) {
101 layers.insert(it.second.layer);
102 }
103 for (const auto &it : padstack.shapes) {
104 layers.insert(it.second.layer);
105 }
106 for (const auto layer : layers) {
107 if (GerberWriter *wr = exporter.get_writer_for_layer(layer)) {
108 wr->draw_padstack(padstack, layer, transform);
109 }
110 }
111 }
112
img_set_padstack(bool v)113 void CanvasGerber::img_set_padstack(bool v)
114 {
115 padstack_mode = v;
116 }
117
img_hole(const Hole & hole)118 void CanvasGerber::img_hole(const Hole &hole)
119 {
120 auto wr = exporter.get_drill_writer(hole.plated);
121 if (hole.shape == Hole::Shape::ROUND)
122 wr->draw_hole(transform.transform(hole.placement.shift), hole.diameter);
123 else if (hole.shape == Hole::Shape::SLOT) {
124 auto tr = transform;
125 tr.accumulate(hole.placement);
126 if (tr.mirror)
127 tr.invert_angle();
128 wr->draw_slot(tr.shift, hole.diameter, hole.length, tr.get_angle());
129 }
130 }
131 } // namespace horizon
132