Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
commit
077d4aa3d7
7 changed files with 114 additions and 9 deletions
BIN
resources/icons/drop_to_bed.png
Normal file
BIN
resources/icons/drop_to_bed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 528 B |
|
@ -586,6 +586,9 @@ void GCode::_do_export(Print &print, FILE *file)
|
||||||
}
|
}
|
||||||
m_analyzer.set_extruder_offsets(extruder_offsets);
|
m_analyzer.set_extruder_offsets(extruder_offsets);
|
||||||
|
|
||||||
|
// tell analyzer about the gcode flavor
|
||||||
|
m_analyzer.set_gcode_flavor(print.config().gcode_flavor);
|
||||||
|
|
||||||
// resets analyzer's tracking data
|
// resets analyzer's tracking data
|
||||||
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
|
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
|
||||||
m_last_width = GCodeAnalyzer::Default_Width;
|
m_last_width = GCodeAnalyzer::Default_Width;
|
||||||
|
|
|
@ -106,6 +106,11 @@ void GCodeAnalyzer::set_extruder_offsets(const GCodeAnalyzer::ExtruderOffsetsMap
|
||||||
m_extruder_offsets = extruder_offsets;
|
m_extruder_offsets = extruder_offsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCodeAnalyzer::set_gcode_flavor(const GCodeFlavor& flavor)
|
||||||
|
{
|
||||||
|
m_gcode_flavor = flavor;
|
||||||
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::reset()
|
void GCodeAnalyzer::reset()
|
||||||
{
|
{
|
||||||
_set_units(Millimeters);
|
_set_units(Millimeters);
|
||||||
|
@ -249,6 +254,14 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi
|
||||||
_processM83(line);
|
_processM83(line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 108:
|
||||||
|
case 135:
|
||||||
|
{
|
||||||
|
// these are used by MakerWare and Sailfish firmwares
|
||||||
|
// for tool changing - we can process it in one place
|
||||||
|
_processM108orM135(line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -426,9 +439,27 @@ void GCodeAnalyzer::_processM600(const GCodeReader::GCodeLine& line)
|
||||||
_set_cp_color_id(m_state.cur_cp_color_id);
|
_set_cp_color_id(m_state.cur_cp_color_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line)
|
void GCodeAnalyzer::_processM108orM135(const GCodeReader::GCodeLine& line)
|
||||||
|
{
|
||||||
|
// These M-codes are used by MakerWare and Sailfish to change active tool.
|
||||||
|
// They have to be processed otherwise toolchanges will be unrecognised
|
||||||
|
// by the analyzer - see https://github.com/prusa3d/PrusaSlicer/issues/2566
|
||||||
|
|
||||||
|
size_t code = ::atoi(&(line.cmd()[1]));
|
||||||
|
if ((code == 108 && m_gcode_flavor == gcfSailfish)
|
||||||
|
|| (code == 135 && m_gcode_flavor == gcfMakerWare)) {
|
||||||
|
|
||||||
|
std::string cmd = line.raw();
|
||||||
|
size_t T_pos = cmd.find("T");
|
||||||
|
if (T_pos != std::string::npos) {
|
||||||
|
cmd = cmd.substr(T_pos);
|
||||||
|
_processT(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeAnalyzer::_processT(const std::string& cmd)
|
||||||
{
|
{
|
||||||
std::string cmd = line.cmd();
|
|
||||||
if (cmd.length() > 1)
|
if (cmd.length() > 1)
|
||||||
{
|
{
|
||||||
unsigned int id = (unsigned int)::strtol(cmd.substr(1).c_str(), nullptr, 10);
|
unsigned int id = (unsigned int)::strtol(cmd.substr(1).c_str(), nullptr, 10);
|
||||||
|
@ -442,6 +473,11 @@ void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line)
|
||||||
|
{
|
||||||
|
_processT(line.cmd());
|
||||||
|
}
|
||||||
|
|
||||||
bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line)
|
bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line)
|
||||||
{
|
{
|
||||||
std::string comment = line.comment();
|
std::string comment = line.comment();
|
||||||
|
|
|
@ -106,6 +106,7 @@ private:
|
||||||
GCodeReader m_parser;
|
GCodeReader m_parser;
|
||||||
TypeToMovesMap m_moves_map;
|
TypeToMovesMap m_moves_map;
|
||||||
ExtruderOffsetsMap m_extruder_offsets;
|
ExtruderOffsetsMap m_extruder_offsets;
|
||||||
|
GCodeFlavor m_gcode_flavor;
|
||||||
|
|
||||||
// The output of process_layer()
|
// The output of process_layer()
|
||||||
std::string m_process_output;
|
std::string m_process_output;
|
||||||
|
@ -115,6 +116,8 @@ public:
|
||||||
|
|
||||||
void set_extruder_offsets(const ExtruderOffsetsMap& extruder_offsets);
|
void set_extruder_offsets(const ExtruderOffsetsMap& extruder_offsets);
|
||||||
|
|
||||||
|
void set_gcode_flavor(const GCodeFlavor& flavor);
|
||||||
|
|
||||||
// Reinitialize the analyzer
|
// Reinitialize the analyzer
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -164,10 +167,14 @@ private:
|
||||||
// Set extruder to relative mode
|
// Set extruder to relative mode
|
||||||
void _processM83(const GCodeReader::GCodeLine& line);
|
void _processM83(const GCodeReader::GCodeLine& line);
|
||||||
|
|
||||||
|
// Set tool (MakerWare and Sailfish flavor)
|
||||||
|
void _processM108orM135(const GCodeReader::GCodeLine& line);
|
||||||
|
|
||||||
// Set color change
|
// Set color change
|
||||||
void _processM600(const GCodeReader::GCodeLine& line);
|
void _processM600(const GCodeReader::GCodeLine& line);
|
||||||
|
|
||||||
// Processes T line (Select Tool)
|
// Processes T line (Select Tool)
|
||||||
|
void _processT(const std::string& command);
|
||||||
void _processT(const GCodeReader::GCodeLine& line);
|
void _processT(const GCodeReader::GCodeLine& line);
|
||||||
|
|
||||||
// Processes the tags
|
// Processes the tags
|
||||||
|
|
|
@ -410,6 +410,8 @@ public:
|
||||||
BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const;
|
BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const;
|
||||||
// caching variant
|
// caching variant
|
||||||
const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
|
const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
|
||||||
|
// convex hull
|
||||||
|
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
|
||||||
|
|
||||||
bool empty() const { return this->indexed_vertex_array.empty(); }
|
bool empty() const { return this->indexed_vertex_array.empty(); }
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,28 @@ namespace Slic3r
|
||||||
namespace GUI
|
namespace GUI
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function to be used by drop to bed button. Returns lowest point of this
|
||||||
|
// volume in world coordinate system.
|
||||||
|
static double get_volume_min_z(const GLVolume* volume)
|
||||||
|
{
|
||||||
|
const Transform3f& world_matrix = volume->world_matrix().cast<float>();
|
||||||
|
|
||||||
|
// need to get the ModelVolume pointer
|
||||||
|
const ModelObject* mo = wxGetApp().model_objects()->at(volume->composite_id.object_id);
|
||||||
|
const ModelVolume* mv = mo->volumes[volume->composite_id.volume_id];
|
||||||
|
const TriangleMesh& hull = mv->get_convex_hull();
|
||||||
|
|
||||||
|
float min_z = std::numeric_limits<float>::max();
|
||||||
|
for (const stl_facet& facet : hull.stl.facet_start) {
|
||||||
|
for (int i = 0; i < 3; ++ i)
|
||||||
|
min_z = std::min(min_z, Vec3f::UnitZ().dot(world_matrix * facet.vertex[i]));
|
||||||
|
}
|
||||||
|
return min_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static wxBitmapComboBox* create_word_local_combo(wxWindow *parent)
|
static wxBitmapComboBox* create_word_local_combo(wxWindow *parent)
|
||||||
{
|
{
|
||||||
wxSize size(15 * wxGetApp().em_unit(), -1);
|
wxSize size(15 * wxGetApp().em_unit(), -1);
|
||||||
|
@ -185,7 +207,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
unsigned int axis_idx = (axis[0] - 'x'); // 0, 1 or 2
|
unsigned int axis_idx = (axis[0] - 'x'); // 0, 1 or 2
|
||||||
|
|
||||||
// We will add a button to toggle mirroring to each axis:
|
// We will add a button to toggle mirroring to each axis:
|
||||||
auto mirror_button = [=](wxWindow* parent) {
|
auto mirror_button = [this, mirror_btn_width, axis_idx, &label](wxWindow* parent) {
|
||||||
wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width);
|
wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width);
|
||||||
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off.png", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
|
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off.png", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
|
||||||
btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), label));
|
btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), label));
|
||||||
|
@ -195,7 +217,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer->Add(btn);
|
sizer->Add(btn);
|
||||||
|
|
||||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
btn->Bind(wxEVT_BUTTON, [this, axis_idx](wxCommandEvent &e) {
|
||||||
Axis axis = (Axis)(axis_idx + X);
|
Axis axis = (Axis)(axis_idx + X);
|
||||||
if (m_mirror_buttons[axis_idx].second == mbHidden)
|
if (m_mirror_buttons[axis_idx].second == mbHidden)
|
||||||
return;
|
return;
|
||||||
|
@ -258,13 +280,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
return btn;
|
return btn;
|
||||||
};
|
};
|
||||||
// Add reset scale button
|
// Add reset scale button
|
||||||
auto reset_scale_button = [=](wxWindow* parent) {
|
auto reset_scale_button = [this](wxWindow* parent) {
|
||||||
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||||
btn->SetToolTip(_(L("Reset scale")));
|
btn->SetToolTip(_(L("Reset scale")));
|
||||||
m_reset_scale_button = btn;
|
m_reset_scale_button = btn;
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer->Add(btn, wxBU_EXACTFIT);
|
sizer->Add(btn, wxBU_EXACTFIT);
|
||||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
|
||||||
change_scale_value(0, 100.);
|
change_scale_value(0, 100.);
|
||||||
change_scale_value(1, 100.);
|
change_scale_value(1, 100.);
|
||||||
change_scale_value(2, 100.);
|
change_scale_value(2, 100.);
|
||||||
|
@ -275,13 +297,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
}
|
}
|
||||||
else if (option_name == "Rotation") {
|
else if (option_name == "Rotation") {
|
||||||
// Add reset rotation button
|
// Add reset rotation button
|
||||||
auto reset_rotation_button = [=](wxWindow* parent) {
|
auto reset_rotation_button = [this](wxWindow* parent) {
|
||||||
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||||
btn->SetToolTip(_(L("Reset rotation")));
|
btn->SetToolTip(_(L("Reset rotation")));
|
||||||
m_reset_rotation_button = btn;
|
m_reset_rotation_button = btn;
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer->Add(btn, wxBU_EXACTFIT);
|
sizer->Add(btn, wxBU_EXACTFIT);
|
||||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
|
|
||||||
|
@ -310,6 +332,34 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
};
|
};
|
||||||
line.append_widget(reset_rotation_button);
|
line.append_widget(reset_rotation_button);
|
||||||
}
|
}
|
||||||
|
else if (option_name == "Position") {
|
||||||
|
// Add drop to bed button
|
||||||
|
auto drop_to_bed_button = [=](wxWindow* parent) {
|
||||||
|
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "drop_to_bed.png"));
|
||||||
|
btn->SetToolTip(_(L("Drop to bed")));
|
||||||
|
m_drop_to_bed_button = btn;
|
||||||
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
sizer->Add(btn, wxBU_EXACTFIT);
|
||||||
|
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||||
|
// ???
|
||||||
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
|
Selection& selection = canvas->get_selection();
|
||||||
|
|
||||||
|
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||||
|
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
|
|
||||||
|
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation();
|
||||||
|
Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume));
|
||||||
|
|
||||||
|
change_position_value(0, diff.x());
|
||||||
|
change_position_value(1, diff.y());
|
||||||
|
change_position_value(2, diff.z());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sizer;
|
||||||
|
};
|
||||||
|
line.append_widget(drop_to_bed_button);
|
||||||
|
}
|
||||||
// Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment
|
// Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment
|
||||||
else if (option_name == "Size") {
|
else if (option_name == "Size") {
|
||||||
line.near_label_widget = [this](wxWindow* parent) {
|
line.near_label_widget = [this](wxWindow* parent) {
|
||||||
|
@ -536,11 +586,13 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
||||||
|
|
||||||
bool show_rotation = false;
|
bool show_rotation = false;
|
||||||
bool show_scale = false;
|
bool show_scale = false;
|
||||||
|
bool show_drop_to_bed = false;
|
||||||
|
|
||||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
Vec3d rotation;
|
Vec3d rotation;
|
||||||
Vec3d scale;
|
Vec3d scale;
|
||||||
|
double min_z = 0.;
|
||||||
|
|
||||||
if (selection.is_single_full_instance()) {
|
if (selection.is_single_full_instance()) {
|
||||||
rotation = volume->get_instance_rotation();
|
rotation = volume->get_instance_rotation();
|
||||||
|
@ -549,14 +601,17 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
||||||
else {
|
else {
|
||||||
rotation = volume->get_volume_rotation();
|
rotation = volume->get_volume_rotation();
|
||||||
scale = volume->get_volume_scaling_factor();
|
scale = volume->get_volume_scaling_factor();
|
||||||
|
min_z = get_volume_min_z(volume);
|
||||||
}
|
}
|
||||||
show_rotation = !rotation.isApprox(Vec3d::Zero());
|
show_rotation = !rotation.isApprox(Vec3d::Zero());
|
||||||
show_scale = !scale.isApprox(Vec3d::Ones());
|
show_scale = !scale.isApprox(Vec3d::Ones());
|
||||||
|
show_drop_to_bed = (std::abs(min_z) > EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxGetApp().CallAfter([this, show_rotation, show_scale]{
|
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed]{
|
||||||
m_reset_rotation_button->Show(show_rotation);
|
m_reset_rotation_button->Show(show_rotation);
|
||||||
m_reset_scale_button->Show(show_scale);
|
m_reset_scale_button->Show(show_scale);
|
||||||
|
m_drop_to_bed_button->Show(show_drop_to_bed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -869,6 +924,7 @@ void ObjectManipulation::msw_rescale()
|
||||||
m_mirror_bitmap_hidden.msw_rescale();
|
m_mirror_bitmap_hidden.msw_rescale();
|
||||||
m_reset_scale_button->msw_rescale();
|
m_reset_scale_button->msw_rescale();
|
||||||
m_reset_rotation_button->msw_rescale();
|
m_reset_rotation_button->msw_rescale();
|
||||||
|
m_drop_to_bed_button->msw_rescale();
|
||||||
|
|
||||||
get_og()->msw_rescale();
|
get_og()->msw_rescale();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ class ObjectManipulation : public OG_Settings
|
||||||
// Non-owning pointers to the reset buttons, so we can hide and show them.
|
// Non-owning pointers to the reset buttons, so we can hide and show them.
|
||||||
ScalableButton* m_reset_scale_button = nullptr;
|
ScalableButton* m_reset_scale_button = nullptr;
|
||||||
ScalableButton* m_reset_rotation_button = nullptr;
|
ScalableButton* m_reset_rotation_button = nullptr;
|
||||||
|
ScalableButton* m_drop_to_bed_button = nullptr;
|
||||||
|
|
||||||
// Mirroring buttons and their current state
|
// Mirroring buttons and their current state
|
||||||
enum MirrorButtonState {
|
enum MirrorButtonState {
|
||||||
|
|
Loading…
Reference in a new issue