mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Changed the "non-uniform scaling is not possible" message.
This commit is contained in:
		
							parent
							
								
									f2bb070ab9
								
							
						
					
					
						commit
						0ab96ed6b5
					
				
					 8 changed files with 150 additions and 153 deletions
				
			
		|  | @ -362,19 +362,18 @@ const BoundingBoxf3& GLVolume::transformed_bounding_box() const | |||
| 
 | ||||
| const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const | ||||
| { | ||||
|     if (m_transformed_convex_hull_bounding_box_dirty) | ||||
|     { | ||||
|         if ((m_convex_hull != nullptr) && (m_convex_hull->stl.stats.number_of_facets > 0)) | ||||
|             m_transformed_convex_hull_bounding_box = m_convex_hull->transformed_bounding_box(world_matrix()); | ||||
|         else | ||||
|             m_transformed_convex_hull_bounding_box = bounding_box.transformed(world_matrix()); | ||||
| 
 | ||||
|         m_transformed_convex_hull_bounding_box_dirty = false; | ||||
|     } | ||||
| 
 | ||||
| 	if (m_transformed_convex_hull_bounding_box_dirty) | ||||
| 		m_transformed_convex_hull_bounding_box = this->transformed_convex_hull_bounding_box(world_matrix()); | ||||
|     return m_transformed_convex_hull_bounding_box; | ||||
| } | ||||
| 
 | ||||
| BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &trafo) const | ||||
| { | ||||
| 	return (m_convex_hull != nullptr && m_convex_hull->stl.stats.number_of_facets > 0) ?  | ||||
| 		m_convex_hull->transformed_bounding_box(trafo) : | ||||
| 		bounding_box.transformed(trafo); | ||||
| } | ||||
| 
 | ||||
| void GLVolume::set_range(double min_z, double max_z) | ||||
| { | ||||
|     this->qverts_range.first  = 0; | ||||
|  |  | |||
|  | @ -397,6 +397,9 @@ public: | |||
|     bool                is_left_handed() const; | ||||
| 
 | ||||
|     const BoundingBoxf3& transformed_bounding_box() const; | ||||
|     // non-caching variant
 | ||||
|     BoundingBoxf3        transformed_convex_hull_bounding_box(const Transform3d &trafo) const; | ||||
|     // caching variant
 | ||||
|     const BoundingBoxf3& transformed_convex_hull_bounding_box() const; | ||||
| 
 | ||||
|     bool                empty() const { return this->indexed_vertex_array.empty(); } | ||||
|  |  | |||
|  | @ -1748,7 +1748,7 @@ void GLCanvas3D::mirror_selection(Axis axis) | |||
| { | ||||
|     m_selection.mirror(axis); | ||||
|     do_mirror(); | ||||
|     wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|     wxGetApp().obj_manipul()->set_dirty(); | ||||
| } | ||||
| 
 | ||||
| // Reload the 3D scene of 
 | ||||
|  | @ -2091,7 +2091,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re | |||
|         // to force a reset of its cache
 | ||||
|         auto manip = wxGetApp().obj_manipul(); | ||||
|         if (manip != nullptr) | ||||
|             manip->update_settings_value(m_selection); | ||||
|             manip->set_dirty(); | ||||
|     } | ||||
| 
 | ||||
|     // and force this canvas to be redrawn.
 | ||||
|  | @ -2726,7 +2726,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
| 
 | ||||
|             m_regenerate_volumes = false; | ||||
|             m_selection.translate(cur_pos - m_mouse.drag.start_position_3D); | ||||
|             wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|             wxGetApp().obj_manipul()->set_dirty(); | ||||
| 
 | ||||
|             m_dirty = true; | ||||
|         } | ||||
|  | @ -2781,7 +2781,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         { | ||||
|             m_regenerate_volumes = false; | ||||
|             do_move(); | ||||
|             wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|             wxGetApp().obj_manipul()->set_dirty(); | ||||
|             // Let the platter know that the dragging finished, so a delayed refresh
 | ||||
|             // of the scene with the background processing data should be performed.
 | ||||
|             post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); | ||||
|  | @ -2793,7 +2793,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             { | ||||
|                 m_selection.clear(); | ||||
|                 m_selection.set_mode(Selection::Instance); | ||||
|                 wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|                 wxGetApp().obj_manipul()->set_dirty(); | ||||
|                 m_gizmos.reset_all_states(); | ||||
|                 m_gizmos.update_data(*this); | ||||
|                 post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
|  | @ -2817,7 +2817,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|                     m_gizmos.refresh_on_off_state(m_selection); | ||||
|                     post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
|                     m_gizmos.update_data(*this); | ||||
|                     wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|                     wxGetApp().obj_manipul()->set_dirty(); | ||||
|                     // forces a frame render to update the view before the context menu is shown
 | ||||
|                     render(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -197,8 +197,10 @@ bool ObjectManipulation::IsShown() | |||
| 
 | ||||
| void ObjectManipulation::UpdateAndShow(const bool show) | ||||
| { | ||||
|     if (show) | ||||
|         update_settings_value(wxGetApp().plater()->canvas3D()->get_selection()); | ||||
| 	if (show) { | ||||
|         this->set_dirty(); | ||||
| 		this->update_if_dirty(); | ||||
| 	} | ||||
| 
 | ||||
|     OG_Settings::UpdateAndShow(show); | ||||
| } | ||||
|  | @ -210,41 +212,35 @@ void ObjectManipulation::update_settings_value(const Selection& selection) | |||
|     m_new_scale_label_string  = L("Scale factors"); | ||||
| 
 | ||||
|     ObjectList* obj_list = wxGetApp().obj_list(); | ||||
|     if (selection.is_single_full_instance() && ! m_world_coordinates) | ||||
|     if (selection.is_single_full_instance()) | ||||
|     { | ||||
|         // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
 | ||||
|         const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|         m_new_position = volume->get_instance_offset(); | ||||
|         m_new_rotation = volume->get_instance_rotation() * (180. / M_PI); | ||||
|         m_new_scale    = volume->get_instance_scaling_factor() * 100.; | ||||
|         int obj_idx = volume->object_idx(); | ||||
|         int instance_idx = volume->instance_idx(); | ||||
|         if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size())) | ||||
|         { | ||||
|             bool changed_box = false; | ||||
|             //FIXME matching an object idx may not be enough
 | ||||
|             if (!m_cache.instance.matches_object(obj_idx)) | ||||
|             { | ||||
|                 m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size()); | ||||
|                 changed_box = true; | ||||
|             } | ||||
|             //FIXME matching an instance idx may not be enough. Check for ModelObject id an all ModelVolume ids.
 | ||||
|             if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(m_new_scale)) | ||||
|                 m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(m_cache.instance.box_size); | ||||
|         } | ||||
|         else { | ||||
|             // this should never happen
 | ||||
|             assert(false); | ||||
|             m_new_size = Vec3d::Zero(); | ||||
|         } | ||||
| 
 | ||||
|         // Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
 | ||||
| 		if (m_world_coordinates && ! m_uniform_scale &&  | ||||
|             ! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { | ||||
| 			// Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling.
 | ||||
| 			m_uniform_scale = true; | ||||
| 			m_lock_bnt->SetLock(true); | ||||
| 		} | ||||
| 
 | ||||
|         if (m_world_coordinates) { | ||||
| 			m_new_rotate_label_string = L("Rotate"); | ||||
| 			m_new_rotation = Vec3d::Zero(); | ||||
| 			m_new_size     = selection.get_bounding_box().size(); | ||||
| 			m_new_scale    = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.; | ||||
| 		} else { | ||||
| 			m_new_rotation = volume->get_instance_rotation() * (180. / M_PI); | ||||
| 			m_new_size     = volume->get_instance_transformation().get_scaling_factor().cwiseProduct((*wxGetApp().model_objects())[volume->object_idx()]->raw_mesh_bounding_box().size()); | ||||
| 			m_new_scale    = volume->get_instance_scaling_factor() * 100.; | ||||
| 		} | ||||
| 
 | ||||
|         m_new_enabled  = true; | ||||
|     } | ||||
|     else if ((selection.is_single_full_instance() && m_world_coordinates) || | ||||
|              (selection.is_single_full_object() && obj_list->is_selected(itObject))) | ||||
|     else if (selection.is_single_full_object() && obj_list->is_selected(itObject)) | ||||
|     { | ||||
|         m_cache.instance.reset(); | ||||
| 
 | ||||
|         const BoundingBoxf3& box = selection.get_bounding_box(); | ||||
|         m_new_position = box.center(); | ||||
|         m_new_rotation = Vec3d::Zero(); | ||||
|  | @ -253,23 +249,9 @@ void ObjectManipulation::update_settings_value(const Selection& selection) | |||
|         m_new_rotate_label_string = L("Rotate"); | ||||
| 		m_new_scale_label_string  = L("Scale"); | ||||
|         m_new_enabled  = true; | ||||
| 
 | ||||
| 		if (selection.is_single_full_instance() && m_world_coordinates && ! m_uniform_scale) { | ||||
| 			// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
 | ||||
| 			// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
 | ||||
| 			const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
| 			// Is the angle close to a multiple of 90 degrees?
 | ||||
| 			if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { | ||||
| 				// Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling.
 | ||||
| 				m_uniform_scale = true; | ||||
| 				m_lock_bnt->SetLock(true); | ||||
| 			} | ||||
| 		} | ||||
|     } | ||||
|     else if (selection.is_single_modifier() || selection.is_single_volume()) | ||||
|     { | ||||
|         m_cache.instance.reset(); | ||||
| 
 | ||||
|         // the selection contains a single volume
 | ||||
|         const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|         m_new_position = volume->get_volume_offset(); | ||||
|  | @ -292,15 +274,16 @@ void ObjectManipulation::update_settings_value(const Selection& selection) | |||
| //		assert(selection.is_empty());
 | ||||
| 		reset_settings_value(); | ||||
| 	} | ||||
| 
 | ||||
|     m_dirty = true; | ||||
| } | ||||
| 
 | ||||
| void ObjectManipulation::update_if_dirty() | ||||
| { | ||||
|     if (!m_dirty) | ||||
|     if (! m_dirty) | ||||
|         return; | ||||
| 
 | ||||
|     const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection(); | ||||
|     this->update_settings_value(selection); | ||||
| 
 | ||||
|     auto update_label = [](wxString &label_cache, const std::string &new_label, wxStaticText *widget) { | ||||
|         wxString new_label_localized = _(new_label) + ":"; | ||||
|         if (label_cache != new_label_localized) { | ||||
|  | @ -330,7 +313,7 @@ void ObjectManipulation::update_if_dirty() | |||
|         update(m_cache.rotation, m_cache.rotation_rounded, "rotation_", m_new_rotation); | ||||
|     } | ||||
| 
 | ||||
|     if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) { | ||||
|     if (selection.requires_uniform_scale()) { | ||||
|         m_lock_bnt->SetLock(true); | ||||
|         m_lock_bnt->Disable(); | ||||
|     } | ||||
|  | @ -377,8 +360,9 @@ void ObjectManipulation::reset_settings_value() | |||
|     m_new_scale = Vec3d::Ones(); | ||||
|     m_new_size = Vec3d::Zero(); | ||||
|     m_new_enabled = false; | ||||
|     m_cache.instance.reset(); | ||||
|     m_dirty = true; | ||||
|     // no need to set the dirty flag here as this method is called from update_settings_value(),
 | ||||
|     // which is called from update_if_dirty(), which resets the dirty flag anyways.
 | ||||
| //    m_dirty = true;
 | ||||
| } | ||||
| 
 | ||||
| void ObjectManipulation::change_position_value(int axis, double value) | ||||
|  | @ -437,12 +421,9 @@ void ObjectManipulation::change_scale_value(int axis, double value) | |||
|         return; | ||||
| 
 | ||||
|     Vec3d scale = m_cache.scale; | ||||
|     scale(axis) = value; | ||||
| 	scale(axis) = value; | ||||
| 
 | ||||
|     this->do_scale(scale); | ||||
| 
 | ||||
|     if (!m_cache.scale.isApprox(scale)) | ||||
|         m_cache.instance.instance_idx = -1; | ||||
|     this->do_scale(axis, scale); | ||||
| 
 | ||||
|     m_cache.scale = scale; | ||||
| 	m_cache.scale_rounded(axis) = DBL_MAX; | ||||
|  | @ -460,46 +441,34 @@ void ObjectManipulation::change_size_value(int axis, double value) | |||
|     const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); | ||||
| 
 | ||||
|     Vec3d ref_size = m_cache.size; | ||||
|     if (selection.is_single_volume() || selection.is_single_modifier()) | ||||
|     { | ||||
|         const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|         ref_size = volume->bounding_box.size(); | ||||
|     } | ||||
|     else if (selection.is_single_full_instance() && ! m_world_coordinates) | ||||
|         ref_size = m_cache.instance.box_size; | ||||
| 	if (selection.is_single_volume() || selection.is_single_modifier()) | ||||
| 		ref_size = selection.get_volume(*selection.get_volume_idxs().begin())->bounding_box.size(); | ||||
| 	else if (selection.is_single_full_instance()) | ||||
| 		ref_size = m_world_coordinates ?  | ||||
|             selection.get_unscaled_instance_bounding_box().size() : | ||||
|             (*wxGetApp().model_objects())[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size(); | ||||
| 
 | ||||
|     this->do_scale(100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); | ||||
|     this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); | ||||
| 
 | ||||
|     m_cache.size = size; | ||||
| 	m_cache.size_rounded(axis) = DBL_MAX; | ||||
| 	this->UpdateAndShow(true); | ||||
| } | ||||
| 
 | ||||
| void ObjectManipulation::do_scale(const Vec3d &scale) const | ||||
| void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const | ||||
| { | ||||
|     Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); | ||||
|     Vec3d scaling_factor = scale; | ||||
| 
 | ||||
|     TransformationType transformation_type(TransformationType::World_Relative_Joint); | ||||
|     if (selection.is_single_full_instance()) { | ||||
|         if (m_world_coordinates) { | ||||
|             // Only a 90 degree rotation is allowed, therefore an axis aligned scaling will
 | ||||
|             // be still axis aligned after the instance rotation is applied.
 | ||||
|             const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|             scaling_factor = (volume->get_instance_transformation().get_matrix(true, false, true, true) * scale).cwiseAbs(); | ||||
|             // Absolute scaling shall not change.
 | ||||
|             assert(std::abs(scale.maxCoeff() - scaling_factor.maxCoeff()) < EPSILON); | ||||
| 			assert(std::abs(scale.minCoeff() - scaling_factor.minCoeff()) < EPSILON); | ||||
| 			assert(std::abs(scale.squaredNorm() - scaling_factor.squaredNorm()) < EPSILON); | ||||
| 		} else | ||||
|         transformation_type.set_absolute(); | ||||
|         if (! m_world_coordinates) | ||||
|             transformation_type.set_local(); | ||||
|     } | ||||
| 
 | ||||
|     if (m_uniform_scale || selection.requires_uniform_scale()) { | ||||
|         int max_diff_axis; | ||||
|         (scale - m_cache.scale).cwiseAbs().maxCoeff(&max_diff_axis); | ||||
|         scaling_factor = scale(max_diff_axis) * Vec3d::Ones(); | ||||
|     } | ||||
|     if (m_uniform_scale || selection.requires_uniform_scale()) | ||||
|         scaling_factor = scale(axis) * Vec3d::Ones(); | ||||
| 
 | ||||
|     selection.start_dragging(); | ||||
|     selection.scale(scaling_factor * 0.01, transformation_type); | ||||
|  | @ -577,8 +546,10 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value) | |||
| 		if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { | ||||
|             // Cannot apply scaling in the world coordinate system.
 | ||||
| 			wxMessageDialog dlg(GUI::wxGetApp().mainframe, | ||||
|                 _(L("Non-uniform scaling of tilted objects is not supported in the World coordinate system.\n" | ||||
|                     "Do you want to rotate the mesh?")), | ||||
|                 _(L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n" | ||||
|                     "Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n" | ||||
|                     "once the rotation is embedded into the object coordinates.\n" | ||||
|                     "Do you want to proceed?")), | ||||
|                 SLIC3R_APP_NAME, | ||||
|                 wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); | ||||
|             if (dlg.ShowModal() != wxID_YES) { | ||||
|  | @ -590,6 +561,8 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value) | |||
|             (*wxGetApp().model_objects())[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id); | ||||
|             // Update the 3D scene, selections etc.
 | ||||
|             wxGetApp().plater()->update(); | ||||
|             // Recalculate cached values at this panel, refresh the screen.
 | ||||
|             this->UpdateAndShow(true); | ||||
|         } | ||||
|     } | ||||
|     m_uniform_scale = new_value; | ||||
|  |  | |||
|  | @ -32,22 +32,6 @@ class ObjectManipulation : public OG_Settings | |||
|         wxString rotate_label_string; | ||||
|         wxString scale_label_string; | ||||
| 
 | ||||
|         struct Instance | ||||
|         { | ||||
|             int object_idx; | ||||
|             int instance_idx; | ||||
|             Vec3d box_size; | ||||
| 
 | ||||
|             Instance() { reset(); } | ||||
|             void reset() { this->object_idx = -1; this->instance_idx = -1; this->box_size = Vec3d::Zero(); } | ||||
|             void set(int object_idx, int instance_idx, const Vec3d& box_size) { this->object_idx = object_idx; this->instance_idx = instance_idx; this->box_size = box_size; } | ||||
|             bool matches(int object_idx, int instance_idx) const { return (this->object_idx == object_idx) && (this->instance_idx == instance_idx); } | ||||
|             bool matches_object(int object_idx) const { return (this->object_idx == object_idx); } | ||||
|             bool matches_instance(int instance_idx) const { return (this->instance_idx == instance_idx); } | ||||
|         }; | ||||
| 
 | ||||
|         Instance instance; | ||||
| 
 | ||||
|         Cache() { reset(); } | ||||
|         void reset() | ||||
|         { | ||||
|  | @ -58,7 +42,6 @@ class ObjectManipulation : public OG_Settings | |||
|             move_label_string = wxString(); | ||||
|             rotate_label_string = wxString(); | ||||
|             scale_label_string = wxString(); | ||||
|             instance.reset(); | ||||
|         } | ||||
|         bool is_valid() const { return position != Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); } | ||||
|     }; | ||||
|  | @ -99,8 +82,7 @@ public: | |||
|     bool        IsShown() override; | ||||
|     void        UpdateAndShow(const bool show) override; | ||||
| 
 | ||||
|     void        update_settings_value(const Selection& selection); | ||||
| 
 | ||||
|     void        set_dirty() { m_dirty = true; } | ||||
| 	// Called from the App to update the UI if dirty.
 | ||||
| 	void		update_if_dirty(); | ||||
| 
 | ||||
|  | @ -120,6 +102,7 @@ public: | |||
| 
 | ||||
| private: | ||||
|     void reset_settings_value(); | ||||
|     void update_settings_value(const Selection& selection); | ||||
| 
 | ||||
|     // update size values after scale unit changing or "gizmos"
 | ||||
|     void update_size_value(const Vec3d& size); | ||||
|  | @ -131,7 +114,7 @@ private: | |||
|     void change_rotation_value(int axis, double value); | ||||
|     void change_scale_value(int axis, double value); | ||||
|     void change_size_value(int axis, double value); | ||||
|     void do_scale(const Vec3d &scale) const; | ||||
|     void do_scale(int axis, const Vec3d &scale) const; | ||||
| 
 | ||||
|     void on_change(t_config_option_key opt_key, const boost::any& value); | ||||
|     void on_fill_empty_value(const std::string& opt_key); | ||||
|  |  | |||
|  | @ -590,7 +590,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | |||
|                     // Rotate the object so the normal points downward:
 | ||||
|                     selection.flattening_rotate(get_flattening_normal()); | ||||
|                     canvas.do_flatten(); | ||||
|                     wxGetApp().obj_manipul()->update_settings_value(selection); | ||||
|                     wxGetApp().obj_manipul()->set_dirty(); | ||||
|                 } | ||||
| 
 | ||||
|                 canvas.set_as_dirty(); | ||||
|  | @ -623,17 +623,17 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | |||
|             { | ||||
|                 // Apply new temporary offset
 | ||||
|                 selection.translate(get_displacement()); | ||||
|                 wxGetApp().obj_manipul()->update_settings_value(selection); | ||||
|                 wxGetApp().obj_manipul()->set_dirty(); | ||||
|                 break; | ||||
|             } | ||||
|             case Scale: | ||||
|             { | ||||
|                 // Apply new temporary scale factors
 | ||||
| 				TransformationType transformation_type(TransformationType::Local_Relative_Joint); | ||||
| 				TransformationType transformation_type(TransformationType::Local_Absolute_Joint); | ||||
| 				if (evt.AltDown()) | ||||
| 					transformation_type.set_independent(); | ||||
| 				selection.scale(get_scale(), transformation_type); | ||||
|                 wxGetApp().obj_manipul()->update_settings_value(selection); | ||||
|                 wxGetApp().obj_manipul()->set_dirty(); | ||||
|                 break; | ||||
|             } | ||||
|             case Rotate: | ||||
|  | @ -643,7 +643,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | |||
|                 if (evt.AltDown()) | ||||
|                     transformation_type.set_independent(); | ||||
|                 selection.rotate(get_rotation(), transformation_type); | ||||
|                 wxGetApp().obj_manipul()->update_settings_value(selection); | ||||
|                 wxGetApp().obj_manipul()->set_dirty(); | ||||
|                 break; | ||||
|             } | ||||
|             default: | ||||
|  | @ -680,7 +680,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | |||
|             stop_dragging(); | ||||
|             update_data(canvas); | ||||
| 
 | ||||
|             wxGetApp().obj_manipul()->update_settings_value(selection); | ||||
|             wxGetApp().obj_manipul()->set_dirty(); | ||||
|             // Let the platter know that the dragging finished, so a delayed refresh
 | ||||
|             // of the scene with the background processing data should be performed.
 | ||||
|             canvas.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); | ||||
|  |  | |||
|  | @ -54,10 +54,10 @@ Selection::Selection() | |||
|     , m_mode(Instance) | ||||
|     , m_type(Empty) | ||||
|     , m_valid(false) | ||||
|     , m_bounding_box_dirty(true) | ||||
|     , m_curved_arrow(16) | ||||
|     , m_scale_factor(1.0f) | ||||
| { | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| #if ENABLE_RENDER_SELECTION_CENTER | ||||
|     m_quadric = ::gluNewQuadric(); | ||||
|     if (m_quadric != nullptr) | ||||
|  | @ -148,7 +148,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec | |||
|     } | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::remove(unsigned int volume_idx) | ||||
|  | @ -173,7 +173,7 @@ void Selection::remove(unsigned int volume_idx) | |||
|     } | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::add_object(unsigned int object_idx, bool as_single_selection) | ||||
|  | @ -190,7 +190,7 @@ void Selection::add_object(unsigned int object_idx, bool as_single_selection) | |||
|     do_add_object(object_idx); | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::remove_object(unsigned int object_idx) | ||||
|  | @ -201,7 +201,7 @@ void Selection::remove_object(unsigned int object_idx) | |||
|     do_remove_object(object_idx); | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::add_instance(unsigned int object_idx, unsigned int instance_idx, bool as_single_selection) | ||||
|  | @ -218,7 +218,7 @@ void Selection::add_instance(unsigned int object_idx, unsigned int instance_idx, | |||
|     do_add_instance(object_idx, instance_idx); | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::remove_instance(unsigned int object_idx, unsigned int instance_idx) | ||||
|  | @ -229,7 +229,7 @@ void Selection::remove_instance(unsigned int object_idx, unsigned int instance_i | |||
|     do_remove_instance(object_idx, instance_idx); | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_idx, bool as_single_selection) | ||||
|  | @ -254,7 +254,7 @@ void Selection::add_volume(unsigned int object_idx, unsigned int volume_idx, int | |||
|     } | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx) | ||||
|  | @ -270,7 +270,7 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx) | |||
|     } | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::add_all() | ||||
|  | @ -288,7 +288,7 @@ void Selection::add_all() | |||
|     } | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::clear() | ||||
|  | @ -304,7 +304,7 @@ void Selection::clear() | |||
|     m_list.clear(); | ||||
| 
 | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| 
 | ||||
|     // resets the cache in the sidebar
 | ||||
|     wxGetApp().obj_manipul()->reset_cache(); | ||||
|  | @ -323,7 +323,7 @@ void Selection::instances_changed(const std::vector<size_t> &instance_ids_select | |||
|             this->do_add_volume(volume_idx); | ||||
|     } | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| // Update the selection based on the map from old indices to new indices after m_volumes changed.
 | ||||
|  | @ -341,7 +341,7 @@ void Selection::volumes_changed(const std::vector<size_t> &map_volume_old_to_new | |||
|         } | ||||
|     m_list = std::move(list_new); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| bool Selection::is_single_full_instance() const | ||||
|  | @ -426,6 +426,14 @@ const BoundingBoxf3& Selection::get_bounding_box() const | |||
|     return m_bounding_box; | ||||
| } | ||||
| 
 | ||||
| const BoundingBoxf3& Selection::get_unscaled_instance_bounding_box() const | ||||
| { | ||||
|     if (m_unscaled_instance_bounding_box_dirty) | ||||
|         calc_unscaled_instance_bounding_box(); | ||||
| 
 | ||||
|     return m_unscaled_instance_bounding_box; | ||||
| } | ||||
| 
 | ||||
| void Selection::start_dragging() | ||||
| { | ||||
|     if (!m_valid) | ||||
|  | @ -473,7 +481,7 @@ void Selection::translate(const Vec3d& displacement, bool local) | |||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| // Rotate an object around one of the axes. Only one rotation component is expected to be changing.
 | ||||
|  | @ -580,7 +588,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ | |||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::flattening_rotate(const Vec3d& normal) | ||||
|  | @ -621,7 +629,7 @@ void Selection::flattening_rotate(const Vec3d& normal) | |||
|         synchronize_unselected_instances(SYNC_ROTATION_FULL); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::scale(const Vec3d& scale, TransformationType transformation_type) | ||||
|  | @ -629,15 +637,21 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type | |||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     // Only relative scaling values are allowed in the world coordinate system.
 | ||||
|     assert(! transformation_type.world() || transformation_type.relative()); | ||||
| 
 | ||||
|     for (unsigned int i : m_list) | ||||
|     { | ||||
|         if (is_single_full_instance() && ! transformation_type.world()) | ||||
|             (*m_volumes)[i]->set_instance_scaling_factor(scale); | ||||
|         GLVolume &volume = *(*m_volumes)[i]; | ||||
|         if (is_single_full_instance()) { | ||||
|             assert(transformation_type.absolute()); | ||||
| 			if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) { | ||||
|                 // Non-uniform scaling. Transform the scaling factors into the local coordinate system.
 | ||||
|                 // This is only possible, if the instance rotation is mulitples of ninety degrees.
 | ||||
|                 assert(Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation())); | ||||
| 				volume.set_instance_scaling_factor((volume.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs()); | ||||
|             } else | ||||
| 				volume.set_instance_scaling_factor(scale); | ||||
|         } | ||||
|         else if (is_single_volume() || is_single_modifier()) | ||||
|             (*m_volumes)[i]->set_volume_scaling_factor(scale); | ||||
|             volume.set_volume_scaling_factor(scale); | ||||
|         else | ||||
|         { | ||||
|             Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale); | ||||
|  | @ -647,9 +661,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type | |||
|                 // extracts scaling factors from the composed transformation
 | ||||
|                 Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); | ||||
|                 if (transformation_type.joint()) | ||||
|                     (*m_volumes)[i]->set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); | ||||
|                     volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); | ||||
| 
 | ||||
|                 (*m_volumes)[i]->set_instance_scaling_factor(new_scale); | ||||
|                 volume.set_instance_scaling_factor(new_scale); | ||||
|             } | ||||
|             else if (m_mode == Volume) | ||||
|             { | ||||
|  | @ -659,9 +673,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type | |||
|                 if (transformation_type.joint()) | ||||
|                 { | ||||
|                     Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); | ||||
|                     (*m_volumes)[i]->set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); | ||||
|                     volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); | ||||
|                 } | ||||
|                 (*m_volumes)[i]->set_volume_scaling_factor(new_scale); | ||||
|                 volume.set_volume_scaling_factor(new_scale); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -675,7 +689,7 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type | |||
| 
 | ||||
|     ensure_on_bed(); | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::mirror(Axis axis) | ||||
|  | @ -700,7 +714,7 @@ void Selection::mirror(Axis axis) | |||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::translate(unsigned int object_idx, const Vec3d& displacement) | ||||
|  | @ -745,7 +759,7 @@ void Selection::translate(unsigned int object_idx, const Vec3d& displacement) | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement) | ||||
|  | @ -790,7 +804,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|     this->set_bounding_boxes_dirty(); | ||||
| } | ||||
| 
 | ||||
| void Selection::erase() | ||||
|  | @ -1396,7 +1410,23 @@ void Selection::calc_bounding_box() const | |||
|             m_bounding_box.merge((*m_volumes)[i]->transformed_convex_hull_bounding_box()); | ||||
|         } | ||||
|     } | ||||
|     m_bounding_box_dirty = false; | ||||
| 	m_bounding_box_dirty = false; | ||||
| } | ||||
| 
 | ||||
| void Selection::calc_unscaled_instance_bounding_box() const | ||||
| { | ||||
| 	m_unscaled_instance_bounding_box = BoundingBoxf3(); | ||||
| 	if (m_valid) | ||||
| 	{ | ||||
| 		for (unsigned int i : m_list) | ||||
| 		{ | ||||
| 			const GLVolume &volume = *(*m_volumes)[i]; | ||||
| 			Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix(); | ||||
| 			trafo.translation()(2) += volume.get_sla_shift_z(); | ||||
| 			m_unscaled_instance_bounding_box.merge(volume.transformed_convex_hull_bounding_box(trafo)); | ||||
| 		} | ||||
| 	} | ||||
| 	m_unscaled_instance_bounding_box_dirty = false; | ||||
| } | ||||
| 
 | ||||
| void Selection::render_selected_volumes() const | ||||
|  |  | |||
|  | @ -183,6 +183,10 @@ private: | |||
|     Clipboard m_clipboard; | ||||
|     mutable BoundingBoxf3 m_bounding_box; | ||||
|     mutable bool m_bounding_box_dirty; | ||||
|     // Bounding box of a selection, with no instance scaling applied. This bounding box
 | ||||
|     // is useful for absolute scaling of tilted objects in world coordinate space.
 | ||||
|     mutable BoundingBoxf3 m_unscaled_instance_bounding_box; | ||||
|     mutable bool m_unscaled_instance_bounding_box_dirty; | ||||
| 
 | ||||
| #if ENABLE_RENDER_SELECTION_CENTER | ||||
|     GLUquadricObj* m_quadric; | ||||
|  | @ -265,6 +269,9 @@ public: | |||
| 
 | ||||
|     unsigned int volumes_count() const { return (unsigned int)m_list.size(); } | ||||
|     const BoundingBoxf3& get_bounding_box() const; | ||||
|     // Bounding box of a selection, with no instance scaling applied. This bounding box
 | ||||
|     // is useful for absolute scaling of tilted objects in world coordinate space.
 | ||||
|     const BoundingBoxf3& get_unscaled_instance_bounding_box() const; | ||||
| 
 | ||||
|     void start_dragging(); | ||||
| 
 | ||||
|  | @ -303,6 +310,8 @@ private: | |||
|     void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); | ||||
|     void do_remove_object(unsigned int object_idx); | ||||
|     void calc_bounding_box() const; | ||||
|     void calc_unscaled_instance_bounding_box() const; | ||||
|     void set_bounding_boxes_dirty() { m_bounding_box_dirty = true; m_unscaled_instance_bounding_box_dirty = true; } | ||||
|     void render_selected_volumes() const; | ||||
|     void render_synchronized_volumes() const; | ||||
|     void render_bounding_box(const BoundingBoxf3& box, float* color) const; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv