This commit is contained in:
YuSanka 2018-12-07 18:00:17 +01:00
commit 386d46417a
21 changed files with 505 additions and 59 deletions

View file

@ -273,8 +273,13 @@ GLCanvas3D::Camera::Camera()
, zoom(1.0f)
, phi(45.0f)
// , distance(0.0f)
#if !ENABLE_CONSTRAINED_CAMERA_TARGET
, target(0.0, 0.0, 0.0)
#endif // !ENABLE_CONSTRAINED_CAMERA_TARGET
, m_theta(45.0f)
#if ENABLE_CONSTRAINED_CAMERA_TARGET
, m_target(Vec3d::Zero())
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
{
}
@ -292,16 +297,32 @@ std::string GLCanvas3D::Camera::get_type_as_string() const
};
}
float GLCanvas3D::Camera::get_theta() const
{
return m_theta;
}
void GLCanvas3D::Camera::set_theta(float theta)
{
m_theta = clamp(0.0f, GIMBALL_LOCK_THETA_MAX, theta);
}
#if ENABLE_CONSTRAINED_CAMERA_TARGET
void GLCanvas3D::Camera::set_target(const Vec3d& target, GLCanvas3D& canvas)
{
m_target = target;
m_target(0) = clamp(m_scene_box.min(0), m_scene_box.max(0), m_target(0));
m_target(1) = clamp(m_scene_box.min(1), m_scene_box.max(1), m_target(1));
m_target(2) = clamp(m_scene_box.min(2), m_scene_box.max(2), m_target(2));
if (!m_target.isApprox(target))
canvas.viewport_changed();
}
void GLCanvas3D::Camera::set_scene_box(const BoundingBoxf3& box, GLCanvas3D& canvas)
{
if (m_scene_box != box)
{
m_scene_box = box;
canvas.viewport_changed();
}
}
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
GLCanvas3D::Bed::Bed()
: m_type(Custom)
{
@ -1383,7 +1404,7 @@ bool GLCanvas3D::Selection::is_single_full_instance() const
return false;
int object_idx = m_valid ? get_object_idx() : -1;
if (object_idx == -1)
if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx))
return false;
int instance_idx = (*m_volumes)[*m_list.begin()]->instance_idx();
@ -1458,13 +1479,13 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement)
for (unsigned int i : m_list)
{
#if ENABLE_MODELVOLUME_TRANSFORM
if (m_mode == Instance)
(*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement);
else if (m_mode == Volume)
{
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix()).inverse() * displacement;
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
}
if ((m_mode == Volume) || (*m_volumes)[i]->is_wipe_tower)
{
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix()).inverse() * displacement;
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
}
else if (m_mode == Instance)
(*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement);
#else
(*m_volumes)[i]->set_offset(m_cache.volumes_data[i].get_position() + displacement);
#endif // ENABLE_MODELVOLUME_TRANSFORM
@ -3650,6 +3671,15 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const
return bb;
}
#if ENABLE_CONSTRAINED_CAMERA_TARGET
BoundingBoxf3 GLCanvas3D::scene_bounding_box() const
{
BoundingBoxf3 bb = volumes_bounding_box();
bb.merge(m_bed.get_bounding_box());
return bb;
}
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
bool GLCanvas3D::is_layers_editing_enabled() const
{
return m_layers_editing.is_enabled();
@ -3789,7 +3819,12 @@ void GLCanvas3D::set_viewport_from_scene(const GLCanvas3D& other)
{
m_camera.phi = other.m_camera.phi;
m_camera.set_theta(other.m_camera.get_theta());
#if ENABLE_CONSTRAINED_CAMERA_TARGET
m_camera.set_scene_box(other.m_camera.get_scene_box(), *this);
m_camera.set_target(other.m_camera.get_target(), *this);
#else
m_camera.target = other.m_camera.target;
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
m_camera.zoom = other.m_camera.zoom;
m_dirty = true;
}
@ -4318,6 +4353,12 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
// restore to default value
m_regenerate_volumes = true;
#if ENABLE_CONSTRAINED_CAMERA_TARGET
m_camera.set_scene_box(scene_bounding_box(), *this);
m_camera.set_target(m_camera.get_target(), *this);
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
// and force this canvas to be redrawn.
m_dirty = true;
}
@ -4857,7 +4898,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
float z = 0.0f;
const Vec3d& cur_pos = _mouse_to_3d(pos, &z);
Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z);
#if ENABLE_CONSTRAINED_CAMERA_TARGET
m_camera.set_target(m_camera.get_target() + orig - cur_pos, *this);
#else
m_camera.target += orig - cur_pos;
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
viewport_changed();
@ -4938,10 +4983,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
#if ENABLE_WORLD_ROTATIONS
_update_gizmos_data();
#endif // ENABLE_WORLD_ROTATIONS
wxGetApp().obj_manipul()->update_settings_value(m_selection);
// 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));
#if ENABLE_CONSTRAINED_CAMERA_TARGET
m_camera.set_scene_box(scene_bounding_box(), *this);
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
}
m_moving = false;
@ -5533,7 +5582,11 @@ void GLCanvas3D::_zoom_to_bounding_box(const BoundingBoxf3& bbox)
{
m_camera.zoom = zoom;
// center view around bounding box center
#if ENABLE_CONSTRAINED_CAMERA_TARGET
m_camera.set_target(bbox.center(), *this);
#else
m_camera.target = bbox.center();
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
viewport_changed();
@ -5655,7 +5708,12 @@ void GLCanvas3D::_camera_tranform() const
::glRotatef(-m_camera.get_theta(), 1.0f, 0.0f, 0.0f); // pitch
::glRotatef(m_camera.phi, 0.0f, 0.0f, 1.0f); // yaw
#if ENABLE_CONSTRAINED_CAMERA_TARGET
Vec3d target = -m_camera.get_target();
::glTranslated(target(0), target(1), target(2));
#else
::glTranslated(-m_camera.target(0), -m_camera.target(1), -m_camera.target(2));
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
}
void GLCanvas3D::_picking_pass() const
@ -5970,6 +6028,23 @@ void GLCanvas3D::_render_camera_target() const
::glLineWidth(2.0f);
::glBegin(GL_LINES);
#if ENABLE_CONSTRAINED_CAMERA_TARGET
const Vec3d& target = m_camera.get_target();
// draw line for x axis
::glColor3f(1.0f, 0.0f, 0.0f);
::glVertex3d(target(0) - half_length, target(1), target(2));
::glVertex3d(target(0) + half_length, target(1), target(2));
// draw line for y axis
::glColor3f(0.0f, 1.0f, 0.0f);
::glVertex3d(target(0), target(1) - half_length, target(2));
::glVertex3d(target(0), target(1) + half_length, target(2));
::glEnd();
::glBegin(GL_LINES);
::glColor3f(0.0f, 0.0f, 1.0f);
::glVertex3d(target(0), target(1), target(2) - half_length);
::glVertex3d(target(0), target(1), target(2) + half_length);
#else
// draw line for x axis
::glColor3f(1.0f, 0.0f, 0.0f);
::glVertex3d(m_camera.target(0) - half_length, m_camera.target(1), m_camera.target(2));
@ -5984,6 +6059,7 @@ void GLCanvas3D::_render_camera_target() const
::glColor3f(0.0f, 0.0f, 1.0f);
::glVertex3d(m_camera.target(0), m_camera.target(1), m_camera.target(2) - half_length);
::glVertex3d(m_camera.target(0), m_camera.target(1), m_camera.target(2) + half_length);
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
::glEnd();
}
#endif // ENABLE_SHOW_CAMERA_TARGET

View file

@ -153,9 +153,15 @@ class GLCanvas3D
float zoom;
float phi;
// float distance;
#if !ENABLE_CONSTRAINED_CAMERA_TARGET
Vec3d target;
#endif !// ENABLE_CONSTRAINED_CAMERA_TARGET
private:
#if ENABLE_CONSTRAINED_CAMERA_TARGET
Vec3d m_target;
BoundingBoxf3 m_scene_box;
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
float m_theta;
public:
@ -163,8 +169,16 @@ class GLCanvas3D
std::string get_type_as_string() const;
float get_theta() const;
float get_theta() const { return m_theta; }
void set_theta(float theta);
#if ENABLE_CONSTRAINED_CAMERA_TARGET
const Vec3d& get_target() const { return m_target; }
void set_target(const Vec3d& target, GLCanvas3D& canvas);
const BoundingBoxf3& get_scene_box() const { return m_scene_box; }
void set_scene_box(const BoundingBoxf3& box, GLCanvas3D& canvas);
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
};
class Bed
@ -782,7 +796,9 @@ private:
wxWindow *m_external_gizmo_widgets_parent;
#endif // not ENABLE_IMGUI
#if !ENABLE_CONSTRAINED_CAMERA_TARGET
void viewport_changed();
#endif // !ENABLE_CONSTRAINED_CAMERA_TARGET
public:
GLCanvas3D(wxGLCanvas* canvas);
@ -845,6 +861,9 @@ public:
float get_camera_zoom() const;
BoundingBoxf3 volumes_bounding_box() const;
#if ENABLE_CONSTRAINED_CAMERA_TARGET
BoundingBoxf3 scene_bounding_box() const;
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
bool is_layers_editing_enabled() const;
bool is_layers_editing_allowed() const;
@ -936,6 +955,10 @@ public:
void update_gizmos_on_off_state();
#if ENABLE_CONSTRAINED_CAMERA_TARGET
void viewport_changed();
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
private:
bool _is_shown_on_screen() const;
void _force_zoom_to_bed();

View file

@ -20,6 +20,7 @@
#include <wx/stattext.h>
#include <wx/debug.h>
#include "Tab.hpp"
#include "GUI.hpp"
#include "GUI_Utils.hpp"
#include "GUI_App.hpp"
@ -642,13 +643,13 @@ void GLGizmoRotate::transform_to_local() const
case X:
{
::glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
::glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
break;
}
case Y:
{
::glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
::glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
::glRotatef(-90.0f, 0.0f, 1.0f, 0.0f);
break;
}
default:
@ -670,14 +671,14 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) cons
{
case X:
{
m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitZ()));
m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitZ()));
m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitY()));
break;
}
case Y:
{
m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitZ()));
m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitX()));
m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitY()));
m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitZ()));
break;
}
default:
@ -769,6 +770,7 @@ void GLGizmoRotate3D::on_render(const GLCanvas3D::Selection& selection) const
#if ENABLE_IMGUI
void GLGizmoRotate3D::on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection)
{
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
Vec3d rotation(Geometry::rad2deg(m_gizmos[0].get_angle()), Geometry::rad2deg(m_gizmos[1].get_angle()), Geometry::rad2deg(m_gizmos[2].get_angle()));
wxString label = _(L("Rotation (deg)"));
@ -777,6 +779,7 @@ void GLGizmoRotate3D::on_render_input_window(float x, float y, const GLCanvas3D:
m_imgui->begin(label, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
m_imgui->input_vec3("", rotation, 100.0f, "%.2f");
m_imgui->end();
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
}
#endif // ENABLE_IMGUI
@ -1073,14 +1076,16 @@ void GLGizmoScale3D::on_render_for_picking(const GLCanvas3D::Selection& selectio
#if ENABLE_IMGUI
void GLGizmoScale3D::on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection)
{
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
bool single_instance = selection.is_single_full_instance();
wxString label = _(L("Scale (%)"));
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->set_next_window_bg_alpha(0.5f);
m_imgui->begin(label, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
m_imgui->input_vec3("", m_scale, 100.0f, "%.2f");
m_imgui->input_vec3("", m_scale * 100.f, 100.0f, "%.2f");
m_imgui->end();
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
}
#endif // ENABLE_IMGUI
@ -1320,6 +1325,7 @@ void GLGizmoMove3D::on_render_for_picking(const GLCanvas3D::Selection& selection
#if ENABLE_IMGUI
void GLGizmoMove3D::on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection)
{
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
bool show_position = selection.is_single_full_instance();
const Vec3d& position = selection.get_bounding_box().center();
@ -1332,6 +1338,7 @@ void GLGizmoMove3D::on_render_input_window(float x, float y, const GLCanvas3D::S
m_imgui->input_vec3("", displacement, 100.0f, "%.2f");
m_imgui->end();
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
}
#endif // ENABLE_IMGUI
@ -1732,7 +1739,9 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent)
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
::gluQuadricDrawStyle(m_quadric, GLU_FILL);
// using GLU_FILL does not work when the instance's transformation
// contains mirroring (normals are reverted)
::gluQuadricDrawStyle(m_quadric, GLU_SILHOUETTE);
#endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
}
@ -1780,8 +1789,7 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G
#else
void GLGizmoSlaSupports::set_model_object_ptr(ModelObject* model_object)
{
if (model_object != nullptr)
{
if (model_object != nullptr) {
m_starting_center = Vec3d::Zero();
m_model_object = model_object;
@ -1810,6 +1818,7 @@ void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const
Vec3d dragged_offset = selection.get_bounding_box().center() - m_starting_center;
#endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD
for (auto& g : m_grabbers) {
g.color[0] = 1.f;
g.color[1] = 0.f;
@ -1869,6 +1878,16 @@ void GLGizmoSlaSupports::render_grabbers(const GLCanvas3D::Selection& selection,
float render_color[3];
for (int i = 0; i < (int)m_grabbers.size(); ++i)
{
// first precalculate the grabber position in world coordinates, so that the grabber
// is not scaled with the object (as it would be if rendered with current gl matrix).
Eigen::Matrix<GLfloat, 4, 4> glmatrix;
glGetFloatv (GL_MODELVIEW_MATRIX, glmatrix.data());
Eigen::Matrix<float, 4, 1> grabber_pos;
for (int j=0; j<3; ++j)
grabber_pos(j) = m_grabbers[i].center(j);
grabber_pos[3] = 1.f;
Eigen::Matrix<float, 4, 1> grabber_world_position = glmatrix * grabber_pos;
if (!picking && (m_hover_id == i))
{
render_color[0] = 1.0f - m_grabbers[i].color[0];
@ -1880,8 +1899,10 @@ void GLGizmoSlaSupports::render_grabbers(const GLCanvas3D::Selection& selection,
::glColor3fv(render_color);
::glPushMatrix();
::glTranslated(m_grabbers[i].center(0), m_grabbers[i].center(1), m_grabbers[i].center(2));
::gluSphere(m_quadric, 0.75, 36, 18);
::glLoadIdentity();
::glTranslated(grabber_world_position(0), grabber_world_position(1), grabber_world_position(2) + z_shift);
::gluQuadricDrawStyle(m_quadric, GLU_SILHOUETTE);
::gluSphere(m_quadric, 0.75, 64, 36);
::glPopMatrix();
}
@ -1930,7 +1951,7 @@ void GLGizmoSlaSupports::render_grabbers(bool picking) const
GLUquadricObj *quadric;
quadric = ::gluNewQuadric();
::gluQuadricDrawStyle(quadric, GLU_FILL );
::gluSphere( quadric , 0.75f, 36 , 18 );
::gluSphere( quadric , 0.75f, 64 , 32 );
::gluDeleteQuadric(quadric);
::glPopMatrix();
if (!picking)
@ -1989,6 +2010,7 @@ void GLGizmoSlaSupports::update_mesh()
// we'll now reload Grabbers (selection might have changed):
m_grabbers.clear();
for (const Vec3f& point : m_model_object->sla_support_points) {
m_grabbers.push_back(Grabber());
m_grabbers.back().center = point.cast<double>();
@ -2080,7 +2102,6 @@ void GLGizmoSlaSupports::delete_current_grabber(bool delete_all)
if (delete_all) {
m_grabbers.clear();
m_model_object->sla_support_points.clear();
m_parent.reload_scene(true); // in case this was called from ImGui overlay dialog, the refresh would be delayed
// This should trigger the support generation
// wxGetApp().plater()->reslice();
@ -2156,12 +2177,34 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, const GLCanvas
m_imgui->text(_(L("Right mouse click - remove point")));
m_imgui->text(" ");
bool remove_all_clicked = m_imgui->button(_(L("Remove all points")));
bool generate = m_imgui->button(_(L("Generate points automatically")));
bool remove_all_clicked = m_imgui->button(_(L("Remove all points")) + (m_model_object == nullptr ? "" : " (" + std::to_string(m_model_object->sla_support_points.size())+")"));
m_imgui->end();
if (remove_all_clicked)
delete_current_grabber(true);
if (generate) {
const DynamicPrintConfig& cfg = *wxGetApp().get_tab(Preset::TYPE_SLA_PRINT)->get_config();
SLAAutoSupports::Config config;
config.density_at_horizontal = cfg.opt_int("support_density_at_horizontal") / 10000.f;
config.density_at_45 = cfg.opt_int("support_density_at_45") / 10000.f;
config.minimal_z = cfg.opt_float("support_minimal_z");
SLAAutoSupports sas(*m_model_object, config);
sas.generate();
m_grabbers.clear();
for (const Vec3f& point : m_model_object->sla_support_points) {
m_grabbers.push_back(Grabber());
m_grabbers.back().center = point.cast<double>();
}
}
if (remove_all_clicked || generate) {
m_parent.reload_scene(true);
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
}
#endif // ENABLE_IMGUI
@ -2177,6 +2220,7 @@ bool GLGizmoSlaSupports::on_is_selectable() const
}
std::string GLGizmoSlaSupports::on_get_name() const
{
return L("SLA Support Points");
}

View file

@ -5,8 +5,10 @@
#include "../../slic3r/GUI/GLTexture.hpp"
#include "../../slic3r/GUI/GLCanvas3D.hpp"
#include "libslic3r/Point.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/SLA/SLAAutoSupports.hpp"
#include <array>
#include <vector>
@ -434,6 +436,7 @@ protected:
class GLGizmoSlaSupports : public GLGizmoBase
{
private:
SLAAutoSupports* m_sas = nullptr;
ModelObject* m_model_object = nullptr;
#if ENABLE_SLA_SUPPORT_GIZMO_MOD
ModelObject* m_old_model_object = nullptr;

View file

@ -733,7 +733,7 @@ void Sidebar::show_info_sizer()
auto& stats = model_object->volumes.front()->mesh.stl.stats;
auto sf = model_instance->get_scaling_factor();
p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume * sf(0) * sf(1) * sf(2)));
p->object_info->info_volume->SetLabel(wxString::Format("%.2f", size(0) * size(1) * size(2) * sf(0) * sf(1) * sf(2)));
p->object_info->info_facets->SetLabel(wxString::Format(_(L("%d (%d shells)")), static_cast<int>(model_object->facets_count()), stats.number_of_parts));
int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
@ -914,7 +914,7 @@ struct Plater::priv
wxMenu sla_object_menu;
// Data
Slic3r::DynamicPrintConfig *config;
Slic3r::DynamicPrintConfig *config; // FIXME: leak?
Slic3r::Print fff_print;
Slic3r::SLAPrint sla_print;
Slic3r::Model model;
@ -1010,7 +1010,6 @@ struct Plater::priv
unsigned int update_background_process();
void async_apply_config();
void reload_from_disk();
void export_object_stl();
void fix_through_netfabb(const int obj_idx);
#if ENABLE_REMOVE_TABS_FROM_PLATER
@ -2097,12 +2096,33 @@ void Plater::priv::update_sla_scene()
void Plater::priv::reload_from_disk()
{
// TODO
}
const auto &selection = get_selection();
const auto obj_orig_idx = selection.get_object_idx();
if (selection.is_wipe_tower() || obj_orig_idx == -1) { return; }
void Plater::priv::export_object_stl()
{
// TODO
auto *object_orig = model.objects[obj_orig_idx];
std::vector<fs::path> input_paths(1, object_orig->input_file);
const auto new_idxs = load_files(input_paths, true, false);
for (const auto idx : new_idxs) {
ModelObject *object = model.objects[idx];
object->clear_instances();
for (const ModelInstance *instance : object_orig->instances) {
object->add_instance(*instance);
}
if (object->volumes.size() == object_orig->volumes.size()) {
for (size_t i = 0; i < object->volumes.size(); i++) {
object->volumes[i]->config.apply(object_orig->volumes[i]->config);
}
}
// XXX: Restore more: layer_height_ranges, layer_height_profile, layer_height_profile_valid (?)
}
remove(obj_orig_idx);
}
void Plater::priv::fix_through_netfabb(const int obj_idx)
@ -2524,6 +2544,12 @@ bool Plater::priv::complit_init_object_menu()
wxMenuItem* item_split = append_submenu(&object_menu, split_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object")), "shape_ungroup.png");
append_menu_item(&object_menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")),
[this](wxCommandEvent&) { reload_from_disk(); });
append_menu_item(&object_menu, wxID_ANY, _(L("Export object as STL…")), _(L("Export this single object as STL file")),
[this](wxCommandEvent&) { q->export_stl(true); });
// Append "Add..." popupmenu
object_menu.AppendSeparator();
sidebar->obj_list()->append_menu_items_add_volume(&object_menu);
@ -2932,7 +2958,7 @@ void Plater::export_gcode(fs::path output_path)
}
}
void Plater::export_stl()
void Plater::export_stl(bool selection_only)
{
if (p->model.objects.empty()) { return; }
@ -2942,7 +2968,19 @@ void Plater::export_stl()
// Store a binary STL
wxString path = dialog->GetPath();
auto path_cstr = path.c_str();
auto mesh = p->model.mesh();
TriangleMesh mesh;
if (selection_only) {
const auto &selection = p->get_selection();
if (selection.is_wipe_tower()) { return; }
const auto obj_idx = selection.get_object_idx();
if (obj_idx == -1) { return; }
mesh = p->model.objects[obj_idx]->mesh();
} else {
auto mesh = p->model.mesh();
}
Slic3r::store_stl(path_cstr, &mesh, true);
p->statusbar()->set_status_text(wxString::Format(_(L("STL file exported to %s")), path));
}

View file

@ -146,7 +146,7 @@ public:
// Note: empty path means "use the default"
void export_gcode(boost::filesystem::path output_path = boost::filesystem::path());
void export_stl();
void export_stl(bool selection_only = false);
void export_amf();
void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
void reslice();

View file

@ -403,6 +403,9 @@ const std::vector<std::string>& Preset::sla_print_options()
"support_critical_angle",
"support_max_bridge_length",
"support_object_elevation",
"support_density_at_horizontal",
"support_density_at_45",
"support_minimal_z",
"pad_enable",
"pad_wall_thickness",
"pad_wall_height",

View file

@ -3112,6 +3112,11 @@ void TabSLAPrint::build()
optgroup->append_single_option_line("support_critical_angle");
optgroup->append_single_option_line("support_max_bridge_length");
optgroup = page->new_optgroup(_(L("Automatic generation")));
optgroup->append_single_option_line("support_density_at_horizontal");
optgroup->append_single_option_line("support_density_at_45");
optgroup->append_single_option_line("support_minimal_z");
page = add_options_page(_(L("Pad")), "brick.png");
optgroup = page->new_optgroup(_(L("Pad")));
optgroup->append_single_option_line("pad_enable");