mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 12:11:15 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/Prusa3d/Slic3r
This commit is contained in:
		
						commit
						fb6aabd785
					
				
					 9 changed files with 245 additions and 111 deletions
				
			
		|  | @ -539,7 +539,7 @@ public: | |||
| // 2D shape from top view.
 | ||||
| using ShapeData2D = std::vector<std::pair<Slic3r::ModelInstance*, Item>>; | ||||
| 
 | ||||
| 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)
 | ||||
|  | @ -600,6 +600,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; | ||||
| } | ||||
| 
 | ||||
|  | @ -608,7 +630,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
 | ||||
|  | @ -617,18 +640,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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -714,6 +744,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.
 | ||||
|  | @ -726,7 +757,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
 | ||||
|  | @ -796,7 +827,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; | ||||
|  | @ -806,7 +837,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
 | ||||
|  | @ -823,10 +854,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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -716,12 +716,12 @@ 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); | ||||
|     v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); | ||||
|     v.set_volume_rotation(Vec3d(0., 0., (M_PI/180.) * rotation_angle)); | ||||
| 
 | ||||
|     // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
 | ||||
|     v.bounding_box = v.indexed_vertex_array.bounding_box(); | ||||
|     v.indexed_vertex_array.finalize_geometry(use_VBOs); | ||||
|  |  | |||
|  | @ -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" | ||||
|  | @ -1202,6 +1203,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); | |||
| wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent); | ||||
|  | @ -3116,6 +3118,10 @@ void GLCanvas3D::do_rotate() | |||
|     for (const GLVolume* v : m_volumes.volumes) | ||||
|     { | ||||
|         int object_idx = v->object_idx(); | ||||
|         if (object_idx == 1000) { // the wipe tower
 | ||||
|             Vec3d offset = v->get_volume_offset(); | ||||
|             post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset(0), offset(1), v->get_volume_rotation()(2)))); | ||||
|         } | ||||
|         if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx)) | ||||
|             continue; | ||||
| 
 | ||||
|  | @ -3312,6 +3318,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<ConfigOptionFloat>("wipe_tower_x", true)->value = wti.pos(0); | ||||
|         cfg.opt<ConfigOptionFloat>("wipe_tower_y", true)->value = wti.pos(1); | ||||
|         cfg.opt<ConfigOptionFloat>("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; | ||||
|  | @ -4315,6 +4353,7 @@ void GLCanvas3D::_render_selection_sidebar_hints() const | |||
|         m_shader.stop_using(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void GLCanvas3D::_update_volumes_hover_state() const | ||||
| { | ||||
|     for (GLVolume* v : m_volumes.volumes) | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <stddef.h> | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "libslic3r/ModelArrange.hpp" | ||||
| #include "3DScene.hpp" | ||||
| #include "GLToolbar.hpp" | ||||
| #include "Event.hpp" | ||||
|  | @ -116,6 +117,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); | |||
| wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent); | ||||
|  | @ -608,6 +610,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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -102,7 +102,7 @@ protected: | |||
|             m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); | ||||
|         } | ||||
|     } | ||||
|     virtual bool on_is_activable(const Selection& selection) const { return !selection.is_wipe_tower(); } | ||||
|     virtual bool on_is_activable(const Selection& selection) const { return true; } | ||||
|     virtual void on_enable_grabber(unsigned int id) | ||||
|     { | ||||
|         if ((0 <= id) && (id < 3)) | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include "slic3r/GUI/3DScene.hpp" | ||||
| #include "slic3r/GUI/GUI_App.hpp" | ||||
| #include "slic3r/GUI/GUI_ObjectManipulation.hpp" | ||||
| #include "slic3r/GUI/PresetBundle.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| #include <wx/glcanvas.h> | ||||
|  | @ -264,8 +265,11 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas) | |||
| 
 | ||||
|     const Selection& selection = canvas.get_selection(); | ||||
| 
 | ||||
|     bool enable_move_z = !selection.is_wipe_tower(); | ||||
|     enable_grabber(Move, 2, enable_move_z); | ||||
|     bool is_wipe_tower = selection.is_wipe_tower(); | ||||
|     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) | ||||
|     { | ||||
|  | @ -290,6 +294,14 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas) | |||
|         set_flattening_data(nullptr); | ||||
|         set_sla_support_data(nullptr, selection); | ||||
|     } | ||||
|     else if (is_wipe_tower) | ||||
|     { | ||||
|         DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config; | ||||
|         set_scale(Vec3d::Ones()); | ||||
|         set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast<const ConfigOptionFloat*>(config.option("wipe_tower_rotation_angle"))->value)); | ||||
|         set_flattening_data(nullptr); | ||||
|         set_sla_support_data(nullptr, selection); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         set_scale(Vec3d::Ones()); | ||||
|  |  | |||
|  | @ -1314,6 +1314,7 @@ struct Plater::priv | |||
|     void on_object_select(SimpleEvent&); | ||||
|     void on_right_click(Vec2dEvent&); | ||||
|     void on_wipetower_moved(Vec3dEvent&); | ||||
|     void on_wipetower_rotated(Vec3dEvent&); | ||||
|     void on_update_geometry(Vec3dsEvent<2>&); | ||||
|     void on_3dcanvas_mouse_dragging_finished(SimpleEvent&); | ||||
| 
 | ||||
|  | @ -1448,6 +1449,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) | |||
|         { if (evt.data == 1) this->q->increase_instances(); else if (this->can_decrease_instances()) this->q->decrease_instances(); }); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); }); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); }); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); }); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event<bool> &evt) { this->sidebar->enable_buttons(evt.data); }); | ||||
|  | @ -1455,6 +1457,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) | |||
|     view3D_canvas->Bind(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, &priv::on_3dcanvas_mouse_dragging_finished, this); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); }); | ||||
|     view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); }); | ||||
| 
 | ||||
|     // 3DScene/Toolbar:
 | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); }); | ||||
|  | @ -1877,7 +1880,13 @@ std::vector<size_t> 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) { | ||||
|  | @ -2134,6 +2143,8 @@ void Plater::priv::arrange() | |||
| 
 | ||||
|     statusfn(0, arrangestr); | ||||
| 
 | ||||
|     arr::WipeTowerInfo wti = view3D->get_canvas3d()->get_wipe_tower_info(); | ||||
| 
 | ||||
|     try { | ||||
|         arr::BedShapeHint hint; | ||||
| 
 | ||||
|  | @ -2141,6 +2152,7 @@ void Plater::priv::arrange() | |||
|         hint.type = arr::BedShapeType::WHO_KNOWS; | ||||
| 
 | ||||
|         arr::arrange(model, | ||||
|                      wti, | ||||
|                      min_obj_distance, | ||||
|                      bed, | ||||
|                      hint, | ||||
|  | @ -2152,6 +2164,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
 | ||||
|  | @ -2254,7 +2269,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(); | ||||
|  | @ -2862,6 +2878,15 @@ void Plater::priv::on_wipetower_moved(Vec3dEvent &evt) | |||
|     wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::on_wipetower_rotated(Vec3dEvent& evt) | ||||
| { | ||||
|     DynamicPrintConfig cfg; | ||||
|     cfg.opt<ConfigOptionFloat>("wipe_tower_x", true)->value = evt.data(0); | ||||
|     cfg.opt<ConfigOptionFloat>("wipe_tower_y", true)->value = evt.data(1); | ||||
|     cfg.opt<ConfigOptionFloat>("wipe_tower_rotation_angle", true)->value = Geometry::rad2deg(evt.data(2)); | ||||
|     wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::on_update_geometry(Vec3dsEvent<2>&) | ||||
| { | ||||
|     // TODO
 | ||||
|  |  | |||
|  | @ -499,100 +499,111 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ | |||
|     // Only relative rotation values are allowed in the world coordinate system.
 | ||||
|     assert(!transformation_type.world() || transformation_type.relative()); | ||||
| 
 | ||||
|     int rot_axis_max = 0; | ||||
|     if (rotation.isApprox(Vec3d::Zero())) | ||||
|     { | ||||
|         for (unsigned int i : m_list) | ||||
|     if (!is_wipe_tower()) { | ||||
|         int rot_axis_max = 0; | ||||
|         if (rotation.isApprox(Vec3d::Zero())) | ||||
|         { | ||||
|             GLVolume &volume = *(*m_volumes)[i]; | ||||
|             if (m_mode == Instance) | ||||
|             { | ||||
|                 volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                 volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position()); | ||||
|             } | ||||
|             else if (m_mode == Volume) | ||||
|             { | ||||
|                 volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation()); | ||||
|                 volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         //FIXME this does not work for absolute rotations (transformation_type.absolute() is true)
 | ||||
|         rotation.cwiseAbs().maxCoeff(&rot_axis_max); | ||||
| 
 | ||||
|         // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
 | ||||
|         std::vector<int> object_instance_first(m_model->objects.size(), -1); | ||||
|         auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) { | ||||
|             int first_volume_idx = object_instance_first[volume.object_idx()]; | ||||
|             if (rot_axis_max != 2 && first_volume_idx != -1) { | ||||
|                 // Generic rotation, but no rotation around the Z axis.
 | ||||
|                 // Always do a local rotation (do not consider the selection to be a rigid body).
 | ||||
|                 assert(is_approx(rotation.z(), 0.0)); | ||||
|                 const GLVolume &first_volume = *(*m_volumes)[first_volume_idx]; | ||||
|                 const Vec3d    &rotation = first_volume.get_instance_rotation(); | ||||
|                 double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                 volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); | ||||
|             } | ||||
|             else { | ||||
|                 // extracts rotations from the composed transformation
 | ||||
|                 Vec3d new_rotation = transformation_type.world() ? | ||||
|                     Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) : | ||||
|                     transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation(); | ||||
|                 if (rot_axis_max == 2 && transformation_type.joint()) { | ||||
|                     // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
 | ||||
|                     Vec3d offset = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, new_rotation(2) - m_cache.volumes_data[i].get_instance_rotation()(2))) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); | ||||
|                     volume.set_instance_offset(m_cache.dragging_center + offset); | ||||
|                 } | ||||
|                 volume.set_instance_rotation(new_rotation); | ||||
|                 object_instance_first[volume.object_idx()] = i; | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         for (unsigned int i : m_list) | ||||
|         { | ||||
|             GLVolume &volume = *(*m_volumes)[i]; | ||||
|             if (is_single_full_instance()) | ||||
|                 rotate_instance(volume, i); | ||||
|             else if (is_single_volume() || is_single_modifier()) | ||||
|             { | ||||
|                 if (transformation_type.independent()) | ||||
|                     volume.set_volume_rotation(volume.get_volume_rotation() + rotation); | ||||
|                 else | ||||
|                 { | ||||
|                     Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
|                     Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); | ||||
|                     volume.set_volume_rotation(new_rotation); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             for (unsigned int i : m_list) | ||||
|             { | ||||
|                 GLVolume &volume = *(*m_volumes)[i]; | ||||
|                 if (m_mode == Instance) | ||||
|                     rotate_instance(volume, i); | ||||
|                 { | ||||
|                     volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                     volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position()); | ||||
|                 } | ||||
|                 else if (m_mode == Volume) | ||||
|                 { | ||||
|                     // extracts rotations from the composed transformation
 | ||||
|                     Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
|                     Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); | ||||
|                     if (transformation_type.joint()) | ||||
|                     { | ||||
|                         Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center; | ||||
|                         Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot); | ||||
|                         volume.set_volume_offset(local_pivot + offset); | ||||
|                     } | ||||
|                     volume.set_volume_rotation(new_rotation); | ||||
|                     volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation()); | ||||
|                     volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|         else { // this is not the wipe tower
 | ||||
|             //FIXME this does not work for absolute rotations (transformation_type.absolute() is true)
 | ||||
|             rotation.cwiseAbs().maxCoeff(&rot_axis_max); | ||||
| 
 | ||||
| #if !DISABLE_INSTANCES_SYNCH | ||||
|     if (m_mode == Instance) | ||||
|         synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); | ||||
|     else if (m_mode == Volume) | ||||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
|             // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
 | ||||
|             std::vector<int> object_instance_first(m_model->objects.size(), -1); | ||||
|             auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) { | ||||
|                 int first_volume_idx = object_instance_first[volume.object_idx()]; | ||||
|                 if (rot_axis_max != 2 && first_volume_idx != -1) { | ||||
|                     // Generic rotation, but no rotation around the Z axis.
 | ||||
|                     // Always do a local rotation (do not consider the selection to be a rigid body).
 | ||||
|                     assert(is_approx(rotation.z(), 0.0)); | ||||
|                     const GLVolume &first_volume = *(*m_volumes)[first_volume_idx]; | ||||
|                     const Vec3d    &rotation = first_volume.get_instance_rotation(); | ||||
|                     double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                     volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); | ||||
|                 } | ||||
|                 else { | ||||
|                     // extracts rotations from the composed transformation
 | ||||
|                     Vec3d new_rotation = transformation_type.world() ? | ||||
|                         Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) : | ||||
|                         transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation(); | ||||
|                     if (rot_axis_max == 2 && transformation_type.joint()) { | ||||
|                         // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
 | ||||
|                         Vec3d offset = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, new_rotation(2) - m_cache.volumes_data[i].get_instance_rotation()(2))) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); | ||||
|                         volume.set_instance_offset(m_cache.dragging_center + offset); | ||||
|                     } | ||||
|                     volume.set_instance_rotation(new_rotation); | ||||
|                     object_instance_first[volume.object_idx()] = i; | ||||
|                 } | ||||
|             }; | ||||
| 
 | ||||
|             for (unsigned int i : m_list) | ||||
|             { | ||||
|                 GLVolume &volume = *(*m_volumes)[i]; | ||||
|                 if (is_single_full_instance()) | ||||
|                     rotate_instance(volume, i); | ||||
|                 else if (is_single_volume() || is_single_modifier()) | ||||
|                 { | ||||
|                     if (transformation_type.independent()) | ||||
|                         volume.set_volume_rotation(volume.get_volume_rotation() + rotation); | ||||
|                     else | ||||
|                     { | ||||
|                         Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
|                         Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); | ||||
|                         volume.set_volume_rotation(new_rotation); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (m_mode == Instance) | ||||
|                         rotate_instance(volume, i); | ||||
|                     else if (m_mode == Volume) | ||||
|                     { | ||||
|                         // extracts rotations from the composed transformation
 | ||||
|                         Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
|                         Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); | ||||
|                         if (transformation_type.joint()) | ||||
|                         { | ||||
|                             Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center; | ||||
|                             Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot); | ||||
|                             volume.set_volume_offset(local_pivot + offset); | ||||
|                         } | ||||
|                         volume.set_volume_rotation(new_rotation); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     #if !DISABLE_INSTANCES_SYNCH | ||||
|         if (m_mode == Instance) | ||||
|             synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); | ||||
|         else if (m_mode == Volume) | ||||
|             synchronize_unselected_volumes(); | ||||
|     #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
|     } | ||||
|     else { // it's the wipe tower that's selected and being rotated
 | ||||
|         GLVolume& volume = *((*m_volumes)[*m_list.begin()]); // the wipe tower is always alone in the selection
 | ||||
| 
 | ||||
|         // make sure the wipe tower rotates around its center, not origin
 | ||||
|         // we can assume that only Z rotation changes
 | ||||
|         Vec3d center_local = volume.transformed_bounding_box().center() - volume.get_volume_offset(); | ||||
|         Vec3d center_local_new = Eigen::AngleAxisd(rotation(2)-volume.get_volume_rotation()(2), Vec3d(0, 0, 1)) * center_local; | ||||
|         volume.set_volume_rotation(rotation); | ||||
|         volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new); | ||||
|     } | ||||
| 
 | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv