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