From f761691b7d733a19d6c8fb42d03f23c5956d6f00 Mon Sep 17 00:00:00 2001 From: tamasmeszaros <meszaros.q@gmail.com> Date: Fri, 4 Jan 2019 16:24:10 +0100 Subject: [PATCH 01/14] Pad now has adjustable wall tilt and maintains wall thickness properly. Edges are not rounded yet. --- src/libslic3r/SLA/SLABasePool.cpp | 208 ++++++++++++++++++--------- src/libslic3r/SLA/SLABasePool.hpp | 6 +- src/libslic3r/SLA/SLASupportTree.cpp | 8 +- src/libslic3r/SLAPrint.cpp | 2 +- 4 files changed, 149 insertions(+), 75 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 21bd124f7..a819d16ca 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -457,104 +457,172 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, const PoolConfig& cfg) { - double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) + - cfg.max_merge_distance_mm; - auto concavehs = concave_hull(ground_layer, mdist, cfg.throw_on_cancel); + double mergedist = 2*(1.8*cfg.min_wall_thickness_mm /*+ 4*cfg.edge_radius_mm*/)+ + cfg.max_merge_distance_mm; + + auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel); + + for(ExPolygon& concaveh : concavehs) { if(concaveh.contour.points.empty()) return; concaveh.holes.clear(); - const coord_t WALL_THICKNESS = mm(cfg.min_wall_thickness_mm); - - const coord_t WALL_DISTANCE = mm(2*cfg.edge_radius_mm) + - coord_t(0.8*WALL_THICKNESS); - - const coord_t HEIGHT = mm(cfg.min_wall_height_mm); + const double thickness = cfg.min_wall_thickness_mm; + const double wingheight = cfg.min_wall_height_mm; + const coord_t s_thickness = mm(thickness); +// const coord_t s_eradius = mm(cfg.edge_radius_mm); + const coord_t s_safety_dist = /*2*s_eradius +*/ coord_t(0.8*s_thickness); + // const coord_t wheight = mm(cfg.min_wall_height_mm); + const double tilt = PI/4; + coord_t s_wingdist = mm(wingheight / std::tan(tilt)); + // Here lies the trick that does the smooting only with clipper offset + // calls. The offset is configured to round edges. Inner edges will + // be rounded because we offset twice: ones to get the outer (top) plate + // and again to get the inner (bottom) plate auto outer_base = concaveh; - offset(outer_base, WALL_THICKNESS+WALL_DISTANCE); + offset(outer_base, s_safety_dist + s_wingdist + s_thickness); auto inner_base = outer_base; - offset(inner_base, -WALL_THICKNESS); - inner_base.holes.clear(); outer_base.holes.clear(); + auto middle_base = outer_base; + offset(inner_base, -(s_thickness + s_wingdist)); + offset(middle_base, -s_thickness); + inner_base.holes.clear(); // bottom contour + middle_base.holes.clear(); // contour of the cavity-top + outer_base.holes.clear(); // bottom contour, also for the cavity + // Punching a hole in the top plate for the cavity ExPolygon top_poly; top_poly.contour = outer_base.contour; - top_poly.holes.emplace_back(inner_base.contour); + top_poly.holes.emplace_back(middle_base.contour); auto& tph = top_poly.holes.back().points; std::reverse(tph.begin(), tph.end()); Contour3D pool; - ExPolygon ob = outer_base; double wh = 0; + double fullheight = wingheight + thickness; + auto& thrcl = cfg.throw_on_cancel; - // now we will calculate the angle or portion of the circle from - // pi/2 that will connect perfectly with the bottom plate. - // this is a tangent point calculation problem and the equation can - // be found for example here: - // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm - // the y coordinate would be: - // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2) - // where px and py are the coordinates of the point outside the circle - // cx and cy are the circle center, r is the radius - // to get the angle we use arcsin function and subtract 90 degrees then - // flip the sign to get the right input to the round_edge function. - double r = cfg.edge_radius_mm; - double cy = 0; - double cx = 0; - double px = cfg.min_wall_thickness_mm; - double py = r - cfg.min_wall_height_mm; - - double pxcx = px - cx; - double pycy = py - cy; - double b_2 = pxcx*pxcx + pycy*pycy; - double r_2 = r*r; - double D = std::sqrt(b_2 - r_2); - double vy = (r_2*pycy - r*pxcx*D) / b_2; - double phi = -(std::asin(vy/r) * 180 / PI - 90); - - auto curvedwalls = round_edges(ob, - r, - phi, // 170 degrees - 0, // z position of the input plane - true, - cfg.throw_on_cancel, - ob, wh); - - pool.merge(curvedwalls); - - ExPolygon ob_contr = ob; - ob_contr.holes.clear(); - - auto pwalls = walls(ob_contr, inner_base, wh, -cfg.min_wall_height_mm, - cfg.throw_on_cancel); + auto pwalls = walls(top_poly, inner_base, 0, -fullheight, thrcl); pool.merge(pwalls); - Polygons top_triangles, bottom_triangles; + auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl); + pool.merge(cavitywalls); + + Polygons top_triangles, middle_triangles, bottom_triangles; + triangulate(top_poly, top_triangles); + triangulate(inner_base, middle_triangles); triangulate(inner_base, bottom_triangles); auto top_plate = convert(top_triangles, 0, false); - auto bottom_plate = convert(bottom_triangles, -HEIGHT, true); - - ob = inner_base; wh = 0; - // rounded edge generation for the inner bed - curvedwalls = round_edges(ob, - cfg.edge_radius_mm, - 90, // 90 degrees - 0, // z position of the input plane - false, - cfg.throw_on_cancel, - ob, wh); - pool.merge(curvedwalls); - - auto innerbed = inner_bed(ob, cfg.min_wall_height_mm/2 + wh, wh); + auto middle_plate = convert(middle_triangles, -mm(wingheight), false); + auto bottom_plate = convert(bottom_triangles, -mm(fullheight), true); pool.merge(top_plate); + pool.merge(middle_plate); pool.merge(bottom_plate); - pool.merge(innerbed); out.merge(mesh(pool)); } + +// double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) + +// cfg.max_merge_distance_mm; + +// auto concavehs = concave_hull(ground_layer, mdist, cfg.throw_on_cancel); +// for(ExPolygon& concaveh : concavehs) { +// if(concaveh.contour.points.empty()) return; +// concaveh.holes.clear(); + +// const coord_t WALL_THICKNESS = mm(cfg.min_wall_thickness_mm); + +// const coord_t WALL_DISTANCE = mm(2*cfg.edge_radius_mm) + +// coord_t(0.8*WALL_THICKNESS); + +// const coord_t HEIGHT = mm(cfg.min_wall_height_mm); + +// auto outer_base = concaveh; +// offset(outer_base, WALL_THICKNESS+WALL_DISTANCE); +// auto inner_base = outer_base; +// offset(inner_base, -WALL_THICKNESS); +// inner_base.holes.clear(); outer_base.holes.clear(); + +// ExPolygon top_poly; +// top_poly.contour = outer_base.contour; +// top_poly.holes.emplace_back(inner_base.contour); +// auto& tph = top_poly.holes.back().points; +// std::reverse(tph.begin(), tph.end()); + +// Contour3D pool; + +// ExPolygon ob = outer_base; double wh = 0; + +// // now we will calculate the angle or portion of the circle from +// // pi/2 that will connect perfectly with the bottom plate. +// // this is a tangent point calculation problem and the equation can +// // be found for example here: +// // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm +// // the y coordinate would be: +// // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2) +// // where px and py are the coordinates of the point outside the circle +// // cx and cy are the circle center, r is the radius +// // to get the angle we use arcsin function and subtract 90 degrees then +// // flip the sign to get the right input to the round_edge function. +// double r = cfg.edge_radius_mm; +// double cy = 0; +// double cx = 0; +// double px = cfg.min_wall_thickness_mm; +// double py = r - cfg.min_wall_height_mm; + +// double pxcx = px - cx; +// double pycy = py - cy; +// double b_2 = pxcx*pxcx + pycy*pycy; +// double r_2 = r*r; +// double D = std::sqrt(b_2 - r_2); +// double vy = (r_2*pycy - r*pxcx*D) / b_2; +// double phi = -(std::asin(vy/r) * 180 / PI - 90); + +// auto curvedwalls = round_edges(ob, +// r, +// phi, // 170 degrees +// 0, // z position of the input plane +// true, +// cfg.throw_on_cancel, +// ob, wh); + +// pool.merge(curvedwalls); + +// ExPolygon ob_contr = ob; +// ob_contr.holes.clear(); + +// auto pwalls = walls(ob_contr, inner_base, wh, -cfg.min_wall_height_mm, +// cfg.throw_on_cancel); +// pool.merge(pwalls); + +// Polygons top_triangles, bottom_triangles; +// triangulate(top_poly, top_triangles); +// triangulate(inner_base, bottom_triangles); +// auto top_plate = convert(top_triangles, 0, false); +// auto bottom_plate = convert(bottom_triangles, -HEIGHT, true); + +// ob = inner_base; wh = 0; +// // rounded edge generation for the inner bed +// curvedwalls = round_edges(ob, +// cfg.edge_radius_mm, +// 90, // 90 degrees +// 0, // z position of the input plane +// false, +// cfg.throw_on_cancel, +// ob, wh); +// pool.merge(curvedwalls); + +// auto innerbed = inner_bed(ob, cfg.min_wall_height_mm/2 + wh, wh); + +// pool.merge(top_plate); +// pool.merge(bottom_plate); +// pool.merge(innerbed); + +// out.merge(mesh(pool)); +// } } } diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp index 62c4971eb..3917d995b 100644 --- a/src/libslic3r/SLA/SLABasePool.hpp +++ b/src/libslic3r/SLA/SLABasePool.hpp @@ -49,7 +49,11 @@ void create_base_pool(const ExPolygons& base_plate, /// min_wall_thickness and it should be corrected in the future. This method /// will return the correct value for further processing. inline double get_pad_elevation(const PoolConfig& cfg) { - return cfg.min_wall_height_mm / 2.0; + return cfg.min_wall_thickness_mm; +} + +inline double get_pad_fullheight(const PoolConfig& cfg) { + return cfg.min_wall_height_mm + cfg.min_wall_thickness_mm; } } diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 746acc547..5239255b1 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -515,7 +515,8 @@ struct Pad { double ground_level, const PoolConfig& pcfg) : cfg(pcfg), - zlevel(ground_level + sla::get_pad_elevation(pcfg)) + zlevel(ground_level + + (sla::get_pad_fullheight(pcfg) - sla::get_pad_elevation(pcfg)) ) { ExPolygons basep; cfg.throw_on_cancel(); @@ -523,7 +524,8 @@ struct Pad { // The 0.1f is the layer height with which the mesh is sampled and then // the layers are unified into one vector of polygons. base_plate(object_support_mesh, basep, - float(cfg.min_wall_height_mm), 0.1f, pcfg.throw_on_cancel); + float(cfg.min_wall_height_mm + cfg.min_wall_thickness_mm), + 0.1f, pcfg.throw_on_cancel); for(auto& bp : baseplate) basep.emplace_back(bp); @@ -781,7 +783,7 @@ public: // WITH THE PAD double full_height() const { if(merged_mesh().empty() && !pad().empty()) - return pad().cfg.min_wall_height_mm; + return get_pad_fullheight(pad().cfg); double h = mesh_height(); if(!pad().empty()) h += sla::get_pad_elevation(pad().cfg); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index f45d805b6..aa759a47a 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -630,7 +630,7 @@ void SLAPrint::process() sla::PoolConfig pcfg(wt, h, md, er); ExPolygons bp; - double pad_h = sla::get_pad_elevation(pcfg); + double pad_h = sla::get_pad_fullheight(pcfg); auto&& trmesh = po.transformed_mesh(); // This call can get pretty time consuming From fa5c96dfb9e3a75b97e8eb8670a6af0d4b65894e Mon Sep 17 00:00:00 2001 From: tamasmeszaros <meszaros.q@gmail.com> Date: Fri, 4 Jan 2019 16:57:27 +0100 Subject: [PATCH 02/14] Recover outer top radius for the new pad. Inner top, bottom and outer bottom radius still missing. --- src/libslic3r/SLA/SLABasePool.cpp | 57 ++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index a819d16ca..598e6f66d 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -458,7 +458,7 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, const PoolConfig& cfg) { - double mergedist = 2*(1.8*cfg.min_wall_thickness_mm /*+ 4*cfg.edge_radius_mm*/)+ + double mergedist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm)+ cfg.max_merge_distance_mm; auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel); @@ -470,12 +470,16 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, const double thickness = cfg.min_wall_thickness_mm; const double wingheight = cfg.min_wall_height_mm; - const coord_t s_thickness = mm(thickness); -// const coord_t s_eradius = mm(cfg.edge_radius_mm); - const coord_t s_safety_dist = /*2*s_eradius +*/ coord_t(0.8*s_thickness); - // const coord_t wheight = mm(cfg.min_wall_height_mm); + const double fullheight = wingheight + thickness; const double tilt = PI/4; - coord_t s_wingdist = mm(wingheight / std::tan(tilt)); + const double wingdist = wingheight / std::tan(tilt); + + // scaled values + const coord_t s_thickness = mm(thickness); + const coord_t s_eradius = mm(cfg.edge_radius_mm); + const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness); + // const coord_t wheight = mm(cfg.min_wall_height_mm); + coord_t s_wingdist = mm(wingdist); // Here lies the trick that does the smooting only with clipper offset // calls. The offset is configured to round edges. Inner edges will @@ -500,10 +504,47 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, Contour3D pool; - double fullheight = wingheight + thickness; + ExPolygon ob = outer_base; double wh = 0; + + // now we will calculate the angle or portion of the circle from + // pi/2 that will connect perfectly with the bottom plate. + // this is a tangent point calculation problem and the equation can + // be found for example here: + // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm + // the y coordinate would be: + // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2) + // where px and py are the coordinates of the point outside the circle + // cx and cy are the circle center, r is the radius + // to get the angle we use arcsin function and subtract 90 degrees then + // flip the sign to get the right input to the round_edge function. + double r = cfg.edge_radius_mm; + double cy = 0; + double cx = 0; + double px = thickness + wingdist; + double py = r - fullheight; + + double pxcx = px - cx; + double pycy = py - cy; + double b_2 = pxcx*pxcx + pycy*pycy; + double r_2 = r*r; + double D = std::sqrt(b_2 - r_2); + double vy = (r_2*pycy - r*pxcx*D) / b_2; + double phi = -(std::asin(vy/r) * 180 / PI - 90); + + auto curvedwalls = round_edges(ob, + r, + phi, // 170 degrees + 0, // z position of the input plane + true, + cfg.throw_on_cancel, + ob, wh); + + pool.merge(curvedwalls); + + auto& thrcl = cfg.throw_on_cancel; - auto pwalls = walls(top_poly, inner_base, 0, -fullheight, thrcl); + auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl); pool.merge(pwalls); auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl); From 0c7fbe0a9356999bc1da5573e75929cfa8948cc1 Mon Sep 17 00:00:00 2001 From: tamasmeszaros <meszaros.q@gmail.com> Date: Mon, 7 Jan 2019 10:07:49 +0100 Subject: [PATCH 03/14] Comments and cosmetics for the new pad code. --- src/libslic3r/SLA/SLABasePool.cpp | 51 ++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 598e6f66d..5dbbb0440 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -461,26 +461,34 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, double mergedist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm)+ cfg.max_merge_distance_mm; + // Here we get the base polygon from which the pad has to be generated. + // We create an artificial concave hull from this polygon and that will + // serve as the bottom plate of the pad. We will offset this concave hull + // and then offset back the result with clipper with rounding edges ON. This + // trick will create a nice rounded pad shape. auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel); + const double thickness = cfg.min_wall_thickness_mm; + const double wingheight = cfg.min_wall_height_mm; + const double fullheight = wingheight + thickness; + const double tilt = PI/4; + const double wingdist = wingheight / std::tan(tilt); + + // scaled values + const coord_t s_thickness = mm(thickness); + const coord_t s_eradius = mm(cfg.edge_radius_mm); + const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness); + // const coord_t wheight = mm(cfg.min_wall_height_mm); + coord_t s_wingdist = mm(wingdist); + + auto& thrcl = cfg.throw_on_cancel; for(ExPolygon& concaveh : concavehs) { if(concaveh.contour.points.empty()) return; + + // Get rif of any holes in the concave hull output. concaveh.holes.clear(); - const double thickness = cfg.min_wall_thickness_mm; - const double wingheight = cfg.min_wall_height_mm; - const double fullheight = wingheight + thickness; - const double tilt = PI/4; - const double wingdist = wingheight / std::tan(tilt); - - // scaled values - const coord_t s_thickness = mm(thickness); - const coord_t s_eradius = mm(cfg.edge_radius_mm); - const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness); - // const coord_t wheight = mm(cfg.min_wall_height_mm); - coord_t s_wingdist = mm(wingdist); - // Here lies the trick that does the smooting only with clipper offset // calls. The offset is configured to round edges. Inner edges will // be rounded because we offset twice: ones to get the outer (top) plate @@ -515,6 +523,8 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2) // where px and py are the coordinates of the point outside the circle // cx and cy are the circle center, r is the radius + // We place the circle center to (0, 0) in the calculation the make + // things easier. // to get the angle we use arcsin function and subtract 90 degrees then // flip the sign to get the right input to the round_edge function. double r = cfg.edge_radius_mm; @@ -531,25 +541,30 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, double vy = (r_2*pycy - r*pxcx*D) / b_2; double phi = -(std::asin(vy/r) * 180 / PI - 90); + + // Generate the smoothed edge geometry auto curvedwalls = round_edges(ob, r, phi, // 170 degrees 0, // z position of the input plane true, - cfg.throw_on_cancel, + thrcl, ob, wh); - pool.merge(curvedwalls); - - auto& thrcl = cfg.throw_on_cancel; - + // Now that we have the rounded edge connencting the top plate with + // the outer side walls, we can generate and merge the sidewall geometry auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl); pool.merge(pwalls); + // Next is the cavity walls connecting to the top plate's artificially + // created hole. auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl); pool.merge(cavitywalls); + // Now we need to triangulate the top and bottom plates as well as the + // cavity bottom plate which is the same as the bottom plate but it is + // eleveted by the thickness. Polygons top_triangles, middle_triangles, bottom_triangles; triangulate(top_poly, top_triangles); From 4d0c0ac7483eac299fea266d9a35e8e10e3cd5de Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 8 Jan 2019 11:47:05 +0100 Subject: [PATCH 04/14] Fix of Cyrillic named files inside the object list (part of the #1622) --- src/slic3r/GUI/GUI_ObjectList.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0b6c38bd8..729946dbf 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -849,7 +849,7 @@ void ObjectList::load_part( ModelObject* model_object, new_volume->set_type(static_cast<ModelVolume::Type>(type)); new_volume->name = boost::filesystem::path(input_file).filename().string(); - part_names.Add(new_volume->name); + part_names.Add(from_u8(new_volume->name)); // set a default extruder value, since user can't add it manually new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); @@ -903,7 +903,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int m_parts_changed = true; parts_changed(obj_idx); - select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type)); + select_item(m_objects_model->AddVolumeChild(GetSelection(), from_u8(name), type)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); #endif //no __WXOSX__ //__WXMSW__ @@ -1031,7 +1031,7 @@ void ObjectList::split() parent = item; for (auto id = 0; id < model_object->volumes.size(); id++) { - const auto vol_item = m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, + const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name), model_object->volumes[id]->is_modifier() ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, model_object->volumes[id]->config.has("extruder") ? @@ -1188,7 +1188,7 @@ void ObjectList::part_selection_changed() void ObjectList::add_object_to_list(size_t obj_idx) { auto model_object = (*m_objects)[obj_idx]; - wxString item_name = model_object->name; + wxString item_name = from_u8(model_object->name); const auto item = m_objects_model->Add(item_name, !model_object->config.has("extruder") ? 0 : model_object->config.option<ConfigOptionInt>("extruder")->value); @@ -1207,8 +1207,8 @@ void ObjectList::add_object_to_list(size_t obj_idx) if (model_object->volumes.size() > 1) { for (auto id = 0; id < model_object->volumes.size(); id++) { auto vol_item = m_objects_model->AddVolumeChild(item, - model_object->volumes[id]->name, - model_object->volumes[id]->type()/*ModelVolume::MODEL_PART*/, + from_u8(model_object->volumes[id]->name), + model_object->volumes[id]->type(), !model_object->volumes[id]->config.has("extruder") ? 0 : model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value, false); From 24e0c9b79e7faca2a3cf5a07c216648b385daf1a Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 8 Jan 2019 13:34:47 +0100 Subject: [PATCH 05/14] Added "uniform scaling" button --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 24 +++++++++++++++++++++-- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 4 ++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index f763cc5a1..1cdf87be2 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -19,7 +19,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) { m_og->set_name(_(L("Object Manipulation"))); - m_og->label_width = 100; + m_og->label_width = 125; m_og->set_grid_vgap(5); m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) { @@ -150,7 +150,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_og->append_line(line); - auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext) + auto add_og_to_object_settings = [this](const std::string& option_name, const std::string& sidetext) { Line line = { _(option_name), "" }; ConfigOptionDef def; @@ -164,6 +164,26 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : def.max = 360; } + // Add "uniform scaling" button in front of "Scale" option + else if (option_name == "Scale") { + line.near_label_widget = [this](wxWindow* parent) { + auto btn = new PrusaLockButton(parent, wxID_ANY); + btn->Bind(wxEVT_BUTTON, [btn, this](wxCommandEvent &event){ + event.Skip(); + wxTheApp->CallAfter([btn, this]() { set_uniform_scaling(btn->IsLocked()); }); + }); + return btn; + }; + } + + // Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment + else if (option_name == "Size") { + line.near_label_widget = [this](wxWindow* parent) { + return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, + wxBitmap(from_u8(var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG).GetSize()); + }; + } + const std::string lower_name = boost::algorithm::to_lower_copy(option_name); std::vector<std::string> axes{ "x", "y", "z" }; diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 97cd2b639..57eb93b71 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -74,6 +74,7 @@ class ObjectManipulation : public OG_Settings Vec3d m_new_scale; Vec3d m_new_size; bool m_new_enabled; + bool m_uniform_scale {false}; public: ObjectManipulation(wxWindow* parent); @@ -88,6 +89,9 @@ public: // Called from the App to update the UI if dirty. void update_if_dirty(); + void set_uniform_scaling(const bool uniform_scale) { m_uniform_scale = uniform_scale;} + bool get_uniform_scaling() const { return m_uniform_scale; } + private: void reset_settings_value(); From f26ec7feb37c9a088b99e9df74922e0d15ede149 Mon Sep 17 00:00:00 2001 From: tamasmeszaros <meszaros.q@gmail.com> Date: Tue, 8 Jan 2019 14:03:41 +0100 Subject: [PATCH 06/14] pad wall smoothing only for the top of the wall. --- src/libslic3r/SLA/SLABasePool.cpp | 195 +++++++++--------------------- 1 file changed, 55 insertions(+), 140 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 5dbbb0440..fb68ae1d0 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -215,41 +215,67 @@ inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) { return lower; } -template<class ExP, class D> Contour3D round_edges(const ExPolygon& base_plate, double radius_mm, double degrees, double ceilheight_mm, bool dir, ThrowOnCancel throw_on_cancel, - ExP&& last_offset = ExP(), D&& last_height = D()) + ExPolygon& last_offset, double& last_height) { auto ob = base_plate; auto ob_prev = ob; double wh = ceilheight_mm, wh_prev = wh; Contour3D curvedwalls; - int steps = 15; // int(std::ceil(10*std::pow(radius_mm, 1.0/3))); + int steps = 30; double stepx = radius_mm / steps; coord_t s = dir? 1 : -1; degrees = std::fmod(degrees, 180); - if(degrees >= 90) { - for(int i = 1; i <= steps; ++i) { - throw_on_cancel(); + // we use sin for x distance because we interpret the angle starting from + // PI/2 + int tos = degrees < 90? + int(radius_mm*std::cos(degrees * PI / 180 - PI/2) / stepx) : steps; + for(int i = 1; i <= tos; ++i) { + throw_on_cancel(); + + ob = base_plate; + + double r2 = radius_mm * radius_mm; + double xx = i*stepx; + double x2 = xx*xx; + double stepy = std::sqrt(r2 - x2); + + offset(ob, s*mm(xx)); + wh = ceilheight_mm - radius_mm + stepy; + + Contour3D pwalls; + pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel); + + curvedwalls.merge(pwalls); + ob_prev = ob; + wh_prev = wh; + } + + if(degrees > 90) { + double tox = radius_mm - radius_mm*std::cos(degrees * PI / 180 - PI/2); + int tos = int(tox / stepx); + + for(int i = 1; i <= tos; ++i) { + throw_on_cancel(); ob = base_plate; double r2 = radius_mm * radius_mm; - double xx = i*stepx; + double xx = radius_mm - i*stepx; double x2 = xx*xx; double stepy = std::sqrt(r2 - x2); - offset(ob, s*mm(xx)); - wh = ceilheight_mm - radius_mm + stepy; + wh = ceilheight_mm - radius_mm - stepy; Contour3D pwalls; - pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel); + pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel); curvedwalls.merge(pwalls); ob_prev = ob; @@ -257,28 +283,6 @@ Contour3D round_edges(const ExPolygon& base_plate, } } - double tox = radius_mm - radius_mm*std::sin(degrees * PI / 180); - int tos = int(tox / stepx); - - for(int i = 1; i <= tos; ++i) { - throw_on_cancel(); - ob = base_plate; - - double r2 = radius_mm * radius_mm; - double xx = radius_mm - i*stepx; - double x2 = xx*xx; - double stepy = std::sqrt(r2 - x2); - offset(ob, s*mm(xx)); - wh = ceilheight_mm - radius_mm - stepy; - - Contour3D pwalls; - pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel); - - curvedwalls.merge(pwalls); - ob_prev = ob; - wh_prev = wh; - } - last_offset = std::move(ob); last_height = wh; @@ -543,23 +547,33 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // Generate the smoothed edge geometry - auto curvedwalls = round_edges(ob, - r, - phi, // 170 degrees - 0, // z position of the input plane - true, - thrcl, - ob, wh); - pool.merge(curvedwalls); + auto walledges = round_edges(ob, + r, + phi, // 170 degrees + 0, // z position of the input plane + true, + thrcl, + ob, wh); + pool.merge(walledges); // Now that we have the rounded edge connencting the top plate with // the outer side walls, we can generate and merge the sidewall geometry auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl); pool.merge(pwalls); + // Generate the smoothed edge geometry + auto cavityedges = round_edges(middle_base, + r, + phi - 90, // 170 degrees + 0, // z position of the input plane + false, + thrcl, + ob, wh); + pool.merge(cavityedges); + // Next is the cavity walls connecting to the top plate's artificially // created hole. - auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl); + auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl); pool.merge(cavitywalls); // Now we need to triangulate the top and bottom plates as well as the @@ -580,105 +594,6 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, out.merge(mesh(pool)); } - -// double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) + -// cfg.max_merge_distance_mm; - -// auto concavehs = concave_hull(ground_layer, mdist, cfg.throw_on_cancel); -// for(ExPolygon& concaveh : concavehs) { -// if(concaveh.contour.points.empty()) return; -// concaveh.holes.clear(); - -// const coord_t WALL_THICKNESS = mm(cfg.min_wall_thickness_mm); - -// const coord_t WALL_DISTANCE = mm(2*cfg.edge_radius_mm) + -// coord_t(0.8*WALL_THICKNESS); - -// const coord_t HEIGHT = mm(cfg.min_wall_height_mm); - -// auto outer_base = concaveh; -// offset(outer_base, WALL_THICKNESS+WALL_DISTANCE); -// auto inner_base = outer_base; -// offset(inner_base, -WALL_THICKNESS); -// inner_base.holes.clear(); outer_base.holes.clear(); - -// ExPolygon top_poly; -// top_poly.contour = outer_base.contour; -// top_poly.holes.emplace_back(inner_base.contour); -// auto& tph = top_poly.holes.back().points; -// std::reverse(tph.begin(), tph.end()); - -// Contour3D pool; - -// ExPolygon ob = outer_base; double wh = 0; - -// // now we will calculate the angle or portion of the circle from -// // pi/2 that will connect perfectly with the bottom plate. -// // this is a tangent point calculation problem and the equation can -// // be found for example here: -// // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm -// // the y coordinate would be: -// // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2) -// // where px and py are the coordinates of the point outside the circle -// // cx and cy are the circle center, r is the radius -// // to get the angle we use arcsin function and subtract 90 degrees then -// // flip the sign to get the right input to the round_edge function. -// double r = cfg.edge_radius_mm; -// double cy = 0; -// double cx = 0; -// double px = cfg.min_wall_thickness_mm; -// double py = r - cfg.min_wall_height_mm; - -// double pxcx = px - cx; -// double pycy = py - cy; -// double b_2 = pxcx*pxcx + pycy*pycy; -// double r_2 = r*r; -// double D = std::sqrt(b_2 - r_2); -// double vy = (r_2*pycy - r*pxcx*D) / b_2; -// double phi = -(std::asin(vy/r) * 180 / PI - 90); - -// auto curvedwalls = round_edges(ob, -// r, -// phi, // 170 degrees -// 0, // z position of the input plane -// true, -// cfg.throw_on_cancel, -// ob, wh); - -// pool.merge(curvedwalls); - -// ExPolygon ob_contr = ob; -// ob_contr.holes.clear(); - -// auto pwalls = walls(ob_contr, inner_base, wh, -cfg.min_wall_height_mm, -// cfg.throw_on_cancel); -// pool.merge(pwalls); - -// Polygons top_triangles, bottom_triangles; -// triangulate(top_poly, top_triangles); -// triangulate(inner_base, bottom_triangles); -// auto top_plate = convert(top_triangles, 0, false); -// auto bottom_plate = convert(bottom_triangles, -HEIGHT, true); - -// ob = inner_base; wh = 0; -// // rounded edge generation for the inner bed -// curvedwalls = round_edges(ob, -// cfg.edge_radius_mm, -// 90, // 90 degrees -// 0, // z position of the input plane -// false, -// cfg.throw_on_cancel, -// ob, wh); -// pool.merge(curvedwalls); - -// auto innerbed = inner_bed(ob, cfg.min_wall_height_mm/2 + wh, wh); - -// pool.merge(top_plate); -// pool.merge(bottom_plate); -// pool.merge(innerbed); - -// out.merge(mesh(pool)); -// } } } From e269758df70ede2cc279d43e8c3e2c8b8066fce2 Mon Sep 17 00:00:00 2001 From: tamasmeszaros <meszaros.q@gmail.com> Date: Tue, 8 Jan 2019 14:42:29 +0100 Subject: [PATCH 07/14] Don't generate the pad cavity if the depth is zero. --- src/libslic3r/SLA/SLABasePool.cpp | 61 ++++++++++++++++++------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index fb68ae1d0..f1e79357d 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -498,21 +498,23 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // be rounded because we offset twice: ones to get the outer (top) plate // and again to get the inner (bottom) plate auto outer_base = concaveh; + outer_base.holes.clear(); offset(outer_base, s_safety_dist + s_wingdist + s_thickness); auto inner_base = outer_base; - auto middle_base = outer_base; offset(inner_base, -(s_thickness + s_wingdist)); - offset(middle_base, -s_thickness); - inner_base.holes.clear(); // bottom contour - middle_base.holes.clear(); // contour of the cavity-top - outer_base.holes.clear(); // bottom contour, also for the cavity // Punching a hole in the top plate for the cavity ExPolygon top_poly; + ExPolygon middle_base; top_poly.contour = outer_base.contour; - top_poly.holes.emplace_back(middle_base.contour); - auto& tph = top_poly.holes.back().points; - std::reverse(tph.begin(), tph.end()); + + if(wingheight > 0) { + middle_base = outer_base; + offset(middle_base, -s_thickness); + top_poly.holes.emplace_back(middle_base.contour); + auto& tph = top_poly.holes.back().points; + std::reverse(tph.begin(), tph.end()); + } Contour3D pool; @@ -549,7 +551,7 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, // Generate the smoothed edge geometry auto walledges = round_edges(ob, r, - phi, // 170 degrees + phi, 0, // z position of the input plane true, thrcl, @@ -561,37 +563,44 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl); pool.merge(pwalls); - // Generate the smoothed edge geometry - auto cavityedges = round_edges(middle_base, - r, - phi - 90, // 170 degrees - 0, // z position of the input plane - false, - thrcl, - ob, wh); - pool.merge(cavityedges); + if(wingheight > 0) { + // Generate the smoothed edge geometry + auto cavityedges = round_edges(middle_base, + r, + phi - 90, // from tangent lines + 0, + false, + thrcl, + ob, wh); + pool.merge(cavityedges); - // Next is the cavity walls connecting to the top plate's artificially - // created hole. - auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl); - pool.merge(cavitywalls); + // Next is the cavity walls connecting to the top plate's + // artificially created hole. + auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl); + pool.merge(cavitywalls); + } // Now we need to triangulate the top and bottom plates as well as the // cavity bottom plate which is the same as the bottom plate but it is // eleveted by the thickness. - Polygons top_triangles, middle_triangles, bottom_triangles; + Polygons top_triangles, bottom_triangles; triangulate(top_poly, top_triangles); - triangulate(inner_base, middle_triangles); triangulate(inner_base, bottom_triangles); + auto top_plate = convert(top_triangles, 0, false); - auto middle_plate = convert(middle_triangles, -mm(wingheight), false); auto bottom_plate = convert(bottom_triangles, -mm(fullheight), true); pool.merge(top_plate); - pool.merge(middle_plate); pool.merge(bottom_plate); + if(wingheight > 0) { + Polygons middle_triangles; + triangulate(inner_base, middle_triangles); + auto middle_plate = convert(middle_triangles, -mm(wingheight), false); + pool.merge(middle_plate); + } + out.merge(mesh(pool)); } } From 7cf67db3321fa4bcae03405be6d6938777b5efa4 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 8 Jan 2019 15:16:40 +0100 Subject: [PATCH 08/14] Uniform scale is sidebar --- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++++++---- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 5 ++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a6d0f4e9d..c8bd71754 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2513,7 +2513,9 @@ void GLCanvas3D::Selection::_render_sidebar_rotation_hints(const std::string& si void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sidebar_field) const { - if (boost::ends_with(sidebar_field, "x") || requires_uniform_scale()) + bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); + + if (boost::ends_with(sidebar_field, "x") || uniform_scale) { ::glPushMatrix(); ::glRotated(-90.0, 0.0, 0.0, 1.0); @@ -2521,14 +2523,14 @@ void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sideb ::glPopMatrix(); } - if (boost::ends_with(sidebar_field, "y") || requires_uniform_scale()) + if (boost::ends_with(sidebar_field, "y") || uniform_scale) { ::glPushMatrix(); _render_sidebar_scale_hint(Y); ::glPopMatrix(); } - if (boost::ends_with(sidebar_field, "z") || requires_uniform_scale()) + if (boost::ends_with(sidebar_field, "z") || uniform_scale) { ::glPushMatrix(); ::glRotated(90.0, 1.0, 0.0, 0.0); @@ -2559,7 +2561,7 @@ void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis) const void GLCanvas3D::Selection::_render_sidebar_scale_hint(Axis axis) const { - m_arrow.set_color((requires_uniform_scale() ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3); + m_arrow.set_color(((requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling()) ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3); ::glTranslated(0.0, 5.0, 0.0); m_arrow.render(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 1cdf87be2..84025bae0 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -399,6 +399,9 @@ void ObjectManipulation::update_if_dirty() m_cache.rotation = m_new_rotation; +// if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) +// m_uniform_scale = true; + if (m_new_enabled) m_og->enable(); else @@ -499,7 +502,7 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale) { Vec3d scaling_factor = scale; const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); - if (selection.requires_uniform_scale()) + if (m_uniform_scale || selection.requires_uniform_scale()) { #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs(); From 2ccdfe68531265a51f6f5a7a8788cdbdf765b74f Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 8 Jan 2019 15:26:27 +0100 Subject: [PATCH 09/14] Fixed typo --- src/libslic3r/Geometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index ba9c7b00e..fc5b158c7 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1194,7 +1194,7 @@ Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& } else { - angles(1) = 0.0; + angles(0) = 0.0; angles(1) = ::atan2(-rotation_matrix(2, 0), sy); angles(2) = (angles(1) >-0.0) ? ::atan2(rotation_matrix(1, 2), rotation_matrix(1, 1)) : ::atan2(-rotation_matrix(1, 2), rotation_matrix(1, 1)); } From 6efcdd1ddf5bd57b110370cc314f275cded3fb2d Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 8 Jan 2019 16:05:49 +0100 Subject: [PATCH 10/14] Added wxEVT_TEXT_ENTER handling for TextCtrl, SpinCtrl & PointCtrl (but it doesn't work under OSX) (fix of #1518) --- src/slic3r/GUI/Field.cpp | 97 ++++++++++++++++++++++++++-------------- src/slic3r/GUI/Field.hpp | 12 +++-- 2 files changed, 72 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 91052570d..2c7bce613 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -66,12 +66,8 @@ void Field::PostInitialize() BUILD(); } -void Field::on_kill_focus(wxEvent& event) +void Field::on_kill_focus() { - // Without this, there will be nasty focus bugs on Windows. - // Also, docs for wxEvent::Skip() say "In general, it is recommended to skip all - // non-command events to allow the default handling to take place." - event.Skip(); // call the registered function if it is available if (m_on_kill_focus!=nullptr) m_on_kill_focus(m_opt_id); @@ -250,11 +246,23 @@ void TextCtrl::BUILD() { break; } - const long style = m_opt.multiline ? wxTE_MULTILINE : 0; + const long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER/*0*/; auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style); temp->SetToolTip(get_tooltip_text(text_value)); + if (style == wxTE_PROCESS_ENTER) { + temp->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent& e) + { +#if !defined(__WXGTK__) + e.Skip(); + temp->GetToolTip()->Enable(true); +#endif // __WXGTK__ + propagate_value(); + bEnterPressed = true; + }), temp->GetId()); + } + temp->Bind(wxEVT_SET_FOCUS, ([this](wxEvent& e) { on_set_focus(e); }), temp->GetId()); temp->Bind(wxEVT_LEFT_DOWN, ([temp](wxEvent& event) @@ -272,14 +280,15 @@ void TextCtrl::BUILD() { temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e) { -#if !defined(__WXGTK__) e.Skip(); +#if !defined(__WXGTK__) temp->GetToolTip()->Enable(true); #endif // __WXGTK__ - if (is_defined_input_value<wxTextCtrl>(window, m_opt.type)) - on_change_field(); - else - on_kill_focus(e); + if (bEnterPressed) { + bEnterPressed = false; + return; + } + propagate_value(); }), temp->GetId()); /* temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt) @@ -311,6 +320,14 @@ void TextCtrl::BUILD() { window = dynamic_cast<wxWindow*>(temp); } +void TextCtrl::propagate_value() +{ + if (is_defined_input_value<wxTextCtrl>(window, m_opt.type)) + on_change_field(); + else + on_kill_focus(); +} + boost::any& TextCtrl::get_value() { wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue(); @@ -398,7 +415,7 @@ void SpinCtrl::BUILD() { const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647; auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, - 0, min_val, max_val, default_value); + 0|wxTE_PROCESS_ENTER, min_val, max_val, default_value); #ifndef __WXOSX__ // #ys_FIXME_KILL_FOCUS @@ -407,15 +424,23 @@ void SpinCtrl::BUILD() { // and on TEXT event under OSX temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { - if (tmp_value < 0) - on_kill_focus(e); - else { - e.Skip(); - on_change_field(); + e.Skip(); + if (bEnterPressed) { + bEnterPressed = false; + return; } + + propagate_value(); }), temp->GetId()); - temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); + temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); + + temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) + { + e.Skip(); + propagate_value(); + bEnterPressed = true; + }), temp->GetId()); #endif temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) @@ -430,12 +455,7 @@ void SpinCtrl::BUILD() { tmp_value = std::stoi(value); else tmp_value = -9999; #ifdef __WXOSX__ - if (tmp_value < 0) { - if (m_on_kill_focus != nullptr) - m_on_kill_focus(m_opt_id); - } - else - on_change_field(); + propagate_value(); #endif }), temp->GetId()); @@ -445,6 +465,14 @@ void SpinCtrl::BUILD() { window = dynamic_cast<wxWindow*>(temp); } +void SpinCtrl::propagate_value() +{ + if (tmp_value < 0) + on_kill_focus(); + else + on_change_field(); +} + void Choice::BUILD() { auto size = wxSize(wxDefaultSize); if (m_opt.height >= 0) size.SetHeight(m_opt.height); @@ -483,7 +511,7 @@ void Choice::BUILD() { on_change_field(); } else - on_kill_focus(e); + on_kill_focus(); }), temp->GetId()); } @@ -755,8 +783,8 @@ void PointCtrl::BUILD() val = default_pt(1); wxString Y = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); - x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size); - y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size); + x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, wxEVT_TEXT_ENTER); + y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, wxEVT_TEXT_ENTER); temp->Add(new wxStaticText(m_parent, wxID_ANY, "x : "), 0, wxALIGN_CENTER_VERTICAL, 0); temp->Add(x_textctrl); @@ -766,8 +794,11 @@ void PointCtrl::BUILD() // x_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), x_textctrl->GetId()); // y_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), y_textctrl->GetId()); - x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), x_textctrl->GetId()); - y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), y_textctrl->GetId()); + x_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(x_textctrl); }), x_textctrl->GetId()); + y_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(y_textctrl); }), y_textctrl->GetId()); + + x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(x_textctrl); }), x_textctrl->GetId()); + y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(y_textctrl); }), y_textctrl->GetId()); // // recast as a wxWindow to fit the calling convention sizer = dynamic_cast<wxSizer*>(temp); @@ -776,14 +807,12 @@ void PointCtrl::BUILD() y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y)); } -void PointCtrl::OnKillFocus(wxEvent& e, wxTextCtrl* win) +void PointCtrl::propagate_value(wxTextCtrl* win) { - e.Skip(); - if (!win->GetValue().empty()) { + if (!win->GetValue().empty()) on_change_field(); - } else - on_kill_focus(e); + on_kill_focus(); } void PointCtrl::set_value(const Vec2d& value, bool change_event) diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 4a19b6103..bcc94c7ba 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -74,7 +74,7 @@ protected: /// Call the attached on_kill_focus method. //! It's important to use wxEvent instead of wxFocusEvent, //! in another case we can't unfocused control at all - void on_kill_focus(wxEvent& event); + void on_kill_focus(); /// Call the attached on_change method. void on_set_focus(wxEvent& event); /// Call the attached on_change method. @@ -226,6 +226,8 @@ protected: // current value boost::any m_value; + + bool bEnterPressed = false; friend class OptionsGroup; }; @@ -252,6 +254,8 @@ public: ~TextCtrl() {} void BUILD(); + // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER + void propagate_value(); wxWindow* window {nullptr}; virtual void set_value(const std::string& value, bool change_event = false) { @@ -310,6 +314,8 @@ public: wxWindow* window{ nullptr }; void BUILD() override; + /// Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER + void propagate_value() ; void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; @@ -393,8 +399,8 @@ public: wxTextCtrl* y_textctrl{ nullptr }; void BUILD() override; - - void OnKillFocus(wxEvent& e, wxTextCtrl* win); + // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER + void propagate_value(wxTextCtrl* win); void set_value(const Vec2d& value, bool change_event = false); void set_value(const boost::any& value, bool change_event = false); boost::any& get_value() override; From 6d7e2b2dd76348b49c54f51be66ebc36ac8617a6 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Wed, 9 Jan 2019 08:48:25 +0100 Subject: [PATCH 11/14] Added SetLock() function for PrusaLockButton --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 8 ++++++-- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 2 ++ src/slic3r/GUI/wxExtensions.cpp | 6 ++++++ src/slic3r/GUI/wxExtensions.hpp | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 84025bae0..17371ccf6 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -172,6 +172,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : event.Skip(); wxTheApp->CallAfter([btn, this]() { set_uniform_scaling(btn->IsLocked()); }); }); + m_lock_bnt = btn; return btn; }; } @@ -399,8 +400,11 @@ void ObjectManipulation::update_if_dirty() m_cache.rotation = m_new_rotation; -// if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) -// m_uniform_scale = true; + if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) { +// m_uniform_scale = true; + m_lock_bnt->SetLock(true); +// m_lock_bnt->Disable(); + } if (m_new_enabled) m_og->enable(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 57eb93b71..d0afa528e 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -7,6 +7,7 @@ #include "GLCanvas3D.hpp" class wxStaticText; +class PrusaLockButton; namespace Slic3r { namespace GUI { @@ -75,6 +76,7 @@ class ObjectManipulation : public OG_Settings Vec3d m_new_size; bool m_new_enabled; bool m_uniform_scale {false}; + PrusaLockButton* m_lock_bnt{ nullptr }; public: ObjectManipulation(wxWindow* parent); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 466580074..9ffa649cc 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2216,6 +2216,12 @@ void PrusaLockButton::OnButton(wxCommandEvent& event) event.Skip(); } +void PrusaLockButton::SetLock(bool lock) +{ + m_is_pushed = lock; + enter_button(true); +} + void PrusaLockButton::enter_button(const bool enter) { wxBitmap* icon = m_is_pushed ? diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index b951c5635..b6f7a4220 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -851,6 +851,7 @@ public: void OnLeaveBtn(wxMouseEvent& event) { enter_button(false); event.Skip(); } bool IsLocked() const { return m_is_pushed; } + void SetLock(bool lock); protected: void enter_button(const bool enter); From 410211a3e44e60bd6fbc2284b86b457f60a268f5 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 9 Jan 2019 09:47:05 +0100 Subject: [PATCH 12/14] Completed uniform scale in sidebar --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 9 ++++++--- src/slic3r/GUI/wxExtensions.cpp | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 17371ccf6..a03b0a212 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -401,9 +401,12 @@ void ObjectManipulation::update_if_dirty() m_cache.rotation = m_new_rotation; if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) { -// m_uniform_scale = true; m_lock_bnt->SetLock(true); -// m_lock_bnt->Disable(); + m_lock_bnt->Disable(); + } + else { + m_lock_bnt->SetLock(m_uniform_scale); + m_lock_bnt->Enable(); } if (m_new_enabled) @@ -562,7 +565,7 @@ void ObjectManipulation::change_size_value(const Vec3d& size) Vec3d scale = 100.0 * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)); Vec3d scaling_factor = scale; - if (selection.requires_uniform_scale()) + if (m_uniform_scale || selection.requires_uniform_scale()) { Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs(); double max_diff = abs_scale_diff(X); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 9ffa649cc..61aee6a67 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2201,6 +2201,7 @@ PrusaLockButton::PrusaLockButton( wxWindow *parent, SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif // __WXMSW__ SetBitmap(m_bmp_unlock_on); + SetBitmapDisabled(m_bmp_lock_on); //button events Bind(wxEVT_BUTTON, &PrusaLockButton::OnButton, this); From abc38ebc824cd151ca5c612a4583b4a23dac615e Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Wed, 9 Jan 2019 10:12:04 +0100 Subject: [PATCH 13/14] Fixed orientation of visual hints for sidebar scale fields --- src/slic3r/GUI/GLCanvas3D.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c8bd71754..9d70fbc1b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2039,11 +2039,17 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel const Vec3d& center = get_bounding_box().center(); if (is_single_full_instance()) + { ::glTranslated(center(0), center(1), center(2)); + if (boost::starts_with(sidebar_field, "scale")) + { + Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); + ::glMultMatrixd(orient_matrix.data()); + } + } else if (is_single_volume() || is_single_modifier()) { - const GLVolume* volume = (*m_volumes)[*m_list.begin()]; - Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true); + Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); const Vec3d& offset = get_bounding_box().center(); ::glTranslated(offset(0), offset(1), offset(2)); @@ -2054,8 +2060,7 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel ::glTranslated(center(0), center(1), center(2)); if (requires_local_axes()) { - const GLVolume* volume = (*m_volumes)[*m_list.begin()]; - Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true); + Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); ::glMultMatrixd(orient_matrix.data()); } } From 2dadf4b5dc153f734d4b095d62d99224dc0502c7 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Wed, 9 Jan 2019 10:30:29 +0100 Subject: [PATCH 14/14] Fixed a crash after settings adding for the instance from the scene's context menu --- src/slic3r/GUI/GUI_ObjectList.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 729946dbf..bc54b2321 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -633,8 +633,10 @@ void ObjectList::get_settings_choice(const wxString& category_name) // Add settings item for object - const auto item = GetSelection(); + auto item = GetSelection(); if (item) { + if (m_objects_model->GetItemType(item) == itInstance) + item = m_objects_model->GetTopParent(item); const auto settings_item = m_objects_model->IsSettingsItem(item) ? item : m_objects_model->GetSettingsItem(item); select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item)); @@ -903,7 +905,8 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int m_parts_changed = true; parts_changed(obj_idx); - select_item(m_objects_model->AddVolumeChild(GetSelection(), from_u8(name), type)); + const auto object_item = m_objects_model->GetTopParent(GetSelection()); + select_item(m_objects_model->AddVolumeChild(object_item, from_u8(name), type)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); #endif //no __WXOSX__ //__WXMSW__ @@ -1156,6 +1159,10 @@ void ObjectList::part_selection_changed() else if (m_objects_model->GetItemType(item) == itInstance) { og_name = _(L("Instance manipulation")); update_and_show_manipulations = true; + + // fill m_config by object's values + const int obj_idx_ = m_objects_model->GetObjectIdByItem(item); + m_config = &(*m_objects)[obj_idx_]->config; } }