From e9a53e49dba0c10aebad555cedb86d9be405ffd3 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 29 Apr 2019 14:32:02 +0200 Subject: [PATCH] Arrange is accounting for the wipe tower now --- src/libslic3r/ModelArrange.cpp | 66 +++++++++++++++++------ src/libslic3r/ModelArrange.hpp | 14 ++++- src/slic3r/GUI/3DScene.cpp | 3 -- src/slic3r/GUI/GLCanvas3D.cpp | 33 ++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 4 ++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 17 +++++- 7 files changed, 114 insertions(+), 25 deletions(-) diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 50901da3a..493d820e0 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -539,7 +539,7 @@ public: // 2D shape from top view. using ShapeData2D = std::vector>; -ShapeData2D projectModelFromTop(const Slic3r::Model &model) { +ShapeData2D projectModelFromTop(const Slic3r::Model &model, const WipeTowerInfo& wti) { ShapeData2D ret; // Count all the items on the bin (all the object's instances) @@ -595,6 +595,28 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { } } + // The wipe tower is a separate case (in case there is one), let's duplicate the code + if (wti.is_wipe_tower) { + Points pts; + pts.emplace_back(coord_t(scale_(0.)), coord_t(scale_(0.))); + pts.emplace_back(coord_t(scale_(wti.bb_size(0))), coord_t(scale_(0.))); + pts.emplace_back(coord_t(scale_(wti.bb_size(0))), coord_t(scale_(wti.bb_size(1)))); + pts.emplace_back(coord_t(scale_(-0.)), coord_t(scale_(wti.bb_size(1)))); + pts.emplace_back(coord_t(scale_(-0.)), coord_t(scale_(0.))); + Polygon p(std::move(pts)); + ClipperLib::Path clpath = Slic3rMultiPoint_to_ClipperPath(p); + ClipperLib::Polygon pn; + pn.Contour = clpath; + // Efficient conversion to item. + Item item(std::move(pn)); + item.rotation(wti.rotation), + item.translation({ + ClipperLib::cInt(wti.pos(0)/SCALING_FACTOR), + ClipperLib::cInt(wti.pos(1)/SCALING_FACTOR) + }); + ret.emplace_back(nullptr, item); + } + return ret; } @@ -603,7 +625,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { void applyResult( IndexedPackGroup::value_type& group, Coord batch_offset, - ShapeData2D& shapemap) + ShapeData2D& shapemap, + WipeTowerInfo& wti) { for(auto& r : group) { auto idx = r.first; // get the original item index @@ -612,18 +635,25 @@ void applyResult( // Get the model instance from the shapemap using the index ModelInstance *inst_ptr = shapemap[idx].first; - // Get the transformation data from the item object and scale it - // appropriately - auto off = item.translation(); - Radians rot = item.rotation(); + // Get the transformation data from the item object and scale it + // appropriately + auto off = item.translation(); + Radians rot = item.rotation(); - Vec3d foff(off.X*SCALING_FACTOR + batch_offset, - off.Y*SCALING_FACTOR, - inst_ptr->get_offset()(Z)); + Vec3d foff(off.X*SCALING_FACTOR + batch_offset, + off.Y*SCALING_FACTOR, + inst_ptr ? inst_ptr->get_offset()(Z) : 0.); - // write the transformation data into the model instance - inst_ptr->set_rotation(Z, rot); - inst_ptr->set_offset(foff); + if (inst_ptr) { + // write the transformation data into the model instance + inst_ptr->set_rotation(Z, rot); + inst_ptr->set_offset(foff); + } + else { // this is the wipe tower - we will modify the struct with the info + // and leave it up to the called to actually move the wipe tower + wti.pos = Vec2d(foff(0), foff(1)); + wti.rotation = rot; + } } } @@ -709,6 +739,7 @@ BedShapeHint bedShape(const Polyline &bed) { // The final client function to arrange the Model. A progress indicator and // a stop predicate can be also be passed to control the process. bool arrange(Model &model, // The model with the geometries + WipeTowerInfo& wti, // Wipe tower info coord_t min_obj_distance, // Has to be in scaled (clipper) measure const Polyline &bed, // The bed geometry. BedShapeHint bedhint, // Hint about the bed geometry type. @@ -721,7 +752,7 @@ bool arrange(Model &model, // The model with the geometries bool ret = true; // Get the 2D projected shapes with their 3D model instance pointers - auto shapemap = arr::projectModelFromTop(model); + auto shapemap = arr::projectModelFromTop(model, wti); // Copy the references for the shapes only as the arranger expects a // sequence of objects convertible to Item or ClipperPolygon @@ -791,7 +822,7 @@ bool arrange(Model &model, // The model with the geometries if(result.empty() || stopcondition()) return false; if(first_bin_only) { - applyResult(result.front(), 0, shapemap); + applyResult(result.front(), 0, shapemap, wti); } else { const auto STRIDE_PADDING = 1.2; @@ -801,7 +832,7 @@ bool arrange(Model &model, // The model with the geometries Coord batch_offset = 0; for(auto& group : result) { - applyResult(group, batch_offset, shapemap); + applyResult(group, batch_offset, shapemap, wti); // Only the first pack group can be placed onto the print bed. The // other objects which could not fit will be placed next to the @@ -818,10 +849,11 @@ bool arrange(Model &model, // The model with the geometries void find_new_position(const Model &model, ModelInstancePtrs toadd, coord_t min_obj_distance, - const Polyline &bed) + const Polyline &bed, + WipeTowerInfo& wti) { // Get the 2D projected shapes with their 3D model instance pointers - auto shapemap = arr::projectModelFromTop(model); + auto shapemap = arr::projectModelFromTop(model, wti); // Copy the references for the shapes only as the arranger expects a // sequence of objects convertible to Item or ClipperPolygon diff --git a/src/libslic3r/ModelArrange.hpp b/src/libslic3r/ModelArrange.hpp index d76769081..b61443da0 100644 --- a/src/libslic3r/ModelArrange.hpp +++ b/src/libslic3r/ModelArrange.hpp @@ -40,6 +40,13 @@ struct BedShapeHint { BedShapeHint bedShape(const Polyline& bed); +struct WipeTowerInfo { + bool is_wipe_tower = false; + Vec2d pos; + Vec2d bb_size; + double rotation; +}; + /** * \brief Arranges the model objects on the screen. * @@ -66,7 +73,9 @@ BedShapeHint bedShape(const Polyline& bed); * packed. The unsigned argument is the number of items remaining to pack. * \param stopcondition A predicate returning true if abort is needed. */ -bool arrange(Model &model, coord_t min_obj_distance, +bool arrange(Model &model, + WipeTowerInfo& wipe_tower_info, + coord_t min_obj_distance, const Slic3r::Polyline& bed, BedShapeHint bedhint, bool first_bin_only, @@ -78,7 +87,8 @@ bool arrange(Model &model, coord_t min_obj_distance, void find_new_position(const Model& model, ModelInstancePtrs instances_to_add, coord_t min_obj_distance, - const Slic3r::Polyline& bed); + const Slic3r::Polyline& bed, + WipeTowerInfo& wti); } // arr } // Slic3r diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 8bd95e372..c3d5c1395 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -709,9 +709,6 @@ int GLVolumeCollection::load_wipe_tower_preview( brim_mesh.translate(-brim_width, -brim_width, 0.f); mesh.merge(brim_mesh); - //mesh.rotate(rotation_angle, &origin_of_rotation); // rotates the box according to the config rotation setting - - this->volumes.emplace_back(new GLVolume(color)); GLVolume &v = *this->volumes.back(); v.indexed_vertex_array.load_mesh(mesh, use_VBOs); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index cc7514e54..eca621051 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -16,6 +16,7 @@ #include "slic3r/GUI/GLShader.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/PresetBundle.hpp" +#include "slic3r/GUI/Tab.hpp" #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" #include "GUI_ObjectManipulation.hpp" @@ -3291,6 +3292,38 @@ void GLCanvas3D::update_ui_from_settings() #endif } + + +arr::WipeTowerInfo GLCanvas3D::get_wipe_tower_info() const +{ + arr::WipeTowerInfo wti; + for (const GLVolume* vol : m_volumes.volumes) { + if (vol->is_wipe_tower) { + wti.is_wipe_tower = true; + wti.pos = Vec2d(m_config->opt_float("wipe_tower_x"), + m_config->opt_float("wipe_tower_y")); + wti.rotation = (M_PI/180.) * m_config->opt_float("wipe_tower_rotation_angle"); + const BoundingBoxf3& bb = vol->bounding_box; + wti.bb_size = Vec2d(bb.size()(0), bb.size()(1)); + break; + } + } + return wti; +} + + +void GLCanvas3D::arrange_wipe_tower(const arr::WipeTowerInfo& wti) const +{ + if (wti.is_wipe_tower) { + DynamicPrintConfig cfg; + cfg.opt("wipe_tower_x", true)->value = wti.pos(0); + cfg.opt("wipe_tower_y", true)->value = wti.pos(1); + cfg.opt("wipe_tower_rotation_angle", true)->value = (180./M_PI) * wti.rotation; + wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg); + } +} + + Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos) { float z0 = 0.0f; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 086209872..ce4c7df74 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -4,6 +4,7 @@ #include #include +#include "libslic3r/ModelArrange.hpp" #include "3DScene.hpp" #include "GLToolbar.hpp" #include "Event.hpp" @@ -608,6 +609,9 @@ public: int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; } int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); } + arr::WipeTowerInfo get_wipe_tower_info() const; + void arrange_wipe_tower(const arr::WipeTowerInfo& wti) const; + // Returns the view ray line, in world coordinate, at the given mouse position. Linef3 mouse_ray(const Point& mouse_pos); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 7cc28ee78..7af1f5400 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -270,7 +270,7 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas) enable_grabber(Move, 2, !is_wipe_tower); enable_grabber(Rotate, 0, !is_wipe_tower); enable_grabber(Rotate, 1, !is_wipe_tower); - + bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); for (int i = 0; i < 6; ++i) { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 31b0d9f3a..b770a7660 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1869,7 +1869,13 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode Polyline bed; bed.points.reserve(bedpoints.size()); for(auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1))); - arr::find_new_position(model, new_instances, min_obj_distance, bed); + arr::WipeTowerInfo wti = view3D->get_canvas3d()->get_wipe_tower_info(); + + arr::find_new_position(model, new_instances, min_obj_distance, bed, wti); + + // it remains to move the wipe tower: + view3D->get_canvas3d()->arrange_wipe_tower(wti); + #endif /* AUTOPLACEMENT_ON_LOAD */ if (scaled_down) { @@ -2126,6 +2132,8 @@ void Plater::priv::arrange() statusfn(0, arrangestr); + arr::WipeTowerInfo wti = view3D->get_canvas3d()->get_wipe_tower_info(); + try { arr::BedShapeHint hint; @@ -2133,6 +2141,7 @@ void Plater::priv::arrange() hint.type = arr::BedShapeType::WHO_KNOWS; arr::arrange(model, + wti, min_obj_distance, bed, hint, @@ -2144,6 +2153,9 @@ void Plater::priv::arrange() "Some geometries may be invalid.")); } + // it remains to move the wipe tower: + view3D->get_canvas3d()->arrange_wipe_tower(wti); + statusfn(0, L("Arranging done.")); statusbar()->set_range(prev_range); statusbar()->set_cancel_callback(); // remove cancel button @@ -2246,7 +2258,8 @@ void Plater::priv::sla_optimize_rotation() { oi->set_rotation(rt); } - arr::find_new_position(model, o->instances, coord_t(mindist/SCALING_FACTOR), bed); + arr::WipeTowerInfo wti; // useless in SLA context + arr::find_new_position(model, o->instances, coord_t(mindist/SCALING_FACTOR), bed, wti); // Correct the z offset of the object which was corrupted be the rotation o->ensure_on_bed();