mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 16:57:53 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer
This commit is contained in:
commit
34759f9a70
5 changed files with 126 additions and 95 deletions
|
@ -507,9 +507,9 @@ protected:
|
||||||
bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); }
|
bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); }
|
||||||
PrintStateBase::TimeStamp set_done(PrintStepEnum step) {
|
PrintStateBase::TimeStamp set_done(PrintStepEnum step) {
|
||||||
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); });
|
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); });
|
||||||
if (status.second)
|
if (status.second)
|
||||||
this->status_update_warnings(this->id(), static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
this->status_update_warnings(this->id(), static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||||
return status.first;
|
return status.first;
|
||||||
}
|
}
|
||||||
bool invalidate_step(PrintStepEnum step)
|
bool invalidate_step(PrintStepEnum step)
|
||||||
{ return m_state.invalidate(step, this->cancel_callback()); }
|
{ return m_state.invalidate(step, this->cancel_callback()); }
|
||||||
|
@ -556,9 +556,9 @@ protected:
|
||||||
{ return m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); }
|
{ return m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); }
|
||||||
PrintStateBase::TimeStamp set_done(PrintObjectStepEnum step) {
|
PrintStateBase::TimeStamp set_done(PrintObjectStepEnum step) {
|
||||||
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); });
|
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); });
|
||||||
if (status.second)
|
if (status.second)
|
||||||
this->status_update_warnings(m_print, static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
this->status_update_warnings(m_print, static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||||
return status.first;
|
return status.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool invalidate_step(PrintObjectStepEnum step)
|
bool invalidate_step(PrintObjectStepEnum step)
|
||||||
|
|
|
@ -3758,6 +3758,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
{
|
{
|
||||||
m_mouse.dragging = true;
|
m_mouse.dragging = true;
|
||||||
|
|
||||||
|
// Translation of objects is forbidden when SLA supports/hollowing/fdm
|
||||||
|
// supports gizmo is active.
|
||||||
|
if (m_gizmos.get_current_type() == GLGizmosManager::SlaSupports
|
||||||
|
|| m_gizmos.get_current_type() == GLGizmosManager::FdmSupports
|
||||||
|
|| m_gizmos.get_current_type() == GLGizmosManager::Hollow)
|
||||||
|
return;
|
||||||
|
|
||||||
Vec3d cur_pos = m_mouse.drag.start_position_3D;
|
Vec3d cur_pos = m_mouse.drag.start_position_3D;
|
||||||
// we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
|
// we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
|
||||||
if (m_selection.contains_volume(get_first_hover_volume_idx()))
|
if (m_selection.contains_volume(get_first_hover_volume_idx()))
|
||||||
|
|
|
@ -314,106 +314,128 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||||
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
|
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
|
||||||
const Transform3d& instance_trafo = mi->get_transformation().get_matrix();
|
const Transform3d& instance_trafo = mi->get_transformation().get_matrix();
|
||||||
|
|
||||||
std::vector<std::vector<std::pair<Vec3f, size_t>>> hit_positions_and_facet_ids;
|
// List of mouse positions that will be used as seeds for painting.
|
||||||
bool clipped_mesh_was_hit = false;
|
std::vector<Vec2d> mouse_positions{mouse_position};
|
||||||
|
|
||||||
Vec3f normal = Vec3f::Zero();
|
// In case current mouse position is far from the last one,
|
||||||
Vec3f hit = Vec3f::Zero();
|
// add several positions from between into the list, so there
|
||||||
size_t facet = 0;
|
// are no gaps in the painted region.
|
||||||
Vec3f closest_hit = Vec3f::Zero();
|
{
|
||||||
double closest_hit_squared_distance = std::numeric_limits<double>::max();
|
if (m_last_mouse_position == Vec2d::Zero())
|
||||||
size_t closest_facet = 0;
|
m_last_mouse_position = mouse_position;
|
||||||
int closest_hit_mesh_id = -1;
|
// resolution describes minimal distance limit using circle radius
|
||||||
|
// as a unit (e.g., 2 would mean the patches will be touching).
|
||||||
|
double resolution = 0.7;
|
||||||
|
double diameter_px = resolution * m_cursor_radius * camera.get_zoom();
|
||||||
|
int patches_in_between = int(((mouse_position - m_last_mouse_position).norm() - diameter_px) / diameter_px);
|
||||||
|
if (patches_in_between > 0) {
|
||||||
|
Vec2d diff = (mouse_position - m_last_mouse_position)/(patches_in_between+1);
|
||||||
|
for (int i=1; i<=patches_in_between; ++i)
|
||||||
|
mouse_positions.emplace_back(m_last_mouse_position + i*diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_last_mouse_position = Vec2d::Zero(); // only actual hits should be saved
|
||||||
|
|
||||||
// Transformations of individual meshes
|
// Now "click" into all the prepared points and spill paint around them.
|
||||||
std::vector<Transform3d> trafo_matrices;
|
for (const Vec2d& mp : mouse_positions) {
|
||||||
|
std::vector<std::vector<std::pair<Vec3f, size_t>>> hit_positions_and_facet_ids;
|
||||||
|
bool clipped_mesh_was_hit = false;
|
||||||
|
|
||||||
int mesh_id = -1;
|
Vec3f normal = Vec3f::Zero();
|
||||||
// Cast a ray on all meshes, pick the closest hit and save it for the respective mesh
|
Vec3f hit = Vec3f::Zero();
|
||||||
for (const ModelVolume* mv : mo->volumes) {
|
size_t facet = 0;
|
||||||
if (! mv->is_model_part())
|
Vec3f closest_hit = Vec3f::Zero();
|
||||||
continue;
|
double closest_hit_squared_distance = std::numeric_limits<double>::max();
|
||||||
|
size_t closest_facet = 0;
|
||||||
|
int closest_hit_mesh_id = -1;
|
||||||
|
|
||||||
++mesh_id;
|
// Transformations of individual meshes
|
||||||
|
std::vector<Transform3d> trafo_matrices;
|
||||||
|
|
||||||
trafo_matrices.push_back(instance_trafo * mv->get_matrix());
|
int mesh_id = -1;
|
||||||
hit_positions_and_facet_ids.push_back(std::vector<std::pair<Vec3f, size_t>>());
|
// Cast a ray on all meshes, pick the closest hit and save it for the respective mesh
|
||||||
|
for (const ModelVolume* mv : mo->volumes) {
|
||||||
if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(
|
if (! mv->is_model_part())
|
||||||
mouse_position,
|
|
||||||
trafo_matrices[mesh_id],
|
|
||||||
camera,
|
|
||||||
hit,
|
|
||||||
normal,
|
|
||||||
m_clipping_plane.get(),
|
|
||||||
&facet))
|
|
||||||
{
|
|
||||||
// In case this hit is clipped, skip it.
|
|
||||||
if (is_mesh_point_clipped(hit.cast<double>())) {
|
|
||||||
clipped_mesh_was_hit = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Is this hit the closest to the camera so far?
|
++mesh_id;
|
||||||
double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast<double>()).squaredNorm();
|
|
||||||
if (hit_squared_distance < closest_hit_squared_distance) {
|
trafo_matrices.push_back(instance_trafo * mv->get_matrix());
|
||||||
closest_hit_squared_distance = hit_squared_distance;
|
hit_positions_and_facet_ids.push_back(std::vector<std::pair<Vec3f, size_t>>());
|
||||||
closest_facet = facet;
|
|
||||||
closest_hit_mesh_id = mesh_id;
|
if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(
|
||||||
closest_hit = hit;
|
mp,
|
||||||
|
trafo_matrices[mesh_id],
|
||||||
|
camera,
|
||||||
|
hit,
|
||||||
|
normal,
|
||||||
|
m_clipping_plane.get(),
|
||||||
|
&facet))
|
||||||
|
{
|
||||||
|
// In case this hit is clipped, skip it.
|
||||||
|
if (is_mesh_point_clipped(hit.cast<double>())) {
|
||||||
|
clipped_mesh_was_hit = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this hit the closest to the camera so far?
|
||||||
|
double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast<double>()).squaredNorm();
|
||||||
|
if (hit_squared_distance < closest_hit_squared_distance) {
|
||||||
|
closest_hit_squared_distance = hit_squared_distance;
|
||||||
|
closest_facet = facet;
|
||||||
|
closest_hit_mesh_id = mesh_id;
|
||||||
|
closest_hit = hit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool dragging_while_painting = (action == SLAGizmoEventType::Dragging && m_button_down != Button::None);
|
bool dragging_while_painting = (action == SLAGizmoEventType::Dragging && m_button_down != Button::None);
|
||||||
|
|
||||||
// The mouse button click detection is enabled when there is a valid hit
|
// The mouse button click detection is enabled when there is a valid hit
|
||||||
// or when the user clicks the clipping plane. Missing the object entirely
|
// or when the user clicks the clipping plane. Missing the object entirely
|
||||||
// shall not capture the mouse.
|
// shall not capture the mouse.
|
||||||
if (closest_hit_mesh_id != -1 || clipped_mesh_was_hit) {
|
if (closest_hit_mesh_id != -1 || clipped_mesh_was_hit) {
|
||||||
if (m_button_down == Button::None)
|
if (m_button_down == Button::None)
|
||||||
m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right);
|
m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right);
|
||||||
}
|
|
||||||
|
|
||||||
if (closest_hit_mesh_id == -1) {
|
|
||||||
// In case we have no valid hit, we can return. The event will
|
|
||||||
// be stopped in following two cases:
|
|
||||||
// 1. clicking the clipping plane
|
|
||||||
// 2. dragging while painting (to prevent scene rotations and moving the object)
|
|
||||||
return clipped_mesh_was_hit
|
|
||||||
|| dragging_while_painting;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find respective mesh id.
|
|
||||||
// FIXME We need a separate TriangleSelector for each volume mesh.
|
|
||||||
mesh_id = -1;
|
|
||||||
//const TriangleMesh* mesh = nullptr;
|
|
||||||
for (const ModelVolume* mv : mo->volumes) {
|
|
||||||
if (! mv->is_model_part())
|
|
||||||
continue;
|
|
||||||
++mesh_id;
|
|
||||||
if (mesh_id == closest_hit_mesh_id) {
|
|
||||||
//mesh = &mv->mesh();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (closest_hit_mesh_id == -1) {
|
||||||
|
// In case we have no valid hit, we can return. The event will
|
||||||
|
// be stopped in following two cases:
|
||||||
|
// 1. clicking the clipping plane
|
||||||
|
// 2. dragging while painting (to prevent scene rotations and moving the object)
|
||||||
|
return clipped_mesh_was_hit
|
||||||
|
|| dragging_while_painting;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find respective mesh id.
|
||||||
|
mesh_id = -1;
|
||||||
|
for (const ModelVolume* mv : mo->volumes) {
|
||||||
|
if (! mv->is_model_part())
|
||||||
|
continue;
|
||||||
|
++mesh_id;
|
||||||
|
if (mesh_id == closest_hit_mesh_id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Transform3d& trafo_matrix = trafo_matrices[mesh_id];
|
||||||
|
|
||||||
|
// Calculate how far can a point be from the line (in mesh coords).
|
||||||
|
// FIXME: The scaling of the mesh can be non-uniform.
|
||||||
|
const Vec3d sf = Geometry::Transformation(trafo_matrix).get_scaling_factor();
|
||||||
|
const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.;
|
||||||
|
const float limit = m_cursor_radius/avg_scaling;
|
||||||
|
|
||||||
|
// Calculate direction from camera to the hit (in mesh coords):
|
||||||
|
Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast<float>();
|
||||||
|
Vec3f dir = (closest_hit - camera_pos).normalized();
|
||||||
|
|
||||||
|
assert(mesh_id < int(m_triangle_selectors.size()));
|
||||||
|
m_triangle_selectors[mesh_id]->select_patch(closest_hit, closest_facet, camera_pos,
|
||||||
|
dir, limit, new_state);
|
||||||
|
m_last_mouse_position = mouse_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Transform3d& trafo_matrix = trafo_matrices[mesh_id];
|
|
||||||
|
|
||||||
// Calculate how far can a point be from the line (in mesh coords).
|
|
||||||
// FIXME: The scaling of the mesh can be non-uniform.
|
|
||||||
const Vec3d sf = Geometry::Transformation(trafo_matrix).get_scaling_factor();
|
|
||||||
const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.;
|
|
||||||
const float limit = m_cursor_radius/avg_scaling;
|
|
||||||
|
|
||||||
// Calculate direction from camera to the hit (in mesh coords):
|
|
||||||
Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast<float>();
|
|
||||||
Vec3f dir = (closest_hit - camera_pos).normalized();
|
|
||||||
|
|
||||||
assert(mesh_id < int(m_triangle_selectors.size()));
|
|
||||||
m_triangle_selectors[mesh_id]->select_patch(closest_hit, closest_facet, camera_pos,
|
|
||||||
dir, limit, new_state);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +452,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||||
update_model_object();
|
update_model_object();
|
||||||
|
|
||||||
m_button_down = Button::None;
|
m_button_down = Button::None;
|
||||||
|
m_last_mouse_position = Vec2d::Zero();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ private:
|
||||||
bool m_setting_angle = false;
|
bool m_setting_angle = false;
|
||||||
bool m_internal_stack_active = false;
|
bool m_internal_stack_active = false;
|
||||||
bool m_schedule_update = false;
|
bool m_schedule_update = false;
|
||||||
|
Vec2d m_last_mouse_position = Vec2d::Zero();
|
||||||
|
|
||||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||||
|
|
|
@ -2944,7 +2944,7 @@ void Plater::priv::export_gcode(fs::path output_path, bool output_path_on_remova
|
||||||
if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
|
if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
show_warning_dialog = true;
|
show_warning_dialog = true;
|
||||||
if (! output_path.empty()) {
|
if (! output_path.empty()) {
|
||||||
background_process.schedule_export(output_path.string(), output_path_on_removable_media);
|
background_process.schedule_export(output_path.string(), output_path_on_removable_media);
|
||||||
} else {
|
} else {
|
||||||
|
@ -4856,8 +4856,8 @@ void Plater::export_gcode(bool prefer_removable)
|
||||||
if (p->model.objects.empty())
|
if (p->model.objects.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (p->process_completed_with_error)//here
|
if (p->process_completed_with_error)//here
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If possible, remove accents from accented latin characters.
|
// If possible, remove accents from accented latin characters.
|
||||||
// This function is useful for generating file names to be processed by legacy firmwares.
|
// This function is useful for generating file names to be processed by legacy firmwares.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue