Merge remote-tracking branch 'origin/master' into ys_buttons
This commit is contained in:
commit
247b70395b
22 changed files with 363 additions and 123 deletions
|
@ -1,11 +1,12 @@
|
||||||
#version 110
|
#version 110
|
||||||
|
|
||||||
|
attribute vec4 v_position;
|
||||||
attribute vec2 v_tex_coords;
|
attribute vec2 v_tex_coords;
|
||||||
|
|
||||||
varying vec2 tex_coords;
|
varying vec2 tex_coords;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = ftransform();
|
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * v_position;
|
||||||
tex_coords = v_tex_coords;
|
tex_coords = v_tex_coords;
|
||||||
}
|
}
|
|
@ -2488,6 +2488,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
// adds analyzer tags and updates analyzer's tracking data
|
// adds analyzer tags and updates analyzer's tracking data
|
||||||
if (m_enable_analyzer)
|
if (m_enable_analyzer)
|
||||||
{
|
{
|
||||||
|
// PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width
|
||||||
|
// so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines
|
||||||
|
bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower);
|
||||||
|
|
||||||
if (path.role() != m_last_analyzer_extrusion_role)
|
if (path.role() != m_last_analyzer_extrusion_role)
|
||||||
{
|
{
|
||||||
m_last_analyzer_extrusion_role = path.role();
|
m_last_analyzer_extrusion_role = path.role();
|
||||||
|
@ -2505,7 +2509,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
gcode += buf;
|
gcode += buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_last_width != path.width)
|
if (last_was_wipe_tower || (m_last_width != path.width))
|
||||||
{
|
{
|
||||||
m_last_width = path.width;
|
m_last_width = path.width;
|
||||||
|
|
||||||
|
@ -2514,7 +2518,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
gcode += buf;
|
gcode += buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_last_height != path.height)
|
if (last_was_wipe_tower || (m_last_height != path.height))
|
||||||
{
|
{
|
||||||
m_last_height = path.height;
|
m_last_height = path.height;
|
||||||
|
|
||||||
|
|
|
@ -242,6 +242,7 @@ public:
|
||||||
|
|
||||||
void set_scaling_factor(const Vec3d& scaling_factor);
|
void set_scaling_factor(const Vec3d& scaling_factor);
|
||||||
void set_scaling_factor(Axis axis, double scaling_factor);
|
void set_scaling_factor(Axis axis, double scaling_factor);
|
||||||
|
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
|
||||||
|
|
||||||
const Vec3d& get_mirror() const { return m_mirror; }
|
const Vec3d& get_mirror() const { return m_mirror; }
|
||||||
double get_mirror(Axis axis) const { return m_mirror(axis); }
|
double get_mirror(Axis axis) const { return m_mirror(axis); }
|
||||||
|
|
|
@ -592,6 +592,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
||||||
this->input_file = rhs.input_file;
|
this->input_file = rhs.input_file;
|
||||||
this->config = rhs.config;
|
this->config = rhs.config;
|
||||||
this->sla_support_points = rhs.sla_support_points;
|
this->sla_support_points = rhs.sla_support_points;
|
||||||
|
this->sla_points_status = rhs.sla_points_status;
|
||||||
this->layer_height_ranges = rhs.layer_height_ranges;
|
this->layer_height_ranges = rhs.layer_height_ranges;
|
||||||
this->layer_height_profile = rhs.layer_height_profile;
|
this->layer_height_profile = rhs.layer_height_profile;
|
||||||
this->origin_translation = rhs.origin_translation;
|
this->origin_translation = rhs.origin_translation;
|
||||||
|
@ -625,6 +626,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||||
this->input_file = std::move(rhs.input_file);
|
this->input_file = std::move(rhs.input_file);
|
||||||
this->config = std::move(rhs.config);
|
this->config = std::move(rhs.config);
|
||||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||||
|
this->sla_points_status = std::move(rhs.sla_points_status);
|
||||||
this->layer_height_ranges = std::move(rhs.layer_height_ranges);
|
this->layer_height_ranges = std::move(rhs.layer_height_ranges);
|
||||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||||
this->origin_translation = std::move(rhs.origin_translation);
|
this->origin_translation = std::move(rhs.origin_translation);
|
||||||
|
@ -1130,6 +1132,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||||
if (keep_upper) {
|
if (keep_upper) {
|
||||||
upper->set_model(nullptr);
|
upper->set_model(nullptr);
|
||||||
upper->sla_support_points.clear();
|
upper->sla_support_points.clear();
|
||||||
|
upper->sla_points_status = sla::PointsStatus::None;
|
||||||
upper->clear_volumes();
|
upper->clear_volumes();
|
||||||
upper->input_file = "";
|
upper->input_file = "";
|
||||||
}
|
}
|
||||||
|
@ -1137,6 +1140,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||||
if (keep_lower) {
|
if (keep_lower) {
|
||||||
lower->set_model(nullptr);
|
lower->set_model(nullptr);
|
||||||
lower->sla_support_points.clear();
|
lower->sla_support_points.clear();
|
||||||
|
lower->sla_points_status = sla::PointsStatus::None;
|
||||||
lower->clear_volumes();
|
lower->clear_volumes();
|
||||||
lower->input_file = "";
|
lower->input_file = "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,6 +180,9 @@ public:
|
||||||
// saved in mesh coordinates to allow using them for several instances.
|
// saved in mesh coordinates to allow using them for several instances.
|
||||||
// The format is (x, y, z, point_size, supports_island)
|
// The format is (x, y, z, point_size, supports_island)
|
||||||
std::vector<sla::SupportPoint> sla_support_points;
|
std::vector<sla::SupportPoint> sla_support_points;
|
||||||
|
// To keep track of where the points came from (used for synchronization between
|
||||||
|
// the SLA gizmo and the backend).
|
||||||
|
sla::PointsStatus sla_points_status = sla::PointsStatus::None;
|
||||||
|
|
||||||
/* This vector accumulates the total translation applied to the object by the
|
/* This vector accumulates the total translation applied to the object by the
|
||||||
center_around_origin() method. Callers might want to apply the same translation
|
center_around_origin() method. Callers might want to apply the same translation
|
||||||
|
|
|
@ -15,6 +15,14 @@ class TriangleMesh;
|
||||||
|
|
||||||
namespace sla {
|
namespace sla {
|
||||||
|
|
||||||
|
// An enum to keep track of where the current points on the ModelObject came from.
|
||||||
|
enum class PointsStatus {
|
||||||
|
None, // No points were generated so far.
|
||||||
|
Generating, // The autogeneration algorithm triggered, but not yet finished.
|
||||||
|
AutoGenerated, // Points were autogenerated (i.e. copied from the backend).
|
||||||
|
UserModified // User has done some edits.
|
||||||
|
};
|
||||||
|
|
||||||
struct SupportPoint {
|
struct SupportPoint {
|
||||||
Vec3f pos;
|
Vec3f pos;
|
||||||
float head_front_radius;
|
float head_front_radius;
|
||||||
|
|
|
@ -342,6 +342,17 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
||||||
if (it_print_object_status != print_object_status.end())
|
if (it_print_object_status != print_object_status.end())
|
||||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||||
}
|
}
|
||||||
|
if (model_object.sla_points_status != model_object_new.sla_points_status) {
|
||||||
|
// Change of this status should invalidate support points. The points themselves are not enough, there are none
|
||||||
|
// in case that nothing was generated OR that points were autogenerated already and not copied to the front-end.
|
||||||
|
// These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT
|
||||||
|
// invalidate - that would keep stopping the background processing without a reason.
|
||||||
|
if (model_object.sla_points_status != sla::PointsStatus::Generating)
|
||||||
|
if (it_print_object_status != print_object_status.end())
|
||||||
|
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||||
|
model_object.sla_points_status = model_object_new.sla_points_status;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
|
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
|
||||||
model_object.name = model_object_new.name;
|
model_object.name = model_object_new.name;
|
||||||
model_object.input_file = model_object_new.input_file;
|
model_object.input_file = model_object_new.input_file;
|
||||||
|
@ -630,10 +641,11 @@ void SLAPrint::process()
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Support point count "
|
BOOST_LOG_TRIVIAL(debug) << "Support point count "
|
||||||
<< mo.sla_support_points.size();
|
<< mo.sla_support_points.size();
|
||||||
|
|
||||||
// If there are no points on the front-end, we will do the
|
// Unless the user modified the points or we already did the calculation, we will do
|
||||||
// autoplacement. Otherwise we will just blindly copy the frontend data
|
// the autoplacement. Otherwise we will just blindly copy the frontend data
|
||||||
// into the backend cache.
|
// into the backend cache.
|
||||||
if(mo.sla_support_points.empty()) {
|
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
|
||||||
|
|
||||||
// calculate heights of slices (slices are calculated already)
|
// calculate heights of slices (slices are calculated already)
|
||||||
double lh = po.m_config.layer_height.getFloat();
|
double lh = po.m_config.layer_height.getFloat();
|
||||||
|
|
||||||
|
@ -645,7 +657,9 @@ void SLAPrint::process()
|
||||||
this->throw_if_canceled();
|
this->throw_if_canceled();
|
||||||
SLAAutoSupports::Config config;
|
SLAAutoSupports::Config config;
|
||||||
const SLAPrintObjectConfig& cfg = po.config();
|
const SLAPrintObjectConfig& cfg = po.config();
|
||||||
config.density_relative = float(cfg.support_points_density_relative / 100.f); // the config value is in percents
|
|
||||||
|
// the density config value is in percents:
|
||||||
|
config.density_relative = float(cfg.support_points_density_relative / 100.f);
|
||||||
config.minimal_distance = float(cfg.support_points_minimal_distance);
|
config.minimal_distance = float(cfg.support_points_minimal_distance);
|
||||||
|
|
||||||
// Construction of this object does the calculation.
|
// Construction of this object does the calculation.
|
||||||
|
@ -669,7 +683,7 @@ void SLAPrint::process()
|
||||||
report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
|
report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// There are some points on the front-end, no calculation will be done.
|
// There are either some points on the front-end, or the user removed them on purpose. No calculation will be done.
|
||||||
po.m_supportdata->support_points = po.transformed_support_points();
|
po.m_supportdata->support_points = po.transformed_support_points();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -516,9 +516,9 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const
|
||||||
|
|
||||||
if (max_anisotropy > 0.0f)
|
if (max_anisotropy > 0.0f)
|
||||||
{
|
{
|
||||||
::glBindTexture(GL_TEXTURE_2D, m_texture.get_id());
|
glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.get_id()));
|
||||||
::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
|
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
|
||||||
::glBindTexture(GL_TEXTURE_2D, 0);
|
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,9 +542,9 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const
|
||||||
|
|
||||||
if (!m_model.get_filename().empty())
|
if (!m_model.get_filename().empty())
|
||||||
{
|
{
|
||||||
::glEnable(GL_LIGHTING);
|
glsafe(::glEnable(GL_LIGHTING));
|
||||||
m_model.render();
|
m_model.render();
|
||||||
::glDisable(GL_LIGHTING);
|
glsafe(::glDisable(GL_LIGHTING));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -553,39 +553,32 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const
|
||||||
{
|
{
|
||||||
if (m_vbo_id == 0)
|
if (m_vbo_id == 0)
|
||||||
{
|
{
|
||||||
::glGenBuffers(1, &m_vbo_id);
|
glsafe(::glGenBuffers(1, &m_vbo_id));
|
||||||
::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||||
::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW);
|
glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW));
|
||||||
::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_position_offset());
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_tex_coords_offset());
|
|
||||||
::glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::glEnable(GL_DEPTH_TEST);
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
::glDepthMask(GL_FALSE);
|
glsafe(::glDepthMask(GL_FALSE));
|
||||||
|
|
||||||
::glEnable(GL_BLEND);
|
glsafe(::glEnable(GL_BLEND));
|
||||||
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||||
|
|
||||||
::glEnable(GL_TEXTURE_2D);
|
|
||||||
::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
|
|
||||||
if (bottom)
|
if (bottom)
|
||||||
::glFrontFace(GL_CW);
|
glsafe(::glFrontFace(GL_CW));
|
||||||
|
|
||||||
render_prusa_shader(triangles_vcount, bottom);
|
render_prusa_shader(bottom);
|
||||||
|
|
||||||
if (bottom)
|
if (bottom)
|
||||||
::glFrontFace(GL_CCW);
|
glsafe(::glFrontFace(GL_CCW));
|
||||||
|
|
||||||
::glDisable(GL_TEXTURE_2D);
|
glsafe(::glDisable(GL_BLEND));
|
||||||
|
glsafe(::glDepthMask(GL_TRUE));
|
||||||
::glDisable(GL_BLEND);
|
|
||||||
::glDepthMask(GL_TRUE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::render_prusa_shader(unsigned int vertices_count, bool transparent) const
|
void Bed3D::render_prusa_shader(bool transparent) const
|
||||||
{
|
{
|
||||||
if (m_shader.get_shader_program_id() == 0)
|
if (m_shader.get_shader_program_id() == 0)
|
||||||
m_shader.init("printbed.vs", "printbed.fs");
|
m_shader.init("printbed.vs", "printbed.fs");
|
||||||
|
@ -595,15 +588,35 @@ void Bed3D::render_prusa_shader(unsigned int vertices_count, bool transparent) c
|
||||||
m_shader.start_using();
|
m_shader.start_using();
|
||||||
m_shader.set_uniform("transparent_background", transparent);
|
m_shader.set_uniform("transparent_background", transparent);
|
||||||
|
|
||||||
::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id());
|
unsigned int stride = m_triangles.get_vertex_data_size();
|
||||||
::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
|
|
||||||
::glEnableVertexAttribArray(0);
|
GLint position_id = m_shader.get_attrib_location("v_position");
|
||||||
::glEnableVertexAttribArray(1);
|
GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords");
|
||||||
::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertices_count);
|
|
||||||
::glDisableVertexAttribArray(1);
|
glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id()));
|
||||||
::glDisableVertexAttribArray(0);
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||||
::glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
::glBindTexture(GL_TEXTURE_2D, 0);
|
if (position_id != -1)
|
||||||
|
{
|
||||||
|
glsafe(::glEnableVertexAttribArray(position_id));
|
||||||
|
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset()));
|
||||||
|
}
|
||||||
|
if (tex_coords_id != -1)
|
||||||
|
{
|
||||||
|
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
||||||
|
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
|
||||||
|
|
||||||
|
if (tex_coords_id != -1)
|
||||||
|
glsafe(::glDisableVertexAttribArray(tex_coords_id));
|
||||||
|
|
||||||
|
if (position_id != -1)
|
||||||
|
glsafe(::glDisableVertexAttribArray(position_id));
|
||||||
|
|
||||||
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||||
|
|
||||||
m_shader.stop_using();
|
m_shader.stop_using();
|
||||||
}
|
}
|
||||||
|
@ -754,7 +767,7 @@ void Bed3D::render_custom() const
|
||||||
glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f));
|
glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f));
|
||||||
glsafe(::glNormal3d(0.0f, 0.0f, 1.0f));
|
glsafe(::glNormal3d(0.0f, 0.0f, 1.0f));
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
#if ENABLE_TEXTURES_FROM_SVG
|
||||||
::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data());
|
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data()));
|
||||||
#else
|
#else
|
||||||
glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()));
|
glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()));
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||||
|
@ -768,7 +781,7 @@ void Bed3D::render_custom() const
|
||||||
glsafe(::glLineWidth(3.0f * m_scale_factor));
|
glsafe(::glLineWidth(3.0f * m_scale_factor));
|
||||||
glsafe(::glColor4f(0.2f, 0.2f, 0.2f, 0.4f));
|
glsafe(::glColor4f(0.2f, 0.2f, 0.2f, 0.4f));
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
#if ENABLE_TEXTURES_FROM_SVG
|
||||||
::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data());
|
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data()));
|
||||||
#else
|
#else
|
||||||
glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_vertices()));
|
glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_vertices()));
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||||
|
@ -786,7 +799,7 @@ void Bed3D::reset()
|
||||||
{
|
{
|
||||||
if (m_vbo_id > 0)
|
if (m_vbo_id > 0)
|
||||||
{
|
{
|
||||||
::glDeleteBuffers(1, &m_vbo_id);
|
glsafe(::glDeleteBuffers(1, &m_vbo_id));
|
||||||
m_vbo_id = 0;
|
m_vbo_id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ private:
|
||||||
EType detect_type(const Pointfs& shape) const;
|
EType detect_type(const Pointfs& shape) const;
|
||||||
#if ENABLE_TEXTURES_FROM_SVG
|
#if ENABLE_TEXTURES_FROM_SVG
|
||||||
void render_prusa(const std::string& key, bool bottom) const;
|
void render_prusa(const std::string& key, bool bottom) const;
|
||||||
void render_prusa_shader(unsigned int vertices_count, bool transparent) const;
|
void render_prusa_shader(bool transparent) const;
|
||||||
#else
|
#else
|
||||||
void render_prusa(const std::string &key, float theta, bool useVBOs) const;
|
void render_prusa(const std::string &key, float theta, bool useVBOs) const;
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||||
|
|
|
@ -896,8 +896,7 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio
|
||||||
if (needs_reset)
|
if (needs_reset)
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
if (volume->is_modifier)
|
m_mode = volume->is_modifier ? Volume : Instance;
|
||||||
m_mode = Volume;
|
|
||||||
|
|
||||||
switch (m_mode)
|
switch (m_mode)
|
||||||
{
|
{
|
||||||
|
@ -1261,17 +1260,21 @@ static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to
|
||||||
return (axis.z() < 0) ? -angle : angle;
|
return (axis.z() < 0) ? -angle : angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
|
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
|
||||||
|
void GLCanvas3D::Selection::rotate(const Vec3d& rotation, GLCanvas3D::TransformationType transformation_type)
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Only relative rotation values are allowed in the world coordinate system.
|
||||||
|
assert(! transformation_type.world() || transformation_type.relative());
|
||||||
|
|
||||||
int rot_axis_max;
|
int rot_axis_max;
|
||||||
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
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.
|
// 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);
|
std::vector<int> object_instance_first(m_model->objects.size(), -1);
|
||||||
auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) {
|
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()];
|
int first_volume_idx = object_instance_first[volume.object_idx()];
|
||||||
if (rot_axis_max != 2 && first_volume_idx != -1) {
|
if (rot_axis_max != 2 && first_volume_idx != -1) {
|
||||||
// Generic rotation, but no rotation around the Z axis.
|
// Generic rotation, but no rotation around the Z axis.
|
||||||
|
@ -1283,11 +1286,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
|
||||||
volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
|
volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
|
||||||
} else {
|
} else {
|
||||||
// extracts rotations from the composed transformation
|
// extracts rotations from the composed transformation
|
||||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
Vec3d new_rotation = transformation_type.world() ?
|
||||||
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix());
|
Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) :
|
||||||
if (rot_axis_max == 2 && !local)
|
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.
|
// Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
|
||||||
volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
double z_diff = rotation_diff_z(new_rotation, m_cache.volumes_data[i].get_instance_rotation());
|
||||||
|
volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||||
|
}
|
||||||
volume.set_instance_rotation(new_rotation);
|
volume.set_instance_rotation(new_rotation);
|
||||||
object_instance_first[volume.object_idx()] = i;
|
object_instance_first[volume.object_idx()] = i;
|
||||||
}
|
}
|
||||||
|
@ -1300,7 +1306,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
|
||||||
rotate_instance(volume, i);
|
rotate_instance(volume, i);
|
||||||
else if (is_single_volume() || is_single_modifier())
|
else if (is_single_volume() || is_single_modifier())
|
||||||
{
|
{
|
||||||
if (local)
|
if (transformation_type.independent())
|
||||||
volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
|
volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1318,7 +1324,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
|
||||||
// extracts rotations from the composed transformation
|
// extracts rotations from the composed transformation
|
||||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
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());
|
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||||
if (!local)
|
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);
|
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
|
||||||
volume.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);
|
||||||
|
@ -5181,7 +5187,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
case Gizmos::Rotate:
|
case Gizmos::Rotate:
|
||||||
{
|
{
|
||||||
// Apply new temporary rotations
|
// Apply new temporary rotations
|
||||||
m_selection.rotate(m_gizmos.get_rotation(), evt.AltDown());
|
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||||
|
if (evt.AltDown())
|
||||||
|
transformation_type.set_independent();
|
||||||
|
m_selection.rotate(m_gizmos.get_rotation(), transformation_type);
|
||||||
wxGetApp().obj_manipul()->update_settings_value(m_selection);
|
wxGetApp().obj_manipul()->update_settings_value(m_selection);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,6 +375,59 @@ class GLCanvas3D
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
class TransformationType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Enum {
|
||||||
|
// Transforming in a world coordinate system
|
||||||
|
World = 0,
|
||||||
|
// Transforming in a local coordinate system
|
||||||
|
Local = 1,
|
||||||
|
// Absolute transformations, allowed in local coordinate system only.
|
||||||
|
Absolute = 0,
|
||||||
|
// Relative transformations, allowed in both local and world coordinate system.
|
||||||
|
Relative = 2,
|
||||||
|
// For group selection, the transformation is performed as if the group made a single solid body.
|
||||||
|
Joint = 0,
|
||||||
|
// For group selection, the transformation is performed on each object independently.
|
||||||
|
Independent = 4,
|
||||||
|
|
||||||
|
World_Relative_Joint = World | Relative | Joint,
|
||||||
|
World_Relative_Independent = World | Relative | Independent,
|
||||||
|
Local_Absolute_Joint = Local | Absolute | Joint,
|
||||||
|
Local_Absolute_Independent = Local | Absolute | Independent,
|
||||||
|
Local_Relative_Joint = Local | Relative | Joint,
|
||||||
|
Local_Relative_Independent = Local | Relative | Independent,
|
||||||
|
};
|
||||||
|
|
||||||
|
TransformationType() : m_value(World) {}
|
||||||
|
TransformationType(Enum value) : m_value(value) {}
|
||||||
|
TransformationType& operator=(Enum value) { m_value = value; return *this; }
|
||||||
|
|
||||||
|
Enum operator()() const { return m_value; }
|
||||||
|
bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; }
|
||||||
|
|
||||||
|
void set_world() { this->remove(Local); }
|
||||||
|
void set_local() { this->add(Local); }
|
||||||
|
void set_absolute() { this->remove(Relative); }
|
||||||
|
void set_relative() { this->add(Relative); }
|
||||||
|
void set_joint() { this->remove(Independent); }
|
||||||
|
void set_independent() { this->add(Independent); }
|
||||||
|
|
||||||
|
bool world() const { return ! this->has(Local); }
|
||||||
|
bool local() const { return this->has(Local); }
|
||||||
|
bool absolute() const { return ! this->has(Relative); }
|
||||||
|
bool relative() const { return this->has(Relative); }
|
||||||
|
bool joint() const { return ! this->has(Independent); }
|
||||||
|
bool independent() const { return this->has(Independent); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); }
|
||||||
|
void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); }
|
||||||
|
|
||||||
|
Enum m_value;
|
||||||
|
};
|
||||||
|
|
||||||
class Selection
|
class Selection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -553,7 +606,7 @@ public:
|
||||||
void start_dragging();
|
void start_dragging();
|
||||||
|
|
||||||
void translate(const Vec3d& displacement, bool local = false);
|
void translate(const Vec3d& displacement, bool local = false);
|
||||||
void rotate(const Vec3d& rotation, bool local);
|
void rotate(const Vec3d& rotation, TransformationType transformation_type);
|
||||||
void flattening_rotate(const Vec3d& normal);
|
void flattening_rotate(const Vec3d& normal);
|
||||||
void scale(const Vec3d& scale, bool local);
|
void scale(const Vec3d& scale, bool local);
|
||||||
void mirror(Axis axis);
|
void mirror(Axis axis);
|
||||||
|
|
|
@ -1789,12 +1789,12 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G
|
||||||
if (is_mesh_update_necessary())
|
if (is_mesh_update_necessary())
|
||||||
update_mesh();
|
update_mesh();
|
||||||
|
|
||||||
// If there are no points, let's ask the backend if it calculated some.
|
|
||||||
if (m_editing_mode_cache.empty())
|
|
||||||
get_data_from_backend();
|
|
||||||
|
|
||||||
if (m_model_object != m_old_model_object)
|
if (m_model_object != m_old_model_object)
|
||||||
m_editing_mode = false;
|
m_editing_mode = false;
|
||||||
|
|
||||||
|
if (m_editing_mode_cache.empty() && m_model_object->sla_points_status != sla::PointsStatus::UserModified)
|
||||||
|
get_data_from_backend();
|
||||||
|
|
||||||
if (m_state == On) {
|
if (m_state == On) {
|
||||||
m_parent.toggle_model_objects_visibility(false);
|
m_parent.toggle_model_objects_visibility(false);
|
||||||
m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
|
m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
|
||||||
|
@ -2296,8 +2296,7 @@ RENDER_AGAIN:
|
||||||
|
|
||||||
m_imgui->text(" "); // vertical gap
|
m_imgui->text(" "); // vertical gap
|
||||||
|
|
||||||
bool apply_changes = m_imgui->button(_(L("Apply changes")));
|
if (m_imgui->button(_(L("Apply changes")))) {
|
||||||
if (apply_changes) {
|
|
||||||
editing_mode_apply_changes();
|
editing_mode_apply_changes();
|
||||||
force_refresh = true;
|
force_refresh = true;
|
||||||
}
|
}
|
||||||
|
@ -2308,24 +2307,28 @@ RENDER_AGAIN:
|
||||||
force_refresh = true;
|
force_refresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else { // not in editing mode:
|
||||||
/* ImGui::PushItemWidth(50.0f);
|
/*ImGui::PushItemWidth(100.0f);
|
||||||
m_imgui->text(_(L("Minimal points distance: ")));
|
m_imgui->text(_(L("Minimal points distance: ")));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
bool value_changed = ImGui::InputDouble("mm", &m_minimal_point_distance, 0.0f, 0.0f, "%.2f");
|
bool value_changed = ImGui::SliderFloat("", &m_minimal_point_distance, 0.f, 20.f, "%.f mm");
|
||||||
m_imgui->text(_(L("Support points density: ")));
|
m_imgui->text(_(L("Support points density: ")));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
value_changed |= ImGui::InputDouble("%", &m_density, 0.0f, 0.0f, "%.f");*/
|
value_changed |= ImGui::SliderFloat(" ", &m_density, 0.f, 200.f, "%.f %%");*/
|
||||||
|
|
||||||
bool generate = m_imgui->button(_(L("Auto-generate points [A]")));
|
bool generate = m_imgui->button(_(L("Auto-generate points [A]")));
|
||||||
|
|
||||||
if (generate)
|
if (generate)
|
||||||
auto_generate();
|
auto_generate();
|
||||||
|
|
||||||
m_imgui->text("");
|
|
||||||
m_imgui->text("");
|
m_imgui->text("");
|
||||||
if (m_imgui->button(_(L("Manual editing [M]"))))
|
if (m_imgui->button(_(L("Manual editing [M]"))))
|
||||||
switch_to_editing_mode();
|
switch_to_editing_mode();
|
||||||
|
|
||||||
|
m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? "No points (will be autogenerated)" :
|
||||||
|
(m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? "Autogenerated points (no modifications)" :
|
||||||
|
(m_model_object->sla_points_status == sla::PointsStatus::UserModified ? "User-modified points" :
|
||||||
|
(m_model_object->sla_points_status == sla::PointsStatus::Generating ? "Generation in progress..." : "UNKNOWN STATUS"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_imgui->end();
|
m_imgui->end();
|
||||||
|
@ -2448,17 +2451,19 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
|
||||||
// If there are no changes, don't touch the front-end. The data in the cache could have been
|
// If there are no changes, don't touch the front-end. The data in the cache could have been
|
||||||
// taken from the backend and copying them to ModelObject would needlessly invalidate them.
|
// taken from the backend and copying them to ModelObject would needlessly invalidate them.
|
||||||
if (m_unsaved_changes) {
|
if (m_unsaved_changes) {
|
||||||
|
m_model_object->sla_points_status = sla::PointsStatus::UserModified;
|
||||||
m_model_object->sla_support_points.clear();
|
m_model_object->sla_support_points.clear();
|
||||||
for (const std::pair<sla::SupportPoint, bool>& point_and_selection : m_editing_mode_cache)
|
for (const std::pair<sla::SupportPoint, bool>& point_and_selection : m_editing_mode_cache)
|
||||||
m_model_object->sla_support_points.push_back(point_and_selection.first);
|
m_model_object->sla_support_points.push_back(point_and_selection.first);
|
||||||
}
|
|
||||||
m_editing_mode = false;
|
|
||||||
m_unsaved_changes = false;
|
|
||||||
|
|
||||||
// Recalculate support structures once the editing mode is left.
|
// Recalculate support structures once the editing mode is left.
|
||||||
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||||
|
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||||
wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
|
wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
|
||||||
}
|
}
|
||||||
|
m_editing_mode = false;
|
||||||
|
m_unsaved_changes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2476,10 +2481,15 @@ void GLGizmoSlaSupports::get_data_from_backend()
|
||||||
{
|
{
|
||||||
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
|
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
|
||||||
if (po->model_object()->id() == m_model_object->id() && po->is_step_done(slaposSupportPoints)) {
|
if (po->model_object()->id() == m_model_object->id() && po->is_step_done(slaposSupportPoints)) {
|
||||||
|
m_editing_mode_cache.clear();
|
||||||
const std::vector<sla::SupportPoint>& points = po->get_support_points();
|
const std::vector<sla::SupportPoint>& points = po->get_support_points();
|
||||||
auto mat = po->trafo().inverse().cast<float>();
|
auto mat = po->trafo().inverse().cast<float>();
|
||||||
for (unsigned int i=0; i<points.size();++i)
|
for (unsigned int i=0; i<points.size();++i)
|
||||||
m_editing_mode_cache.emplace_back(sla::SupportPoint(mat * points[i].pos, points[i].head_front_radius, points[i].is_new_island), false);
|
m_editing_mode_cache.emplace_back(sla::SupportPoint(mat * points[i].pos, points[i].head_front_radius, points[i].is_new_island), false);
|
||||||
|
|
||||||
|
if (m_model_object->sla_points_status != sla::PointsStatus::UserModified)
|
||||||
|
m_model_object->sla_points_status = sla::PointsStatus::AutoGenerated;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2497,8 +2507,9 @@ void GLGizmoSlaSupports::auto_generate()
|
||||||
"Are you sure you want to do it?\n"
|
"Are you sure you want to do it?\n"
|
||||||
)), _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
|
)), _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
|
||||||
|
|
||||||
if (m_model_object->sla_support_points.empty() || dlg.ShowModal() == wxID_YES) {
|
if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || dlg.ShowModal() == wxID_YES) {
|
||||||
m_model_object->sla_support_points.clear();
|
m_model_object->sla_support_points.clear();
|
||||||
|
m_model_object->sla_points_status = sla::PointsStatus::Generating;
|
||||||
m_editing_mode_cache.clear();
|
m_editing_mode_cache.clear();
|
||||||
wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
|
wxGetApp().plater()->reslice_SLA_supports(*m_model_object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -489,19 +489,19 @@ private:
|
||||||
#endif // not ENABLE_IMGUI
|
#endif // not ENABLE_IMGUI
|
||||||
|
|
||||||
bool m_lock_unique_islands = false;
|
bool m_lock_unique_islands = false;
|
||||||
bool m_editing_mode = false;
|
bool m_editing_mode = false; // Is editing mode active?
|
||||||
bool m_old_editing_state = false;
|
bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes).
|
||||||
float m_new_point_head_diameter = 0.4f;
|
float m_new_point_head_diameter = 0.4f; // Size of a new point.
|
||||||
double m_minimal_point_distance = 20.;
|
float m_minimal_point_distance = 20.f;
|
||||||
double m_density = 100.;
|
float m_density = 100.f;
|
||||||
std::vector<std::pair<sla::SupportPoint, bool>> m_editing_mode_cache; // a support point and whether it is currently selected
|
std::vector<std::pair<sla::SupportPoint, bool>> m_editing_mode_cache; // a support point and whether it is currently selected
|
||||||
|
|
||||||
bool m_selection_rectangle_active = false;
|
bool m_selection_rectangle_active = false;
|
||||||
Vec2d m_selection_rectangle_start_corner;
|
Vec2d m_selection_rectangle_start_corner;
|
||||||
Vec2d m_selection_rectangle_end_corner;
|
Vec2d m_selection_rectangle_end_corner;
|
||||||
bool m_ignore_up_event = false;
|
bool m_ignore_up_event = false;
|
||||||
bool m_combo_box_open = false;
|
bool m_combo_box_open = false; // To ensure proper rendering of the imgui combobox.
|
||||||
bool m_unsaved_changes = false;
|
bool m_unsaved_changes = false; // Are there unsaved changes in manual mode?
|
||||||
bool m_selection_empty = true;
|
bool m_selection_empty = true;
|
||||||
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
|
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
|
||||||
int m_canvas_width;
|
int m_canvas_width;
|
||||||
|
|
|
@ -225,6 +225,17 @@ bool GLShader::set_uniform(const char* name, const float* matrix) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLShader::set_uniform(const char* name, int value) const
|
||||||
|
{
|
||||||
|
int id = get_uniform_location(name);
|
||||||
|
if (id >= 0)
|
||||||
|
{
|
||||||
|
::glUniform1i(id, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
# Set shader vector
|
# Set shader vector
|
||||||
sub SetVector
|
sub SetVector
|
||||||
|
@ -306,6 +317,16 @@ void Shader::stop_using() const
|
||||||
m_shader->disable();
|
m_shader->disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Shader::get_attrib_location(const std::string& name) const
|
||||||
|
{
|
||||||
|
return (m_shader != nullptr) ? m_shader->get_attrib_location(name.c_str()) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Shader::get_uniform_location(const std::string& name) const
|
||||||
|
{
|
||||||
|
return (m_shader != nullptr) ? m_shader->get_uniform_location(name.c_str()) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
void Shader::set_uniform(const std::string& name, float value) const
|
void Shader::set_uniform(const std::string& name, float value) const
|
||||||
{
|
{
|
||||||
if (m_shader != nullptr)
|
if (m_shader != nullptr)
|
||||||
|
@ -321,7 +342,7 @@ void Shader::set_uniform(const std::string& name, const float* matrix) const
|
||||||
void Shader::set_uniform(const std::string& name, bool value) const
|
void Shader::set_uniform(const std::string& name, bool value) const
|
||||||
{
|
{
|
||||||
if (m_shader != nullptr)
|
if (m_shader != nullptr)
|
||||||
m_shader->set_uniform(name.c_str(), value);
|
m_shader->set_uniform(name.c_str(), value ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Shader::get_shader_program_id() const
|
unsigned int Shader::get_shader_program_id() const
|
||||||
|
|
|
@ -26,6 +26,7 @@ public:
|
||||||
|
|
||||||
bool set_uniform(const char *name, float value) const;
|
bool set_uniform(const char *name, float value) const;
|
||||||
bool set_uniform(const char* name, const float* matrix) const;
|
bool set_uniform(const char* name, const float* matrix) const;
|
||||||
|
bool set_uniform(const char* name, int value) const;
|
||||||
|
|
||||||
void enable() const;
|
void enable() const;
|
||||||
void disable() const;
|
void disable() const;
|
||||||
|
@ -52,6 +53,9 @@ public:
|
||||||
bool start_using() const;
|
bool start_using() const;
|
||||||
void stop_using() const;
|
void stop_using() const;
|
||||||
|
|
||||||
|
int get_attrib_location(const std::string& name) const;
|
||||||
|
int get_uniform_location(const std::string& name) const;
|
||||||
|
|
||||||
void set_uniform(const std::string& name, float value) const;
|
void set_uniform(const std::string& name, float value) const;
|
||||||
void set_uniform(const std::string& name, const float* matrix) const;
|
void set_uniform(const std::string& name, const float* matrix) const;
|
||||||
void set_uniform(const std::string& name, bool value) const;
|
void set_uniform(const std::string& name, bool value) const;
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "nanosvg/nanosvgrast.h"
|
#include "nanosvg/nanosvgrast.h"
|
||||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||||
|
|
||||||
|
#include "libslic3r/Utils.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
|
|
@ -1173,10 +1173,91 @@ void ObjectList::load_part( ModelObject* model_object,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
|
||||||
|
// as possible in least squares norm in regard to the 8 corners of bbox.
|
||||||
|
// Bounding box is expected to be centered around zero in all axes.
|
||||||
|
Geometry::Transformation volume_to_bed_transformation(const Geometry::Transformation &instance_transformation, const BoundingBoxf3 &bbox)
|
||||||
|
{
|
||||||
|
Geometry::Transformation out;
|
||||||
|
|
||||||
|
// Is the angle close to a multiple of 90 degrees?
|
||||||
|
auto ninety_degrees = [](double a) {
|
||||||
|
a = fmod(std::abs(a), 0.5 * PI);
|
||||||
|
if (a > 0.25 * PI)
|
||||||
|
a = 0.5 * PI - a;
|
||||||
|
return a < 0.001;
|
||||||
|
};
|
||||||
|
if (instance_transformation.is_scaling_uniform()) {
|
||||||
|
// No need to run the non-linear least squares fitting for uniform scaling.
|
||||||
|
// Just set the inverse.
|
||||||
|
out.set_from_transform(instance_transformation.get_matrix(true).inverse());
|
||||||
|
}
|
||||||
|
else if (ninety_degrees(instance_transformation.get_rotation().x()) && ninety_degrees(instance_transformation.get_rotation().y()) && ninety_degrees(instance_transformation.get_rotation().z()))
|
||||||
|
{
|
||||||
|
// Anisotropic scaling, rotation by multiples of ninety degrees.
|
||||||
|
Eigen::Matrix3d instance_rotation_trafo =
|
||||||
|
(Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) *
|
||||||
|
Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
|
||||||
|
Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix();
|
||||||
|
Eigen::Matrix3d volume_rotation_trafo =
|
||||||
|
(Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) *
|
||||||
|
Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
|
||||||
|
Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix();
|
||||||
|
|
||||||
|
// 8 corners of the bounding box.
|
||||||
|
auto pts = Eigen::MatrixXd(8, 3);
|
||||||
|
pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z();
|
||||||
|
pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z();
|
||||||
|
pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z();
|
||||||
|
pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z();
|
||||||
|
pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z();
|
||||||
|
pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z();
|
||||||
|
pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z();
|
||||||
|
pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z();
|
||||||
|
|
||||||
|
// Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier.
|
||||||
|
auto qs = pts *
|
||||||
|
(instance_rotation_trafo *
|
||||||
|
Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) *
|
||||||
|
volume_rotation_trafo).inverse().transpose();
|
||||||
|
// Fill in scaling based on least squares fitting of the bounding box corners.
|
||||||
|
Vec3d scale;
|
||||||
|
for (int i = 0; i < 3; ++ i)
|
||||||
|
scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i));
|
||||||
|
|
||||||
|
out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo));
|
||||||
|
out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2))));
|
||||||
|
out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// General anisotropic scaling, general rotation.
|
||||||
|
// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
|
||||||
|
// Scale it to get the required size.
|
||||||
|
out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type)
|
void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type)
|
||||||
{
|
{
|
||||||
const auto obj_idx = get_selected_obj_idx();
|
const auto obj_idx = get_selected_obj_idx();
|
||||||
if (obj_idx < 0) return;
|
if (obj_idx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||||
|
assert(obj_idx == selection.get_object_idx());
|
||||||
|
// Selected instance index in ModelObject. Only valid if there is only one instance selected in the selection.
|
||||||
|
int instance_idx = selection.get_instance_idx();
|
||||||
|
assert(instance_idx != -1);
|
||||||
|
if (instance_idx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Selected object
|
||||||
|
ModelObject &model_object = *(*m_objects)[obj_idx];
|
||||||
|
// Bounding box of the selected instance in world coordinate system including the translation, without modifiers.
|
||||||
|
BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx);
|
||||||
|
|
||||||
const wxString name = _(L("Generic")) + "-" + _(type_name);
|
const wxString name = _(L("Generic")) + "-" + _(type_name);
|
||||||
TriangleMesh mesh;
|
TriangleMesh mesh;
|
||||||
|
@ -1185,48 +1266,48 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
||||||
const auto& sz = BoundingBoxf(bed_shape).size();
|
const auto& sz = BoundingBoxf(bed_shape).size();
|
||||||
const auto side = 0.1 * std::max(sz(0), sz(1));
|
const auto side = 0.1 * std::max(sz(0), sz(1));
|
||||||
|
|
||||||
if (type_name == "Box") {
|
if (type_name == "Box")
|
||||||
|
// Sitting on the print bed, left front front corner at (0, 0).
|
||||||
mesh = make_cube(side, side, side);
|
mesh = make_cube(side, side, side);
|
||||||
// box sets the base coordinate at 0, 0, move to center of plate
|
|
||||||
mesh.translate(-side * 0.5, -side * 0.5, 0);
|
|
||||||
}
|
|
||||||
else if (type_name == "Cylinder")
|
else if (type_name == "Cylinder")
|
||||||
mesh = make_cylinder(0.5*side, side);
|
// Centered around 0, sitting on the print bed.
|
||||||
|
// The cylinder has the same volume as the box above.
|
||||||
|
mesh = make_cylinder(0.564 * side, side);
|
||||||
else if (type_name == "Sphere")
|
else if (type_name == "Sphere")
|
||||||
mesh = make_sphere(0.5*side, PI/18);
|
// Centered around 0, half the sphere below the print bed, half above.
|
||||||
else if (type_name == "Slab") {
|
// The sphere has the same volume as the box above.
|
||||||
const auto& size = (*m_objects)[obj_idx]->bounding_box().size();
|
mesh = make_sphere(0.62 * side, PI / 18);
|
||||||
mesh = make_cube(size(0)*1.5, size(1)*1.5, size(2)*0.5);
|
else if (type_name == "Slab")
|
||||||
// box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z
|
// Sitting on the print bed, left front front corner at (0, 0).
|
||||||
mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, 0);
|
mesh = make_cube(instance_bb.size().x()*1.5, instance_bb.size().y()*1.5, instance_bb.size().z()*0.5);
|
||||||
}
|
|
||||||
mesh.repair();
|
mesh.repair();
|
||||||
|
|
||||||
auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh);
|
// Mesh will be centered when loading.
|
||||||
|
ModelVolume *new_volume = model_object.add_volume(std::move(mesh));
|
||||||
new_volume->set_type(type);
|
new_volume->set_type(type);
|
||||||
|
|
||||||
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||||
new_volume->set_offset(Vec3d(0.0, 0.0, (*m_objects)[obj_idx]->origin_translation(2) - mesh.stl.stats.min(2)));
|
new_volume->set_offset(Vec3d(0.0, 0.0, model_object.origin_translation(2) - mesh.stl.stats.min(2)));
|
||||||
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||||
#if !ENABLE_VOLUMES_CENTERING_FIXES
|
#if !ENABLE_VOLUMES_CENTERING_FIXES
|
||||||
new_volume->center_geometry();
|
new_volume->center_geometry();
|
||||||
#endif // !ENABLE_VOLUMES_CENTERING_FIXES
|
#endif // !ENABLE_VOLUMES_CENTERING_FIXES
|
||||||
|
|
||||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||||
const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
|
||||||
int instance_idx = selection.get_instance_idx();
|
|
||||||
if (instance_idx != -1)
|
if (instance_idx != -1)
|
||||||
{
|
{
|
||||||
|
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
|
||||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
const Transform3d& inst_m = v->get_instance_transformation().get_matrix(true);
|
// Transform the new modifier to be aligned with the print bed.
|
||||||
TriangleMesh vol_mesh(mesh);
|
const BoundingBoxf3 mesh_bb = new_volume->mesh.bounding_box();
|
||||||
vol_mesh.transform(inst_m);
|
new_volume->set_transformation(volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb));
|
||||||
Vec3d vol_shift = -vol_mesh.bounding_box().center();
|
// Set the modifier position.
|
||||||
vol_mesh.translate((float)vol_shift(0), (float)vol_shift(1), (float)vol_shift(2));
|
auto offset = (type_name == "Slab") ?
|
||||||
Vec3d world_mesh_bb_size = vol_mesh.bounding_box().size();
|
// Slab: Lift to print bed
|
||||||
BoundingBoxf3 inst_bb = (*m_objects)[obj_idx]->instance_bounding_box(instance_idx);
|
Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) :
|
||||||
Vec3d world_target = Vec3d(inst_bb.max(0), inst_bb.min(1), inst_bb.min(2)) + 0.5 * world_mesh_bb_size;
|
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
|
||||||
new_volume->set_offset(inst_m.inverse() * (world_target - v->get_instance_offset()));
|
Vec3d(instance_bb.max(0), instance_bb.min(1), instance_bb.min(2)) + 0.5 * mesh_bb.size() - v->get_instance_offset();
|
||||||
|
new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
|
||||||
}
|
}
|
||||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||||
|
|
||||||
|
|
|
@ -361,16 +361,20 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation)
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
const GLCanvas3D::Selection& selection = canvas->get_selection();
|
const GLCanvas3D::Selection& selection = canvas->get_selection();
|
||||||
|
|
||||||
Vec3d delta_rotation = rotation - m_cache.rotation;
|
GLCanvas3D::TransformationType transformation_type(GLCanvas3D::TransformationType::World_Relative_Joint);
|
||||||
|
if (selection.is_single_full_instance() || selection.requires_local_axes())
|
||||||
|
transformation_type.set_independent();
|
||||||
|
if (selection.is_single_full_instance()) {
|
||||||
|
transformation_type.set_absolute();
|
||||||
|
transformation_type.set_local();
|
||||||
|
}
|
||||||
|
|
||||||
Vec3d rad_rotation;
|
Vec3d rad_rotation;
|
||||||
for (size_t i = 0; i < 3; ++i)
|
for (size_t i = 0; i < 3; ++i)
|
||||||
{
|
rad_rotation(i) = Geometry::deg2rad((transformation_type.absolute()) ? rotation(i) : rotation(i) - m_cache.rotation(i));
|
||||||
rad_rotation(i) = Geometry::deg2rad(delta_rotation(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas->get_selection().start_dragging();
|
canvas->get_selection().start_dragging();
|
||||||
canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance() || selection.requires_local_axes());
|
canvas->get_selection().rotate(rad_rotation, transformation_type);
|
||||||
canvas->do_rotate();
|
canvas->do_rotate();
|
||||||
|
|
||||||
m_cache.rotation = rotation;
|
m_cache.rotation = rotation;
|
||||||
|
|
|
@ -418,11 +418,14 @@ void Preview::load_print()
|
||||||
load_print_as_sla();
|
load_print_as_sla();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preview::reload_print(bool force)
|
void Preview::reload_print(bool force, bool keep_volumes)
|
||||||
|
{
|
||||||
|
if (!keep_volumes)
|
||||||
{
|
{
|
||||||
m_canvas->reset_volumes();
|
m_canvas->reset_volumes();
|
||||||
m_canvas->reset_legend_texture();
|
m_canvas->reset_legend_texture();
|
||||||
m_loaded = false;
|
m_loaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsShown() && !force)
|
if (!IsShown() && !force)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -129,7 +129,7 @@ public:
|
||||||
void set_drop_target(wxDropTarget* target);
|
void set_drop_target(wxDropTarget* target);
|
||||||
|
|
||||||
void load_print();
|
void load_print();
|
||||||
void reload_print(bool force = false);
|
void reload_print(bool force = false, bool keep_volumes = false);
|
||||||
void refresh_print();
|
void refresh_print();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -2037,6 +2037,9 @@ void Plater::priv::schedule_background_process()
|
||||||
this->background_process_timer.Start(500, wxTIMER_ONE_SHOT);
|
this->background_process_timer.Start(500, wxTIMER_ONE_SHOT);
|
||||||
// Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff.
|
// Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff.
|
||||||
this->view3D->get_canvas3d()->set_config(this->config);
|
this->view3D->get_canvas3d()->set_config(this->config);
|
||||||
|
// Reset gcode preview
|
||||||
|
this->preview->get_canvas3d()->reset_volumes();
|
||||||
|
this->preview->get_canvas3d()->reset_legend_texture();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::update_print_volume_state()
|
void Plater::priv::update_print_volume_state()
|
||||||
|
@ -2326,7 +2329,8 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
||||||
else if (current_panel == preview)
|
else if (current_panel == preview)
|
||||||
{
|
{
|
||||||
this->q->reslice();
|
this->q->reslice();
|
||||||
preview->reload_print();
|
// keeps current gcode preview, if any
|
||||||
|
preview->reload_print(false, true);
|
||||||
preview->set_canvas_as_dirty();
|
preview->set_canvas_as_dirty();
|
||||||
view_toolbar.select_item("Preview");
|
view_toolbar.select_item("Preview");
|
||||||
}
|
}
|
||||||
|
@ -3071,7 +3075,7 @@ void Plater::export_gcode()
|
||||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
||||||
auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string());
|
auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string());
|
||||||
|
|
||||||
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")),
|
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")),
|
||||||
start_dir,
|
start_dir,
|
||||||
from_path(default_output_file.filename()),
|
from_path(default_output_file.filename()),
|
||||||
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()),
|
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()),
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# (the version numbers are generated by the build script from the git current label)
|
# (the version numbers are generated by the build script from the git current label)
|
||||||
|
|
||||||
set(SLIC3R_FORK_NAME "Slic3r Prusa Edition")
|
set(SLIC3R_FORK_NAME "Slic3r Prusa Edition")
|
||||||
set(SLIC3R_VERSION "1.42.0-alpha5")
|
set(SLIC3R_VERSION "1.42.0-alpha6")
|
||||||
set(SLIC3R_BUILD "${SLIC3R_VERSION}+UNKNOWN")
|
set(SLIC3R_BUILD "${SLIC3R_VERSION}+UNKNOWN")
|
||||||
set(SLIC3R_BUILD_ID "${SLIC3R_BUILD_ID}")
|
set(SLIC3R_BUILD_ID "${SLIC3R_BUILD_ID}")
|
||||||
set(SLIC3R_RC_VERSION "1,42,0,0")
|
set(SLIC3R_RC_VERSION "1,42,0,0")
|
||||||
|
|
Loading…
Reference in a new issue