2018-04-09 14:24:34 +00:00
|
|
|
#include "2DBed.hpp"
|
2019-02-04 09:35:16 +00:00
|
|
|
#include "GUI_App.hpp"
|
2018-01-25 12:46:04 +00:00
|
|
|
|
|
|
|
#include <wx/dcbuffer.h>
|
2018-11-26 13:41:58 +00:00
|
|
|
|
|
|
|
#include "libslic3r/BoundingBox.hpp"
|
|
|
|
#include "libslic3r/Geometry.hpp"
|
|
|
|
#include "libslic3r/ClipperUtils.hpp"
|
2018-01-25 12:46:04 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
namespace GUI {
|
|
|
|
|
2019-02-04 09:35:16 +00:00
|
|
|
|
|
|
|
Bed_2D::Bed_2D(wxWindow* parent) :
|
2019-02-06 08:49:32 +00:00
|
|
|
wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(25 * wxGetApp().em_unit(), -1), wxTAB_TRAVERSAL)
|
2019-02-04 09:35:16 +00:00
|
|
|
{
|
|
|
|
SetBackgroundStyle(wxBG_STYLE_PAINT); // to avoid assert message after wxAutoBufferedPaintDC
|
|
|
|
#ifdef __APPLE__
|
|
|
|
m_user_drawn_background = false;
|
|
|
|
#endif /*__APPLE__*/
|
2019-04-09 11:13:42 +00:00
|
|
|
Bind(wxEVT_PAINT, ([this](wxPaintEvent &/* e */) { repaint(); }));
|
|
|
|
Bind(wxEVT_SIZE, ([this](wxSizeEvent & /* e */) { Refresh(); }));
|
2019-02-04 09:35:16 +00:00
|
|
|
}
|
2018-01-25 12:46:04 +00:00
|
|
|
void Bed_2D::repaint()
|
|
|
|
{
|
2018-01-30 11:10:12 +00:00
|
|
|
wxAutoBufferedPaintDC dc(this);
|
2018-01-25 12:46:04 +00:00
|
|
|
auto cw = GetSize().GetWidth();
|
|
|
|
auto ch = GetSize().GetHeight();
|
|
|
|
// when canvas is not rendered yet, size is 0, 0
|
|
|
|
if (cw == 0) return ;
|
|
|
|
|
|
|
|
if (m_user_drawn_background) {
|
|
|
|
// On all systems the AutoBufferedPaintDC() achieves double buffering.
|
|
|
|
// On MacOS the background is erased, on Windows the background is not erased
|
|
|
|
// and on Linux / GTK the background is erased to gray color.
|
|
|
|
// Fill DC with the background on Windows & Linux / GTK.
|
|
|
|
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); //GetSystemColour
|
2018-01-30 11:10:12 +00:00
|
|
|
dc.SetPen(*new wxPen(color, 1, wxPENSTYLE_SOLID));
|
2018-01-25 12:46:04 +00:00
|
|
|
dc.SetBrush(*new wxBrush(color, wxBRUSHSTYLE_SOLID));
|
|
|
|
auto rect = GetUpdateRegion().GetBox();
|
|
|
|
dc.DrawRectangle(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
|
|
|
|
}
|
|
|
|
|
2019-06-12 08:00:51 +00:00
|
|
|
if (m_bed_shape.empty())
|
|
|
|
return;
|
2018-01-25 12:46:04 +00:00
|
|
|
|
2019-06-12 08:00:51 +00:00
|
|
|
// reduce size to have some space around the drawn shape
|
|
|
|
cw -= (2 * Border);
|
|
|
|
ch -= (2 * Border);
|
2018-01-25 12:46:04 +00:00
|
|
|
|
2019-06-12 08:00:51 +00:00
|
|
|
auto cbb = BoundingBoxf(Vec2d(0, 0),Vec2d(cw, ch));
|
2018-01-25 12:46:04 +00:00
|
|
|
auto ccenter = cbb.center();
|
|
|
|
|
|
|
|
// get bounding box of bed shape in G - code coordinates
|
|
|
|
auto bed_shape = m_bed_shape;
|
|
|
|
auto bed_polygon = Polygon::new_scale(m_bed_shape);
|
|
|
|
auto bb = BoundingBoxf(m_bed_shape);
|
2018-08-21 19:05:24 +00:00
|
|
|
bb.merge(Vec2d(0, 0)); // origin needs to be in the visible area
|
2018-08-17 13:53:43 +00:00
|
|
|
auto bw = bb.size()(0);
|
|
|
|
auto bh = bb.size()(1);
|
2018-01-25 12:46:04 +00:00
|
|
|
auto bcenter = bb.center();
|
|
|
|
|
|
|
|
// calculate the scaling factor for fitting bed shape in canvas area
|
|
|
|
auto sfactor = std::min(cw/bw, ch/bh);
|
2018-08-21 19:05:24 +00:00
|
|
|
auto shift = Vec2d(
|
2018-08-17 13:53:43 +00:00
|
|
|
ccenter(0) - bcenter(0) * sfactor,
|
|
|
|
ccenter(1) - bcenter(1) * sfactor
|
2018-01-25 12:46:04 +00:00
|
|
|
);
|
2019-06-12 08:00:51 +00:00
|
|
|
|
2018-01-25 12:46:04 +00:00
|
|
|
m_scale_factor = sfactor;
|
2019-06-12 08:00:51 +00:00
|
|
|
m_shift = Vec2d(shift(0) + cbb.min(0), shift(1) - (cbb.max(1) - ch));
|
2018-01-25 12:46:04 +00:00
|
|
|
|
|
|
|
// draw bed fill
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxBRUSHSTYLE_SOLID));
|
2018-01-30 11:10:12 +00:00
|
|
|
wxPointList pt_list;
|
|
|
|
for (auto pt: m_bed_shape)
|
|
|
|
{
|
2019-06-12 08:00:51 +00:00
|
|
|
Point pt_pix = to_pixels(pt, ch);
|
|
|
|
pt_list.push_back(new wxPoint(pt_pix(0), pt_pix(1)));
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
|
|
|
dc.DrawPolygon(&pt_list, 0, 0);
|
|
|
|
|
2018-01-25 12:46:04 +00:00
|
|
|
// draw grid
|
2018-01-30 11:10:12 +00:00
|
|
|
auto step = 10; // 1cm grid
|
|
|
|
Polylines polylines;
|
2018-08-17 13:53:43 +00:00
|
|
|
for (auto x = bb.min(0) - fmod(bb.min(0), step) + step; x < bb.max(0); x += step) {
|
2018-08-21 19:05:24 +00:00
|
|
|
polylines.push_back(Polyline::new_scale({ Vec2d(x, bb.min(1)), Vec2d(x, bb.max(1)) }));
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
2018-08-17 13:53:43 +00:00
|
|
|
for (auto y = bb.min(1) - fmod(bb.min(1), step) + step; y < bb.max(1); y += step) {
|
2018-08-21 19:05:24 +00:00
|
|
|
polylines.push_back(Polyline::new_scale({ Vec2d(bb.min(0), y), Vec2d(bb.max(0), y) }));
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
|
|
|
polylines = intersection_pl(polylines, bed_polygon);
|
|
|
|
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetPen(wxPen(wxColour(230, 230, 230), 1, wxPENSTYLE_SOLID));
|
2018-01-30 11:10:12 +00:00
|
|
|
for (auto pl : polylines)
|
|
|
|
{
|
2018-10-31 11:56:08 +00:00
|
|
|
for (size_t i = 0; i < pl.points.size()-1; i++) {
|
2019-06-12 08:00:51 +00:00
|
|
|
Point pt1 = to_pixels(unscale(pl.points[i]), ch);
|
|
|
|
Point pt2 = to_pixels(unscale(pl.points[i + 1]), ch);
|
|
|
|
dc.DrawLine(pt1(0), pt1(1), pt2(0), pt2(1));
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw bed contour
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxPENSTYLE_SOLID));
|
|
|
|
dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT));
|
2018-01-30 11:10:12 +00:00
|
|
|
dc.DrawPolygon(&pt_list, 0, 0);
|
|
|
|
|
2019-06-12 08:00:51 +00:00
|
|
|
auto origin_px = to_pixels(Vec2d(0, 0), ch);
|
2018-01-30 11:10:12 +00:00
|
|
|
|
|
|
|
// draw axes
|
|
|
|
auto axes_len = 50;
|
|
|
|
auto arrow_len = 6;
|
|
|
|
auto arrow_angle = Geometry::deg2rad(45.0);
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetPen(wxPen(wxColour(255, 0, 0), 2, wxPENSTYLE_SOLID)); // red
|
2018-08-21 19:05:24 +00:00
|
|
|
auto x_end = Vec2d(origin_px(0) + axes_len, origin_px(1));
|
2018-08-17 13:53:43 +00:00
|
|
|
dc.DrawLine(wxPoint(origin_px(0), origin_px(1)), wxPoint(x_end(0), x_end(1)));
|
2018-10-31 11:56:08 +00:00
|
|
|
for (auto angle : { -arrow_angle, arrow_angle }) {
|
2018-08-21 18:34:45 +00:00
|
|
|
auto end = Eigen::Translation2d(x_end) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- x_end) * Eigen::Vector2d(x_end(0) - arrow_len, x_end(1));
|
2018-08-17 13:53:43 +00:00
|
|
|
dc.DrawLine(wxPoint(x_end(0), x_end(1)), wxPoint(end(0), end(1)));
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
|
|
|
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetPen(wxPen(wxColour(0, 255, 0), 2, wxPENSTYLE_SOLID)); // green
|
2018-08-21 19:05:24 +00:00
|
|
|
auto y_end = Vec2d(origin_px(0), origin_px(1) - axes_len);
|
2018-08-17 13:53:43 +00:00
|
|
|
dc.DrawLine(wxPoint(origin_px(0), origin_px(1)), wxPoint(y_end(0), y_end(1)));
|
2018-01-30 11:10:12 +00:00
|
|
|
for (auto angle : { -arrow_angle, arrow_angle }) {
|
2018-08-21 18:34:45 +00:00
|
|
|
auto end = Eigen::Translation2d(y_end) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- y_end) * Eigen::Vector2d(y_end(0), y_end(1) + arrow_len);
|
2018-08-17 13:53:43 +00:00
|
|
|
dc.DrawLine(wxPoint(y_end(0), y_end(1)), wxPoint(end(0), end(1)));
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// draw origin
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxPENSTYLE_SOLID));
|
|
|
|
dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxBRUSHSTYLE_SOLID));
|
2018-08-17 13:53:43 +00:00
|
|
|
dc.DrawCircle(origin_px(0), origin_px(1), 3);
|
2018-01-30 11:10:12 +00:00
|
|
|
|
2018-04-09 14:24:34 +00:00
|
|
|
static const auto origin_label = wxString("(0,0)");
|
|
|
|
dc.SetTextForeground(wxColour(0, 0, 0));
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
2018-04-09 14:24:34 +00:00
|
|
|
auto extent = dc.GetTextExtent(origin_label);
|
2018-08-17 13:53:43 +00:00
|
|
|
const auto origin_label_x = origin_px(0) <= cw / 2 ? origin_px(0) + 1 : origin_px(0) - 1 - extent.GetWidth();
|
|
|
|
const auto origin_label_y = origin_px(1) <= ch / 2 ? origin_px(1) + 1 : origin_px(1) - 1 - extent.GetHeight();
|
2018-04-09 14:24:34 +00:00
|
|
|
dc.DrawText(origin_label, origin_label_x, origin_label_y);
|
2018-01-30 11:10:12 +00:00
|
|
|
|
|
|
|
// draw current position
|
2018-08-21 19:05:24 +00:00
|
|
|
if (m_pos!= Vec2d(0, 0)) {
|
2019-06-12 08:00:51 +00:00
|
|
|
auto pos_px = to_pixels(m_pos, ch);
|
2018-11-29 14:42:33 +00:00
|
|
|
dc.SetPen(wxPen(wxColour(200, 0, 0), 2, wxPENSTYLE_SOLID));
|
|
|
|
dc.SetBrush(wxBrush(wxColour(200, 0, 0), wxBRUSHSTYLE_TRANSPARENT));
|
2018-08-17 13:53:43 +00:00
|
|
|
dc.DrawCircle(pos_px(0), pos_px(1), 5);
|
2018-01-30 11:10:12 +00:00
|
|
|
|
2018-08-17 13:53:43 +00:00
|
|
|
dc.DrawLine(pos_px(0) - 15, pos_px(1), pos_px(0) + 15, pos_px(1));
|
|
|
|
dc.DrawLine(pos_px(0), pos_px(1) - 15, pos_px(0), pos_px(1) + 15);
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
2018-01-25 12:46:04 +00:00
|
|
|
}
|
|
|
|
|
2019-06-12 08:00:51 +00:00
|
|
|
|
2018-01-25 12:46:04 +00:00
|
|
|
// convert G - code coordinates into pixels
|
2019-06-12 08:00:51 +00:00
|
|
|
Point Bed_2D::to_pixels(Vec2d point, int height)
|
2018-10-31 11:56:08 +00:00
|
|
|
{
|
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
|
|
|
auto p = point * m_scale_factor + m_shift;
|
2019-06-12 08:00:51 +00:00
|
|
|
return Point(p(0) + Border, height - p(1) + Border);
|
2018-01-30 11:10:12 +00:00
|
|
|
}
|
|
|
|
|
2018-10-31 11:56:08 +00:00
|
|
|
void Bed_2D::set_pos(Vec2d pos)
|
|
|
|
{
|
2018-01-30 11:10:12 +00:00
|
|
|
m_pos = pos;
|
|
|
|
Refresh();
|
|
|
|
}
|
|
|
|
|
2018-01-25 12:46:04 +00:00
|
|
|
} // GUI
|
|
|
|
} // Slic3r
|