1 #include "2DBed.hpp"
2 #include "GUI_App.hpp"
3
4 #include <wx/dcbuffer.h>
5
6 #include "libslic3r/BoundingBox.hpp"
7 #include "libslic3r/Geometry.hpp"
8 #include "libslic3r/ClipperUtils.hpp"
9
10 namespace Slic3r {
11 namespace GUI {
12
13
Bed_2D(wxWindow * parent)14 Bed_2D::Bed_2D(wxWindow* parent) :
15 wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(25 * wxGetApp().em_unit(), -1), wxTAB_TRAVERSAL)
16 {
17 SetBackgroundStyle(wxBG_STYLE_PAINT); // to avoid assert message after wxAutoBufferedPaintDC
18 #ifdef __APPLE__
19 m_user_drawn_background = false;
20 #endif /*__APPLE__*/
21 }
22
repaint(const std::vector<Vec2d> & shape)23 void Bed_2D::repaint(const std::vector<Vec2d>& shape)
24 {
25 wxAutoBufferedPaintDC dc(this);
26 auto cw = GetSize().GetWidth();
27 auto ch = GetSize().GetHeight();
28 // when canvas is not rendered yet, size is 0, 0
29 if (cw == 0) return ;
30
31 if (m_user_drawn_background) {
32 // On all systems the AutoBufferedPaintDC() achieves double buffering.
33 // On MacOS the background is erased, on Windows the background is not erased
34 // and on Linux / GTK the background is erased to gray color.
35 // Fill DC with the background on Windows & Linux / GTK.
36 auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); //GetSystemColour
37 dc.SetPen(*new wxPen(color, 1, wxPENSTYLE_SOLID));
38 dc.SetBrush(*new wxBrush(color, wxBRUSHSTYLE_SOLID));
39 auto rect = GetUpdateRegion().GetBox();
40 dc.DrawRectangle(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
41 }
42
43 if (shape.empty())
44 return;
45
46 // reduce size to have some space around the drawn shape
47 cw -= (2 * Border);
48 ch -= (2 * Border);
49
50 auto cbb = BoundingBoxf(Vec2d(0, 0),Vec2d(cw, ch));
51 auto ccenter = cbb.center();
52
53 // get bounding box of bed shape in G - code coordinates
54 auto bed_polygon = Polygon::new_scale(shape);
55 auto bb = BoundingBoxf(shape);
56 bb.merge(Vec2d(0, 0)); // origin needs to be in the visible area
57 auto bw = bb.size()(0);
58 auto bh = bb.size()(1);
59 auto bcenter = bb.center();
60
61 // calculate the scaling factor for fitting bed shape in canvas area
62 auto sfactor = std::min(cw/bw, ch/bh);
63 auto shift = Vec2d(
64 ccenter(0) - bcenter(0) * sfactor,
65 ccenter(1) - bcenter(1) * sfactor
66 );
67
68 m_scale_factor = sfactor;
69 m_shift = Vec2d(shift(0) + cbb.min(0), shift(1) - (cbb.max(1) - ch));
70
71 // draw bed fill
72 dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxBRUSHSTYLE_SOLID));
73 wxPointList pt_list;
74 for (auto pt : shape)
75 {
76 Point pt_pix = to_pixels(pt, ch);
77 pt_list.push_back(new wxPoint(pt_pix(0), pt_pix(1)));
78 }
79 dc.DrawPolygon(&pt_list, 0, 0);
80
81 // draw grid
82 auto step = 10; // 1cm grid
83 Polylines polylines;
84 for (auto x = bb.min(0) - fmod(bb.min(0), step) + step; x < bb.max(0); x += step) {
85 polylines.push_back(Polyline::new_scale({ Vec2d(x, bb.min(1)), Vec2d(x, bb.max(1)) }));
86 }
87 for (auto y = bb.min(1) - fmod(bb.min(1), step) + step; y < bb.max(1); y += step) {
88 polylines.push_back(Polyline::new_scale({ Vec2d(bb.min(0), y), Vec2d(bb.max(0), y) }));
89 }
90 polylines = intersection_pl(polylines, (Polygons)bed_polygon);
91
92 dc.SetPen(wxPen(wxColour(230, 230, 230), 1, wxPENSTYLE_SOLID));
93 for (auto pl : polylines)
94 {
95 for (size_t i = 0; i < pl.points.size()-1; i++) {
96 Point pt1 = to_pixels(unscale(pl.points[i]), ch);
97 Point pt2 = to_pixels(unscale(pl.points[i + 1]), ch);
98 dc.DrawLine(pt1(0), pt1(1), pt2(0), pt2(1));
99 }
100 }
101
102 // draw bed contour
103 dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxPENSTYLE_SOLID));
104 dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT));
105 dc.DrawPolygon(&pt_list, 0, 0);
106
107 auto origin_px = to_pixels(Vec2d(0, 0), ch);
108
109 // draw axes
110 auto axes_len = 50;
111 auto arrow_len = 6;
112 auto arrow_angle = Geometry::deg2rad(45.0);
113 dc.SetPen(wxPen(wxColour(255, 0, 0), 2, wxPENSTYLE_SOLID)); // red
114 auto x_end = Vec2d(origin_px(0) + axes_len, origin_px(1));
115 dc.DrawLine(wxPoint(origin_px(0), origin_px(1)), wxPoint(x_end(0), x_end(1)));
116 for (auto angle : { -arrow_angle, arrow_angle }) {
117 auto end = Eigen::Translation2d(x_end) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- x_end) * Eigen::Vector2d(x_end(0) - arrow_len, x_end(1));
118 dc.DrawLine(wxPoint(x_end(0), x_end(1)), wxPoint(end(0), end(1)));
119 }
120
121 dc.SetPen(wxPen(wxColour(0, 255, 0), 2, wxPENSTYLE_SOLID)); // green
122 auto y_end = Vec2d(origin_px(0), origin_px(1) - axes_len);
123 dc.DrawLine(wxPoint(origin_px(0), origin_px(1)), wxPoint(y_end(0), y_end(1)));
124 for (auto angle : { -arrow_angle, arrow_angle }) {
125 auto end = Eigen::Translation2d(y_end) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- y_end) * Eigen::Vector2d(y_end(0), y_end(1) + arrow_len);
126 dc.DrawLine(wxPoint(y_end(0), y_end(1)), wxPoint(end(0), end(1)));
127 }
128
129 // draw origin
130 dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxPENSTYLE_SOLID));
131 dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxBRUSHSTYLE_SOLID));
132 dc.DrawCircle(origin_px(0), origin_px(1), 3);
133
134 static const auto origin_label = wxString("(0,0)");
135 dc.SetTextForeground(wxColour(0, 0, 0));
136 dc.SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
137 auto extent = dc.GetTextExtent(origin_label);
138 const auto origin_label_x = origin_px(0) <= cw / 2 ? origin_px(0) + 1 : origin_px(0) - 1 - extent.GetWidth();
139 const auto origin_label_y = origin_px(1) <= ch / 2 ? origin_px(1) + 1 : origin_px(1) - 1 - extent.GetHeight();
140 dc.DrawText(origin_label, origin_label_x, origin_label_y);
141
142 // draw current position
143 if (m_pos!= Vec2d(0, 0)) {
144 auto pos_px = to_pixels(m_pos, ch);
145 dc.SetPen(wxPen(wxColour(200, 0, 0), 2, wxPENSTYLE_SOLID));
146 dc.SetBrush(wxBrush(wxColour(200, 0, 0), wxBRUSHSTYLE_TRANSPARENT));
147 dc.DrawCircle(pos_px(0), pos_px(1), 5);
148
149 dc.DrawLine(pos_px(0) - 15, pos_px(1), pos_px(0) + 15, pos_px(1));
150 dc.DrawLine(pos_px(0), pos_px(1) - 15, pos_px(0), pos_px(1) + 15);
151 }
152 }
153
154
155 // convert G - code coordinates into pixels
to_pixels(const Vec2d & point,int height)156 Point Bed_2D::to_pixels(const Vec2d& point, int height)
157 {
158 auto p = point * m_scale_factor + m_shift;
159 return Point(p(0) + Border, height - p(1) + Border);
160 }
161
set_pos(const Vec2d & pos)162 void Bed_2D::set_pos(const Vec2d& pos)
163 {
164 m_pos = pos;
165 Refresh();
166 }
167
168 } // GUI
169 } // Slic3r
170