Merge remote-tracking branch 'origin/et_negative_z'

This commit is contained in:
enricoturri1966 2021-05-10 10:44:55 +02:00
commit 51ef2a98e6
17 changed files with 535 additions and 395 deletions

View file

@ -4,7 +4,9 @@ const vec3 ZERO = vec3(0.0, 0.0, 0.0);
const vec3 GREEN = vec3(0.0, 0.7, 0.0);
const vec3 YELLOW = vec3(0.5, 0.7, 0.0);
const vec3 RED = vec3(0.7, 0.0, 0.0);
const vec3 WHITE = vec3(1.0, 1.0, 1.0);
const float EPSILON = 0.0001;
const float BANDS_WIDTH = 10.0;
struct SlopeDetection
{
@ -15,6 +17,7 @@ struct SlopeDetection
uniform vec4 uniform_color;
uniform SlopeDetection slope;
uniform bool sinking;
#ifdef ENABLE_ENVIRONMENT_MAP
uniform sampler2D environment_tex;
@ -23,27 +26,38 @@ uniform SlopeDetection slope;
varying vec3 clipping_planes_dots;
// x = tainted, y = specular;
// x = diffuse, y = specular;
varying vec2 intensity;
varying vec3 delta_box_min;
varying vec3 delta_box_max;
varying vec4 model_pos;
varying float world_pos_z;
varying float world_normal_z;
varying vec3 eye_normal;
vec3 sinking_color(vec3 color)
{
return (mod(model_pos.x + model_pos.y + model_pos.z, BANDS_WIDTH) < (0.5 * BANDS_WIDTH)) ? mix(color, ZERO, 0.6666) : color;
}
void main()
{
if (any(lessThan(clipping_planes_dots, ZERO)))
discard;
vec3 color = uniform_color.rgb;
float alpha = uniform_color.a;
if (slope.actived && world_normal_z < slope.normal_z - EPSILON) {
if (slope.actived && world_normal_z < slope.normal_z - EPSILON)
{
color = vec3(0.7, 0.7, 1.0);
alpha = 1.0;
}
// if the fragment is outside the print volume -> use darker color
color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color;
// if the object is sinking, shade it with inclined bands or white around world z = 0
if (sinking)
color = (abs(world_pos_z) < 0.05) ? WHITE : sinking_color(color);
#ifdef ENABLE_ENVIRONMENT_MAP
if (use_environment_tex)
gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha);

View file

@ -41,7 +41,7 @@ uniform vec2 z_range;
// Clipping plane - general orientation. Used by the SLA gizmo.
uniform vec4 clipping_plane;
// x = tainted, y = specular;
// x = diffuse, y = specular;
varying vec2 intensity;
varying vec3 delta_box_min;
@ -49,6 +49,8 @@ varying vec3 delta_box_max;
varying vec3 clipping_planes_dots;
varying vec4 model_pos;
varying float world_pos_z;
varying float world_normal_z;
varying vec3 eye_normal;
@ -69,12 +71,16 @@ void main()
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
model_pos = gl_Vertex;
// Point in homogenous coordinates.
vec4 world_pos = print_box.volume_world_matrix * gl_Vertex;
world_pos_z = world_pos.z;
// compute deltas for out of print volume detection (world coordinates)
if (print_box.actived)
{
vec3 v = (print_box.volume_world_matrix * gl_Vertex).xyz;
delta_box_min = v - print_box.min;
delta_box_max = v - print_box.max;
delta_box_min = world_pos.xyz - print_box.min;
delta_box_max = world_pos.xyz - print_box.max;
}
else
{
@ -86,8 +92,6 @@ void main()
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0;
gl_Position = ftransform();
// Point in homogenous coordinates.
vec4 world_pos = print_box.volume_world_matrix * gl_Vertex;
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
}

View file

@ -24,7 +24,7 @@ void main()
float z_texture_col = object_z_row - z_texture_row;
float z_blend = 0.25 * cos(min(M_PI, abs(M_PI * (object_z - z_cursor) * 1.8 / z_cursor_band_width))) + 0.25;
// Calculate level of detail from the object Z coordinate.
// This makes the slowly sloping surfaces to be show with high detail (with stripes),
// This makes the slowly sloping surfaces to be shown with high detail (with stripes),
// and the vertical surfaces to be shown with low detail (no stripes)
float z_in_cells = object_z_row * 190.;
// Gradient of Z projected on the screen.
@ -32,9 +32,10 @@ void main()
float dy_vtc = dFdy(z_in_cells);
float lod = clamp(0.5 * log2(max(dx_vtc * dx_vtc, dy_vtc * dy_vtc)), 0., 1.);
// Sample the Z texture. Texture coordinates are normalized to <0, 1>.
vec4 color = mix(texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.),
texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row * 2. + 1.)), 10000.), lod);
vec4 color = vec4(0.25, 0.25, 0.25, 1.0);
if (z_texture_row >= 0.0)
color = mix(texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.),
texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row * 2. + 1.)), 10000.), lod);
// Mix the final color.
gl_FragColor = vec4(intensity.y, intensity.y, intensity.y, 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend);
gl_FragColor = vec4(vec3(intensity.y), 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend);
}

View file

@ -942,30 +942,39 @@ void ModelObject::center_around_origin(bool include_modifiers)
{
// calculate the displacements needed to
// center this object around the origin
BoundingBoxf3 bb = include_modifiers ? full_raw_mesh_bounding_box() : raw_mesh_bounding_box();
const BoundingBoxf3 bb = include_modifiers ? full_raw_mesh_bounding_box() : raw_mesh_bounding_box();
// Shift is the vector from the center of the bounding box to the origin
Vec3d shift = -bb.center();
const Vec3d shift = -bb.center();
this->translate(shift);
this->origin_translation += shift;
}
#if ENABLE_ALLOW_NEGATIVE_Z
void ModelObject::ensure_on_bed(bool allow_negative_z)
{
const double min_z = get_min_z();
if (!allow_negative_z || min_z > 0.0)
translate_instances({ 0.0, 0.0, -min_z });
}
#else
void ModelObject::ensure_on_bed()
{
translate_instances(Vec3d(0.0, 0.0, -get_min_z()));
translate_instances({ 0.0, 0.0, -get_min_z() });
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
void ModelObject::translate_instances(const Vec3d& vector)
{
for (size_t i = 0; i < instances.size(); ++i)
{
for (size_t i = 0; i < instances.size(); ++i) {
translate_instance(i, vector);
}
}
void ModelObject::translate_instance(size_t instance_idx, const Vec3d& vector)
{
assert(instance_idx < instances.size());
ModelInstance* i = instances[instance_idx];
i->set_offset(i->get_offset() + vector);
invalidate_bounding_box();
@ -973,8 +982,7 @@ void ModelObject::translate_instance(size_t instance_idx, const Vec3d& vector)
void ModelObject::translate(double x, double y, double z)
{
for (ModelVolume *v : this->volumes)
{
for (ModelVolume *v : this->volumes) {
v->translate(x, y, z);
}
@ -984,8 +992,7 @@ void ModelObject::translate(double x, double y, double z)
void ModelObject::scale(const Vec3d &versor)
{
for (ModelVolume *v : this->volumes)
{
for (ModelVolume *v : this->volumes) {
v->scale(versor);
}
this->invalidate_bounding_box();
@ -993,41 +1000,34 @@ void ModelObject::scale(const Vec3d &versor)
void ModelObject::rotate(double angle, Axis axis)
{
for (ModelVolume *v : this->volumes)
{
for (ModelVolume *v : this->volumes) {
v->rotate(angle, axis);
}
center_around_origin();
this->invalidate_bounding_box();
}
void ModelObject::rotate(double angle, const Vec3d& axis)
{
for (ModelVolume *v : this->volumes)
{
for (ModelVolume *v : this->volumes) {
v->rotate(angle, axis);
}
center_around_origin();
this->invalidate_bounding_box();
}
void ModelObject::mirror(Axis axis)
{
for (ModelVolume *v : this->volumes)
{
for (ModelVolume *v : this->volumes) {
v->mirror(axis);
}
this->invalidate_bounding_box();
}
// This method could only be called before the meshes of this ModelVolumes are not shared!
void ModelObject::scale_mesh_after_creation(const Vec3d &versor)
{
for (ModelVolume *v : this->volumes)
{
for (ModelVolume *v : this->volumes) {
v->scale_geometry_after_creation(versor);
v->set_offset(versor.cwiseProduct(v->get_offset()));
}
@ -1418,11 +1418,9 @@ double ModelObject::get_min_z() const
{
if (instances.empty())
return 0.0;
else
{
else {
double min_z = DBL_MAX;
for (size_t i = 0; i < instances.size(); ++i)
{
for (size_t i = 0; i < instances.size(); ++i) {
min_z = std::min(min_z, get_instance_min_z(i));
}
return min_z;
@ -1433,15 +1431,14 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
{
double min_z = DBL_MAX;
ModelInstance* inst = instances[instance_idx];
const ModelInstance* inst = instances[instance_idx];
const Transform3d& mi = inst->get_matrix(true);
for (const ModelVolume* v : volumes)
{
for (const ModelVolume* v : volumes) {
if (!v->is_model_part())
continue;
Transform3d mv = mi * v->get_matrix();
const Transform3d mv = mi * v->get_matrix();
const TriangleMesh& hull = v->get_convex_hull();
for (const stl_facet &facet : hull.stl.facet_start)
for (int i = 0; i < 3; ++ i)

View file

@ -306,7 +306,11 @@ public:
void center_around_origin(bool include_modifiers = true);
#if ENABLE_ALLOW_NEGATIVE_Z
void ensure_on_bed(bool allow_negative_z = false);
#else
void ensure_on_bed();
#endif // ENABLE_ALLOW_NEGATIVE_Z
void translate_instances(const Vec3d& vector);
void translate_instance(size_t instance_idx, const Vec3d& vector);
void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); }

View file

@ -1628,9 +1628,15 @@ PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegion
void PrintObject::update_slicing_parameters()
{
#if ENABLE_ALLOW_NEGATIVE_Z
if (!m_slicing_params.valid)
m_slicing_params = SlicingParameters::create_from_config(
this->print()->config(), m_config, this->model_object()->bounding_box().max.z(), this->object_extruders());
#else
if (! m_slicing_params.valid)
m_slicing_params = SlicingParameters::create_from_config(
this->print()->config(), m_config, unscale<double>(this->height()), this->object_extruders());
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
@ -1692,6 +1698,15 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
updated = true;
}
#if ENABLE_ALLOW_NEGATIVE_Z
// Verify the layer_height_profile.
if (!layer_height_profile.empty() &&
// Must not be of even length.
((layer_height_profile.size() & 1) != 0 ||
// Last entry must be at the top of the object.
std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_max) > 1e-3))
layer_height_profile.clear();
#else
// Verify the layer_height_profile.
if (! layer_height_profile.empty() &&
// Must not be of even length.
@ -1699,6 +1714,7 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
// Last entry must be at the top of the object.
std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_height()) > 1e-3))
layer_height_profile.clear();
#endif // ENABLE_ALLOW_NEGATIVE_Z
if (layer_height_profile.empty()) {
//layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);

View file

@ -65,11 +65,13 @@
#define ENABLE_START_GCODE_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0)
// Enable visualization of seams in preview
#define ENABLE_SEAMS_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0)
// Enable project dirty state manager
#define ENABLE_PROJECT_DIRTY_STATE (1 && ENABLE_2_4_0_ALPHA0)
// Enable project dirty state manager debug window
#define ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW (0 && ENABLE_PROJECT_DIRTY_STATE)
// Enable to push object instances under the bed
#define ENABLE_ALLOW_NEGATIVE_Z (1 && ENABLE_2_4_0_ALPHA0)
#define DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA (1 && ENABLE_ALLOW_NEGATIVE_Z)
#endif // _prusaslicer_technologies_h_

View file

@ -23,6 +23,9 @@
#include "libslic3r/Format/STL.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
#include "libslic3r/PresetBundle.hpp"
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
#include <stdio.h>
#include <stdlib.h>
@ -345,9 +348,16 @@ void GLVolume::set_render_color(const float* rgba, unsigned int size)
void GLVolume::set_render_color()
{
if (force_native_color || force_neutral_color)
{
#if ENABLE_ALLOW_NEGATIVE_Z
bool outside = is_outside || is_below_printbed();
#endif // ENABLE_ALLOW_NEGATIVE_Z
if (force_native_color || force_neutral_color) {
#if ENABLE_ALLOW_NEGATIVE_Z
if (outside && shader_outside_printer_detection_enabled)
#else
if (is_outside && shader_outside_printer_detection_enabled)
#endif // ENABLE_ALLOW_NEGATIVE_Z
set_render_color(OUTSIDE_COLOR, 4);
else {
if (force_native_color)
@ -362,17 +372,24 @@ void GLVolume::set_render_color()
else if (hover == HS_Deselect)
set_render_color(HOVER_DESELECT_COLOR, 4);
else if (selected)
#if ENABLE_ALLOW_NEGATIVE_Z
set_render_color(outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
#else
set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
#endif // ENABLE_ALLOW_NEGATIVE_Z
else if (disabled)
set_render_color(DISABLED_COLOR, 4);
#if ENABLE_ALLOW_NEGATIVE_Z
else if (outside && shader_outside_printer_detection_enabled)
#else
else if (is_outside && shader_outside_printer_detection_enabled)
#endif // ENABLE_ALLOW_NEGATIVE_Z
set_render_color(OUTSIDE_COLOR, 4);
else
set_render_color(color, 4);
}
if (!printable)
{
if (!printable) {
render_color[0] /= 4;
render_color[1] /= 4;
render_color[2] /= 4;
@ -504,6 +521,25 @@ void GLVolume::render() const
bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -int(slaposSupportTree); }
bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposPad); }
#if ENABLE_ALLOW_NEGATIVE_Z
bool GLVolume::is_sinking() const
{
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
if (is_modifier || GUI::wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA)
#else
if (is_modifier)
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
return false;
const BoundingBoxf3& box = transformed_convex_hull_bounding_box();
return box.min(2) < -EPSILON && box.max(2) >= -EPSILON;
}
bool GLVolume::is_below_printbed() const
{
return transformed_convex_hull_bounding_box().max(2) < 0.0;
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
std::vector<int> GLVolumeCollection::load_object(
const ModelObject *model_object,
int obj_idx,
@ -778,6 +814,9 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
shader->set_uniform("print_box.volume_world_matrix", volume.first->world_matrix());
shader->set_uniform("slope.actived", m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower);
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
#if ENABLE_ALLOW_NEGATIVE_Z
shader->set_uniform("sinking", volume.first->is_sinking());
#endif // ENABLE_ALLOW_NEGATIVE_Z
volume.first->render();
}

View file

@ -453,6 +453,11 @@ public:
bool is_sla_support() const;
bool is_sla_pad() const;
#if ENABLE_ALLOW_NEGATIVE_Z
bool is_sinking() const;
bool is_below_printbed() const;
#endif // ENABLE_ALLOW_NEGATIVE_Z
// Return an estimate of the memory consumed by this class.
size_t cpu_memory_used() const {
//FIXME what to do wih m_convex_hull?

View file

@ -134,27 +134,9 @@ void Size::set_scale_factor(int scale_factor)
m_scale_factor = scale_factor;
}
GLCanvas3D::LayersEditing::LayersEditing()
: m_enabled(false)
, m_z_texture_id(0)
, m_model_object(nullptr)
, m_object_max_z(0.f)
, m_slicing_parameters(nullptr)
, m_layer_height_profile_modified(false)
, m_adaptive_quality(0.5f)
, state(Unknown)
, band_width(2.0f)
, strength(0.005f)
, last_object_id(-1)
, last_z(0.0f)
, last_action(LAYER_HEIGHT_EDIT_ACTION_INCREASE)
{
}
GLCanvas3D::LayersEditing::~LayersEditing()
{
if (m_z_texture_id != 0)
{
if (m_z_texture_id != 0) {
glsafe(::glDeleteTextures(1, &m_z_texture_id));
m_z_texture_id = 0;
}
@ -186,11 +168,18 @@ void GLCanvas3D::LayersEditing::set_config(const DynamicPrintConfig* config)
void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
{
const ModelObject *model_object_new = (object_id >= 0) ? model.objects[object_id] : nullptr;
#if ENABLE_ALLOW_NEGATIVE_Z
// Maximum height of an object changes when the object gets rotated or scaled.
// Changing maximum height of an object will invalidate the layer heigth editing profile.
// m_model_object->bounding_box() is cached, therefore it is cheap even if this method is called frequently.
const float new_max_z = (model_object_new == nullptr) ? 0.0f : static_cast<float>(model_object_new->bounding_box().max.z());
#else
// Maximum height of an object changes when the object gets rotated or scaled.
// Changing maximum height of an object will invalidate the layer heigth editing profile.
// m_model_object->raw_bounding_box() is cached, therefore it is cheap even if this method is called frequently.
float new_max_z = (model_object_new == nullptr) ? 0.f : model_object_new->raw_bounding_box().size().z();
if (m_model_object != model_object_new || this->last_object_id != object_id || m_object_max_z != new_max_z ||
#endif // ENABLE_ALLOW_NEGATIVE_Z
if (m_model_object != model_object_new || this->last_object_id != object_id || m_object_max_z != new_max_z ||
(model_object_new != nullptr && m_model_object->id() != model_object_new->id())) {
m_layer_height_profile.clear();
m_layer_height_profile_modified = false;
@ -218,7 +207,7 @@ void GLCanvas3D::LayersEditing::set_enabled(bool enabled)
m_enabled = is_allowed() && enabled;
}
float GLCanvas3D::LayersEditing::s_overelay_window_width;
float GLCanvas3D::LayersEditing::s_overlay_window_width;
void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
{
@ -302,7 +291,7 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
if (imgui.button(_L("Reset")))
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE));
GLCanvas3D::LayersEditing::s_overelay_window_width = ImGui::GetWindowSize().x /*+ (float)m_layers_texture.width/4*/;
GLCanvas3D::LayersEditing::s_overlay_window_width = ImGui::GetWindowSize().x /*+ (float)m_layers_texture.width/4*/;
imgui.end();
const Rect& bar_rect = get_bar_rect_viewport(canvas);
@ -319,7 +308,7 @@ float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas)
float t = rect.get_top();
float b = rect.get_bottom();
return ((rect.get_left() <= x) && (x <= rect.get_right()) && (t <= y) && (y <= b)) ?
return (rect.get_left() <= x && x <= rect.get_right() && t <= y && y <= b) ?
// Inside the bar.
(b - y - 1.0f) / (b - t - 1.0f) :
// Outside the bar.
@ -329,7 +318,7 @@ float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas)
bool GLCanvas3D::LayersEditing::bar_rect_contains(const GLCanvas3D& canvas, float x, float y)
{
const Rect& rect = get_bar_rect_screen(canvas);
return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom());
return rect.get_left() <= x && x <= rect.get_right() && rect.get_top() <= y && y <= rect.get_bottom();
}
Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
@ -338,7 +327,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
float w = (float)cnv_size.get_width();
float h = (float)cnv_size.get_height();
return Rect(w - thickness_bar_width(canvas), 0.0f, w, h);
return { w - thickness_bar_width(canvas), 0.0f, w, h };
}
Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
@ -347,7 +336,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
float half_w = 0.5f * (float)cnv_size.get_width();
float half_h = 0.5f * (float)cnv_size.get_height();
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
return { (half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom };
}
bool GLCanvas3D::LayersEditing::is_initialized() const
@ -365,11 +354,12 @@ std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) con
float h = 0.0f;
for (size_t i = m_layer_height_profile.size() - 2; i >= 2; i -= 2) {
float zi = m_layer_height_profile[i];
float zi_1 = m_layer_height_profile[i - 2];
const float zi = static_cast<float>(m_layer_height_profile[i]);
const float zi_1 = static_cast<float>(m_layer_height_profile[i - 2]);
if (zi_1 <= z && z <= zi) {
float dz = zi - zi_1;
h = (dz != 0.0f) ? lerp(m_layer_height_profile[i - 1], m_layer_height_profile[i + 1], (z - zi_1) / dz) : m_layer_height_profile[i + 1];
h = (dz != 0.0f) ? static_cast<float>(lerp(m_layer_height_profile[i - 1], m_layer_height_profile[i + 1], (z - zi_1) / dz)) :
static_cast<float>(m_layer_height_profile[i + 1]);
break;
}
}
@ -398,10 +388,10 @@ void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3
glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id));
// Render the color bar
float l = bar_rect.get_left();
float r = bar_rect.get_right();
float t = bar_rect.get_top();
float b = bar_rect.get_bottom();
const float l = bar_rect.get_left();
const float r = bar_rect.get_right();
const float t = bar_rect.get_top();
const float b = bar_rect.get_bottom();
::glBegin(GL_QUADS);
::glNormal3f(0.0f, 0.0f, 1.0f);
@ -564,7 +554,7 @@ void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas)
{
if (last_object_id >= 0) {
if (m_layer_height_profile_modified) {
wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Manual edit")));
wxGetApp().plater()->take_snapshot(_L("Variable layer height - Manual edit"));
const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile);
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
wxGetApp().obj_list()->update_info_items(last_object_id);
@ -577,7 +567,7 @@ void GLCanvas3D::LayersEditing::update_slicing_parameters()
{
if (m_slicing_parameters == nullptr) {
m_slicing_parameters = new SlicingParameters();
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object, m_object_max_z);
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object, m_object_max_z);
}
}
@ -1961,7 +1951,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
m_reload_delayed = !m_canvas->IsShown() && !refresh_immediately && !force_full_scene_refresh;
PrinterTechnology printer_technology = m_process->current_printer_technology();
PrinterTechnology printer_technology = current_printer_technology();
int volume_idx_wipe_tower_old = -1;
// Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed).
@ -3578,14 +3568,38 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
wipe_tower_origin = v->get_volume_offset();
}
#if ENABLE_ALLOW_NEGATIVE_Z
// Fixes flying instances
#else
// Fixes sinking/flying instances
#endif // ENABLE_ALLOW_NEGATIVE_Z
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
#if ENABLE_ALLOW_NEGATIVE_Z
double shift_z = m->get_instance_min_z(i.second);
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
if (current_printer_technology() == ptSLA || shift_z > 0.0) {
#else
if (shift_z > 0.0) {
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
Vec3d shift(0.0, 0.0, -shift_z);
#else
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
#endif // ENABLE_ALLOW_NEGATIVE_Z
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
#if ENABLE_ALLOW_NEGATIVE_Z
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
#if ENABLE_ALLOW_NEGATIVE_Z
// if the selection is not valid to allow for layer editing after the move, we need to turn off the tool if it is running
// similar to void Plater::priv::selection_changed()
if (!wxGetApp().plater()->can_layers_editing() && is_layers_editing_enabled())
post_event(SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING));
#endif // ENABLE_ALLOW_NEGATIVE_Z
if (object_moved)
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
@ -3603,18 +3617,30 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(snapshot_type));
#if ENABLE_ALLOW_NEGATIVE_Z
// stores current min_z of instances
std::map<std::pair<int, int>, double> min_zs;
if (!snapshot_type.empty()) {
for (int i = 0; i < static_cast<int>(m_model->objects.size()); ++i) {
const ModelObject* obj = m_model->objects[i];
for (int j = 0; j < static_cast<int>(obj->instances.size()); ++j) {
min_zs[{ i, j }] = obj->instance_bounding_box(j).min(2);
}
}
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
std::set<std::pair<int, int>> done; // keeps track of modified instances
Selection::EMode selection_mode = m_selection.get_mode();
for (const GLVolume* v : m_volumes.volumes)
{
for (const GLVolume* v : m_volumes.volumes) {
int object_idx = v->object_idx();
if (object_idx == 1000) { // the wipe tower
Vec3d offset = v->get_volume_offset();
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset(0), offset(1), v->get_volume_rotation()(2))));
}
if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx))
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue;
int instance_idx = v->instance_idx();
@ -3624,15 +3650,12 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
// Rotate instances/volumes.
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr)
{
if (selection_mode == Selection::Instance)
{
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_rotation(v->get_instance_rotation());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
}
else if (selection_mode == Selection::Volume)
{
else if (selection_mode == Selection::Volume) {
model_object->volumes[volume_idx]->set_rotation(v->get_volume_rotation());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
}
@ -3641,12 +3664,21 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
}
// Fixes sinking/flying instances
for (const std::pair<int, int>& i : done)
{
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
#if ENABLE_ALLOW_NEGATIVE_Z
double shift_z = m->get_instance_min_z(i.second);
// leave sinking instances as sinking
if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= 0.0 || shift_z > 0.0) {
Vec3d shift(0.0, 0.0, -shift_z);
#else
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
#endif // ENABLE_ALLOW_NEGATIVE_Z
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
#if ENABLE_ALLOW_NEGATIVE_Z
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
if (!done.empty())
@ -3663,14 +3695,26 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(snapshot_type));
#if ENABLE_ALLOW_NEGATIVE_Z
// stores current min_z of instances
std::map<std::pair<int, int>, double> min_zs;
if (!snapshot_type.empty()) {
for (int i = 0; i < static_cast<int>(m_model->objects.size()); ++i) {
const ModelObject* obj = m_model->objects[i];
for (int j = 0; j < static_cast<int>(obj->instances.size()); ++j) {
min_zs[{ i, j }] = obj->instance_bounding_box(j).min(2);
}
}
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
std::set<std::pair<int, int>> done; // keeps track of modified instances
Selection::EMode selection_mode = m_selection.get_mode();
for (const GLVolume* v : m_volumes.volumes)
{
for (const GLVolume* v : m_volumes.volumes) {
int object_idx = v->object_idx();
if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx))
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue;
int instance_idx = v->instance_idx();
@ -3680,15 +3724,12 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// Rotate instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr)
{
if (selection_mode == Selection::Instance)
{
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_scaling_factor(v->get_instance_scaling_factor());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
}
else if (selection_mode == Selection::Volume)
{
else if (selection_mode == Selection::Volume) {
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
model_object->volumes[volume_idx]->set_scaling_factor(v->get_volume_scaling_factor());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
@ -3698,16 +3739,25 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
}
// Fixes sinking/flying instances
for (const std::pair<int, int>& i : done)
{
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
#if ENABLE_ALLOW_NEGATIVE_Z
double shift_z = m->get_instance_min_z(i.second);
// leave sinking instances as sinking
if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= 0.0 || shift_z > 0.0) {
Vec3d shift(0.0, 0.0, -shift_z);
#else
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
#endif // ENABLE_ALLOW_NEGATIVE_Z
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
#if ENABLE_ALLOW_NEGATIVE_Z
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
if (!done.empty())
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_SCALED));
m_dirty = true;
}
@ -3875,7 +3925,7 @@ void GLCanvas3D::update_tooltip_for_settings_item_in_main_toolbar()
{
std::string new_tooltip = _u8L("Switch to Settings") +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "2] - " + _u8L("Print Settings Tab") +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (m_process->current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab") ;
m_main_toolbar.set_tooltip(get_main_toolbar_item_id("settings"), new_tooltip);
@ -4029,7 +4079,7 @@ bool GLCanvas3D::_render_arrange_menu(float pos_x)
ArrangeSettings &settings_out = get_arrange_settings();
auto &appcfg = wxGetApp().app_config;
PrinterTechnology ptech = m_process->current_printer_technology();
PrinterTechnology ptech = current_printer_technology();
bool settings_changed = false;
float dist_min = 0.f;
@ -4596,7 +4646,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "settings";
item.icon_filename = "settings.svg";
item.tooltip = _u8L("Switch to Settings") + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "2] - " + _u8L("Print Settings Tab") +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (m_process->current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab") ;
item.sprite_id = 10;
item.enabling_callback = GLToolbarItem::Default_Enabling_Callback;
@ -4638,7 +4688,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.sprite_id = 12;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); };
item.visibility_callback = [this]()->bool {
bool res = m_process->current_printer_technology() == ptFFF;
bool res = current_printer_technology() == ptFFF;
// turns off if changing printer technology
if (!res && m_main_toolbar.is_item_visible("layersediting") && m_main_toolbar.is_item_pressed("layersediting"))
force_main_toolbar_left_action(get_main_toolbar_item_id("layersediting"));

View file

@ -154,53 +154,50 @@ class GLCanvas3D
static const float THICKNESS_BAR_WIDTH;
private:
bool m_enabled;
unsigned int m_z_texture_id;
bool m_enabled{ false };
unsigned int m_z_texture_id{ 0 };
// Not owned by LayersEditing.
const DynamicPrintConfig *m_config;
const DynamicPrintConfig *m_config{ nullptr };
// ModelObject for the currently selected object (Model::objects[last_object_id]).
const ModelObject *m_model_object;
const ModelObject *m_model_object{ nullptr };
// Maximum z of the currently selected object (Model::objects[last_object_id]).
float m_object_max_z;
float m_object_max_z{ 0.0f };
// Owned by LayersEditing.
SlicingParameters *m_slicing_parameters;
SlicingParameters *m_slicing_parameters{ nullptr };
std::vector<double> m_layer_height_profile;
bool m_layer_height_profile_modified;
bool m_layer_height_profile_modified{ false };
mutable float m_adaptive_quality;
mutable float m_adaptive_quality{ 0.5f };
mutable HeightProfileSmoothingParams m_smooth_params;
static float s_overelay_window_width;
static float s_overlay_window_width;
class LayersTexture
struct LayersTexture
{
public:
LayersTexture() : width(0), height(0), levels(0), cells(0), valid(false) {}
// Texture data
std::vector<char> data;
// Width of the texture, top level.
size_t width;
size_t width{ 0 };
// Height of the texture, top level.
size_t height;
size_t height{ 0 };
// For how many levels of detail is the data allocated?
size_t levels;
size_t levels{ 0 };
// Number of texture cells allocated for the height texture.
size_t cells;
size_t cells{ 0 };
// Does it need to be refreshed?
bool valid;
bool valid{ false };
};
LayersTexture m_layers_texture;
public:
EState state;
float band_width;
float strength;
int last_object_id;
float last_z;
LayerHeightEditActionType last_action;
EState state{ Unknown };
float band_width{ 2.0f };
float strength{ 0.005f };
int last_object_id{ -1 };
float last_z{ 0.0f };
LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE };
LayersEditing();
LayersEditing() = default;
~LayersEditing();
void init();
@ -226,7 +223,7 @@ class GLCanvas3D
static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);
static Rect get_bar_rect_screen(const GLCanvas3D& canvas);
static Rect get_bar_rect_viewport(const GLCanvas3D& canvas);
static float get_overlay_window_width() { return LayersEditing::s_overelay_window_width; }
static float get_overlay_window_width() { return LayersEditing::s_overlay_window_width; }
float object_max_z() const { return m_object_max_z; }

View file

@ -142,7 +142,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(editor);
auto temp = new wxStaticText(m_parent, wxID_ANY, _(L("mm")));
auto temp = new wxStaticText(m_parent, wxID_ANY, _L("mm"));
temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
temp->SetFont(wxGetApp().normal_font());
sizer->Add(temp, 0, wxLEFT, wxGetApp().em_unit());
@ -154,15 +154,14 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus
void ObjectLayers::create_layers_list()
{
for (const auto &layer : m_object->layer_config_ranges)
{
for (const auto &layer : m_object->layer_config_ranges) {
const t_layer_height_range& range = layer.first;
auto del_btn = new PlusMinusButton(m_parent, m_bmp_delete, range);
del_btn->SetToolTip(_(L("Remove layer range")));
del_btn->SetToolTip(_L("Remove layer range"));
auto add_btn = new PlusMinusButton(m_parent, m_bmp_add, range);
wxString tooltip = wxGetApp().obj_list()->can_add_new_range_after_current(range);
add_btn->SetToolTip(tooltip.IsEmpty() ? _(L("Add layer range")) : tooltip);
add_btn->SetToolTip(tooltip.IsEmpty() ? _L("Add layer range") : tooltip);
add_btn->Enable(tooltip.IsEmpty());
auto sizer = create_layer(range, del_btn, add_btn);
@ -242,11 +241,9 @@ void ObjectLayers::msw_rescale()
// rescale edit-boxes
const int cells_cnt = m_grid_sizer->GetCols() * m_grid_sizer->GetEffectiveRowsCount();
for (int i = 0; i < cells_cnt; i++)
{
for (int i = 0; i < cells_cnt; ++i) {
const wxSizerItem* item = m_grid_sizer->GetItem(i);
if (item->IsWindow())
{
if (item->IsWindow()) {
LayerRangeEditor* editor = dynamic_cast<LayerRangeEditor*>(item->GetWindow());
if (editor != nullptr)
editor->msw_rescale();
@ -283,8 +280,7 @@ void ObjectLayers::sys_color_changed()
// rescale edit-boxes
const int cells_cnt = m_grid_sizer->GetCols() * m_grid_sizer->GetEffectiveRowsCount();
for (int i = 0; i < cells_cnt; i++)
{
for (int i = 0; i < cells_cnt; ++i) {
const wxSizerItem* item = m_grid_sizer->GetItem(i);
if (item->IsSizer()) {// case when we have editor with buttons
const std::vector<size_t> btns = {2, 3}; // del_btn, add_btn
@ -405,11 +401,9 @@ coordf_t LayerRangeEditor::get_value()
str.Replace(",", ".", false);
if (str == ".")
layer_height = 0.0;
else
{
if (!str.ToCDouble(&layer_height) || layer_height < 0.0f)
{
show_error(m_parent, _(L("Invalid numeric input.")));
else {
if (!str.ToCDouble(&layer_height) || layer_height < 0.0f) {
show_error(m_parent, _L("Invalid numeric input."));
SetValue(double_to_string(layer_height));
}
}

View file

@ -2119,18 +2119,15 @@ void ObjectList::part_selection_changed()
const auto item = GetSelection();
if ( multiple_selection() || (item && m_objects_model->GetItemType(item) == itInstanceRoot ))
{
og_name = _(L("Group manipulation"));
if ( multiple_selection() || (item && m_objects_model->GetItemType(item) == itInstanceRoot )) {
og_name = _L("Group manipulation");
const Selection& selection = scene_selection();
// don't show manipulation panel for case of all Object's parts selection
update_and_show_manipulations = !selection.is_single_full_instance();
}
else
{
if (item)
{
else {
if (item) {
const ItemType type = m_objects_model->GetItemType(item);
const wxDataViewItem parent = m_objects_model->GetParent(item);
const ItemType parent_type = m_objects_model->GetItemType(parent);
@ -2138,7 +2135,7 @@ void ObjectList::part_selection_changed()
if (parent == wxDataViewItem(nullptr)
|| type == itInfo) {
og_name = _(L("Object manipulation"));
og_name = _L("Object manipulation");
m_config = &(*m_objects)[obj_idx]->config;
update_and_show_manipulations = true;
@ -2158,35 +2155,35 @@ void ObjectList::part_selection_changed()
else {
if (type & itSettings) {
if (parent_type & itObject) {
og_name = _(L("Object Settings to modify"));
og_name = _L("Object Settings to modify");
m_config = &(*m_objects)[obj_idx]->config;
}
else if (parent_type & itVolume) {
og_name = _(L("Part Settings to modify"));
og_name = _L("Part Settings to modify");
volume_id = m_objects_model->GetVolumeIdByItem(parent);
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
}
else if (parent_type & itLayer) {
og_name = _(L("Layer range Settings to modify"));
og_name = _L("Layer range Settings to modify");
m_config = &get_item_config(parent);
}
update_and_show_settings = true;
}
else if (type & itVolume) {
og_name = _(L("Part manipulation"));
og_name = _L("Part manipulation");
volume_id = m_objects_model->GetVolumeIdByItem(item);
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
update_and_show_manipulations = true;
}
else if (type & itInstance) {
og_name = _(L("Instance manipulation"));
og_name = _L("Instance manipulation");
update_and_show_manipulations = true;
// fill m_config by object's values
m_config = &(*m_objects)[obj_idx]->config;
}
else if (type & (itLayerRoot|itLayer)) {
og_name = type & itLayerRoot ? _(L("Height ranges")) : _(L("Settings for height range"));
og_name = type & itLayerRoot ? _L("Height ranges") : _L("Settings for height range");
update_and_show_layers = true;
if (type & itLayer)
@ -2815,7 +2812,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
const int obj_idx = m_selected_object_id;
if (obj_idx < 0) return false;
take_snapshot(_(L("Edit Height Range")));
take_snapshot(_L("Edit Height Range"));
const ItemType sel_type = m_objects_model->GetItemType(GetSelection());

View file

@ -26,21 +26,26 @@ const double ObjectManipulation::mm_to_in = 0.0393700787;
// Helper function to be used by drop to bed button. Returns lowest point of this
// volume in world coordinate system.
static double get_volume_min_z(const GLVolume* volume)
static double get_volume_min_z(const GLVolume& volume)
{
const Transform3f& world_matrix = volume->world_matrix().cast<float>();
#if ENABLE_ALLOW_NEGATIVE_Z
return volume.transformed_convex_hull_bounding_box().min.z();
#else
const Transform3f& world_matrix = volume.world_matrix().cast<float>();
// need to get the ModelVolume pointer
const ModelObject* mo = wxGetApp().model().objects[volume->composite_id.object_id];
const ModelVolume* mv = mo->volumes[volume->composite_id.volume_id];
const ModelObject* mo = wxGetApp().model().objects[volume.composite_id.object_id];
const ModelVolume* mv = mo->volumes[volume.composite_id.volume_id];
const TriangleMesh& hull = mv->get_convex_hull();
float min_z = std::numeric_limits<float>::max();
for (const stl_facet& facet : hull.stl.facet_start) {
for (int i = 0; i < 3; ++ i)
for (int i = 0; i < 3; ++i)
min_z = std::min(min_z, Vec3f::UnitZ().dot(world_matrix * facet.vertex[i]));
}
return min_z;
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
@ -341,13 +346,27 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation();
Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume));
const Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(*volume));
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
}
#if ENABLE_ALLOW_NEGATIVE_Z
else if (selection.is_single_full_instance()) {
const ModelObjectPtrs& objects = wxGetApp().model().objects;
const int idx = selection.get_object_idx();
if (0 <= idx && idx < static_cast<int>(objects.size())) {
const ModelObject* mo = wxGetApp().model().objects[idx];
const double min_z = mo->bounding_box().min.z();
if (std::abs(min_z) > EPSILON) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z);
}
}
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
});
editors_grid_sizer->Add(m_drop_to_bed_button);
@ -671,11 +690,15 @@ void ObjectManipulation::update_reset_buttons_visibility()
if (selection.is_single_full_instance()) {
rotation = volume->get_instance_rotation();
scale = volume->get_instance_scaling_factor();
#if ENABLE_ALLOW_NEGATIVE_Z
min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z();
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
else {
rotation = volume->get_volume_rotation();
scale = volume->get_volume_scaling_factor();
min_z = get_volume_min_z(volume);
min_z = get_volume_min_z(*volume);
}
show_rotation = !rotation.isApprox(Vec3d::Zero());
show_scale = !scale.isApprox(Vec3d::Ones());

View file

@ -1593,7 +1593,11 @@ struct Plater::priv
BoundingBox scaled_bed_shape_bb() const;
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool used_inches = false);
#if ENABLE_ALLOW_NEGATIVE_Z
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false);
#else
std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects);
#endif // ENABLE_ALLOW_NEGATIVE_Z
wxString get_export_file(GUI::FileType file_type);
const Selection& get_selection() const;
@ -2333,11 +2337,19 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
return obj_idxs;
}
#if ENABLE_ALLOW_NEGATIVE_Z
for (ModelObject* model_object : model.objects) {
if (!type_3mf && !type_zip_amf)
model_object->center_around_origin(false);
model_object->ensure_on_bed(is_project_file);
}
#else
for (ModelObject* model_object : model.objects) {
if (!type_3mf && !type_zip_amf)
model_object->center_around_origin(false);
model_object->ensure_on_bed();
}
#endif // ENABLE_ALLOW_NEGATIVE_Z
// check multi-part object adding for the SLA-printing
if (printer_technology == ptSLA) {
@ -2351,7 +2363,11 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
if (one_by_one) {
#if ENABLE_ALLOW_NEGATIVE_Z
auto loaded_idxs = load_model_objects(model.objects, is_project_file);
#else
auto loaded_idxs = load_model_objects(model.objects);
#endif // ENABLE_ALLOW_NEGATIVE_Z
obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end());
} else {
// This must be an .stl or .obj file, which may contain a maximum of one volume.
@ -2403,7 +2419,11 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// #define AUTOPLACEMENT_ON_LOAD
#if ENABLE_ALLOW_NEGATIVE_Z
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z)
#else
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &model_objects)
#endif // ENABLE_ALLOW_NEGATIVE_Z
{
const BoundingBoxf bed_shape = bed_shape_bb();
const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast<double>(), 1.0) - 2.0 * Vec3d::Ones();
@ -2480,7 +2500,11 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
}
#endif // ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG
#if ENABLE_ALLOW_NEGATIVE_Z
object->ensure_on_bed(allow_negative_z);
#else
object->ensure_on_bed();
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
#ifdef AUTOPLACEMENT_ON_LOAD
@ -2636,8 +2660,7 @@ int Plater::priv::get_selected_volume_idx() const
void Plater::priv::selection_changed()
{
// if the selection is not valid to allow for layer editing, we need to turn off the tool if it is running
bool enable_layer_editing = layers_height_allowed();
if (!enable_layer_editing && view3D->is_layers_editing_enabled()) {
if (!layers_height_allowed() && view3D->is_layers_editing_enabled()) {
SimpleEvent evt(EVT_GLTOOLBAR_LAYERSEDITING);
on_action_layersediting(evt);
}
@ -3078,21 +3101,19 @@ void Plater::priv::reload_from_disk()
int volume_idx;
// operators needed by std::algorithms
bool operator < (const SelectedVolume& other) const { return (object_idx < other.object_idx) || ((object_idx == other.object_idx) && (volume_idx < other.volume_idx)); }
bool operator == (const SelectedVolume& other) const { return (object_idx == other.object_idx) && (volume_idx == other.volume_idx); }
bool operator < (const SelectedVolume& other) const { return object_idx < other.object_idx || (object_idx == other.object_idx && volume_idx < other.volume_idx); }
bool operator == (const SelectedVolume& other) const { return object_idx == other.object_idx && volume_idx == other.volume_idx; }
};
std::vector<SelectedVolume> selected_volumes;
// collects selected ModelVolumes
const std::set<unsigned int>& selected_volumes_idxs = selection.get_volume_idxs();
for (unsigned int idx : selected_volumes_idxs)
{
for (unsigned int idx : selected_volumes_idxs) {
const GLVolume* v = selection.get_volume(idx);
int v_idx = v->volume_idx();
if (v_idx >= 0)
{
if (v_idx >= 0) {
int o_idx = v->object_idx();
if ((0 <= o_idx) && (o_idx < (int)model.objects.size()))
if (0 <= o_idx && o_idx < (int)model.objects.size())
selected_volumes.push_back({ o_idx, v_idx });
}
}
@ -3102,13 +3123,11 @@ void Plater::priv::reload_from_disk()
// collects paths of files to load
std::vector<fs::path> input_paths;
std::vector<fs::path> missing_input_paths;
for (const SelectedVolume& v : selected_volumes)
{
for (const SelectedVolume& v : selected_volumes) {
const ModelObject* object = model.objects[v.object_idx];
const ModelVolume* volume = object->volumes[v.volume_idx];
if (!volume->source.input_file.empty())
{
if (!volume->source.input_file.empty()) {
if (fs::exists(volume->source.input_file))
input_paths.push_back(volume->source.input_file);
else
@ -3121,8 +3140,7 @@ void Plater::priv::reload_from_disk()
std::sort(missing_input_paths.begin(), missing_input_paths.end());
missing_input_paths.erase(std::unique(missing_input_paths.begin(), missing_input_paths.end()), missing_input_paths.end());
while (!missing_input_paths.empty())
{
while (!missing_input_paths.empty()) {
// ask user to select the missing file
fs::path search = missing_input_paths.back();
wxString title = _L("Please select the file to reload");
@ -3136,21 +3154,18 @@ void Plater::priv::reload_from_disk()
std::string sel_filename_path = dialog.GetPath().ToUTF8().data();
std::string sel_filename = fs::path(sel_filename_path).filename().string();
if (boost::algorithm::iequals(search.filename().string(), sel_filename))
{
if (boost::algorithm::iequals(search.filename().string(), sel_filename)) {
input_paths.push_back(sel_filename_path);
missing_input_paths.pop_back();
fs::path sel_path = fs::path(sel_filename_path).remove_filename().string();
std::vector<fs::path>::iterator it = missing_input_paths.begin();
while (it != missing_input_paths.end())
{
while (it != missing_input_paths.end()) {
// try to use the path of the selected file with all remaining missing files
fs::path repathed_filename = sel_path;
repathed_filename /= it->filename();
if (fs::exists(repathed_filename))
{
if (fs::exists(repathed_filename)) {
input_paths.push_back(repathed_filename.string());
it = missing_input_paths.erase(it);
}
@ -3158,8 +3173,7 @@ void Plater::priv::reload_from_disk()
++it;
}
}
else
{
else {
wxString message = _L("It is not allowed to change the file to reload") + " (" + from_u8(search.filename().string()) + ").\n" + _L("Do you want to retry") + " ?";
wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES)
@ -3173,8 +3187,7 @@ void Plater::priv::reload_from_disk()
std::vector<wxString> fail_list;
// load one file at a time
for (size_t i = 0; i < input_paths.size(); ++i)
{
for (size_t i = 0; i < input_paths.size(); ++i) {
const auto& path = input_paths[i].string();
wxBusyCursor wait;
@ -3184,8 +3197,7 @@ void Plater::priv::reload_from_disk()
try
{
new_model = Model::read_from_file(path, nullptr, true, false);
for (ModelObject* model_object : new_model.objects)
{
for (ModelObject* model_object : new_model.objects) {
model_object->center_around_origin();
model_object->ensure_on_bed();
}
@ -3197,34 +3209,31 @@ void Plater::priv::reload_from_disk()
}
// update the selected volumes whose source is the current file
for (const SelectedVolume& sel_v : selected_volumes)
{
for (const SelectedVolume& sel_v : selected_volumes) {
ModelObject* old_model_object = model.objects[sel_v.object_idx];
ModelVolume* old_volume = old_model_object->volumes[sel_v.volume_idx];
#if ENABLE_ALLOW_NEGATIVE_Z
bool sinking = old_model_object->bounding_box().min.z() < 0.0;
#endif // ENABLE_ALLOW_NEGATIVE_Z
bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string());
bool has_name = !old_volume->name.empty() && boost::algorithm::iequals(old_volume->name, fs::path(path).filename().string());
if (has_source || has_name)
{
if (has_source || has_name) {
int new_volume_idx = -1;
int new_object_idx = -1;
if (has_source)
{
if (has_source) {
// take idxs from source
new_volume_idx = old_volume->source.volume_idx;
new_object_idx = old_volume->source.object_idx;
}
else
{
else {
// take idxs from the 1st matching volume
for (size_t o = 0; o < new_model.objects.size(); ++o)
{
for (size_t o = 0; o < new_model.objects.size(); ++o) {
ModelObject* obj = new_model.objects[o];
bool found = false;
for (size_t v = 0; v < obj->volumes.size(); ++v)
{
if (obj->volumes[v]->name == old_volume->name)
{
for (size_t v = 0; v < obj->volumes.size(); ++v) {
if (obj->volumes[v]->name == old_volume->name) {
new_volume_idx = (int)v;
new_object_idx = (int)o;
found = true;
@ -3236,19 +3245,16 @@ void Plater::priv::reload_from_disk()
}
}
if ((new_object_idx < 0) && ((int)new_model.objects.size() <= new_object_idx))
{
if (new_object_idx < 0 && (int)new_model.objects.size() <= new_object_idx) {
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
continue;
}
ModelObject* new_model_object = new_model.objects[new_object_idx];
if ((new_volume_idx < 0) && ((int)new_model.objects.size() <= new_volume_idx))
{
if (new_volume_idx < 0 && (int)new_model.objects.size() <= new_volume_idx) {
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
continue;
}
if (new_volume_idx < (int)new_model_object->volumes.size())
{
if (new_volume_idx < (int)new_model_object->volumes.size()) {
old_model_object->add_volume(*new_model_object->volumes[new_volume_idx]);
ModelVolume* new_volume = old_model_object->volumes.back();
new_volume->set_new_unique_id();
@ -3265,7 +3271,10 @@ void Plater::priv::reload_from_disk()
new_volume->seam_facets.assign(old_volume->seam_facets);
std::swap(old_model_object->volumes[sel_v.volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
old_model_object->ensure_on_bed();
#if ENABLE_ALLOW_NEGATIVE_Z
if (!sinking)
#endif // ENABLE_ALLOW_NEGATIVE_Z
old_model_object->ensure_on_bed();
sla::reproject_points_and_holes(old_model_object);
}
@ -3273,11 +3282,9 @@ void Plater::priv::reload_from_disk()
}
}
if (!fail_list.empty())
{
if (!fail_list.empty()) {
wxString message = _L("Unable to reload:") + "\n";
for (const wxString& s : fail_list)
{
for (const wxString& s : fail_list) {
message += s + "\n";
}
wxMessageDialog dlg(q, message, _L("Error during reload"), wxOK | wxOK_DEFAULT | wxICON_WARNING);
@ -3288,8 +3295,7 @@ void Plater::priv::reload_from_disk()
update();
// new GLVolumes have been created at this point, so update their printable state
for (size_t i = 0; i < model.objects.size(); ++i)
{
for (size_t i = 0; i < model.objects.size(); ++i) {
view3D->get_canvas3d()->update_instance_printable_state_for_object(i);
}
}
@ -3309,8 +3315,7 @@ void Plater::priv::reload_all_from_disk()
reload_from_disk();
// restore previous selection
selection.clear();
for (unsigned int idx : curr_idxs)
{
for (unsigned int idx : curr_idxs) {
selection.add(idx, false);
}
}
@ -4030,7 +4035,7 @@ void Plater::priv::reset_gcode_toolpaths()
bool Plater::priv::can_set_instance_to_object() const
{
const int obj_idx = get_selected_object_idx();
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1);
return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->instances.size() > 1;
}
bool Plater::priv::can_split(bool to_objects) const
@ -4044,7 +4049,12 @@ bool Plater::priv::layers_height_allowed() const
return false;
int obj_idx = get_selected_object_idx();
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed();
#if ENABLE_ALLOW_NEGATIVE_Z
return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->bounding_box().max.z() > 0.0 &&
config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed();
#else
return 0 <= obj_idx && obj_idx < (int)model.objects.size() && config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed();
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
bool Plater::priv::can_mirror() const
@ -5923,6 +5933,14 @@ bool Plater::set_printer_technology(PrinterTechnology printer_technology)
//FIXME for SLA synchronize
//p->background_process.apply(Model)!
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
if (printer_technology == ptSLA) {
for (ModelObject* model_object : p->model.objects) {
model_object->ensure_on_bed();
}
}
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
p->label_btn_export = printer_technology == ptFFF ? L("Export G-code") : L("Export");
p->label_btn_send = printer_technology == ptFFF ? L("Send G-code") : L("Send to printer");
@ -5942,7 +5960,15 @@ void Plater::changed_object(int obj_idx)
return;
// recenter and re - align to Z = 0
auto model_object = p->model.objects[obj_idx];
#if ENABLE_ALLOW_NEGATIVE_Z
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
model_object->ensure_on_bed(this->p->printer_technology != ptSLA);
#else
model_object->ensure_on_bed(true);
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
#else
model_object->ensure_on_bed();
#endif // ENABLE_ALLOW_NEGATIVE_Z
if (this->p->printer_technology == ptSLA) {
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data, update the 3D scene.
@ -5960,11 +5986,18 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
if (object_idxs.empty())
return;
for (size_t obj_idx : object_idxs)
{
for (size_t obj_idx : object_idxs) {
#if ENABLE_ALLOW_NEGATIVE_Z
if (obj_idx < p->model.objects.size()) {
if (p->model.objects[obj_idx]->bounding_box().min.z() >= 0.0)
// re - align to Z = 0
p->model.objects[obj_idx]->ensure_on_bed();
}
#else
if (obj_idx < p->model.objects.size())
// recenter and re - align to Z = 0
p->model.objects[obj_idx]->ensure_on_bed();
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
if (this->p->printer_technology == ptSLA) {
// Update the SLAPrint from the current Model, so that the reload_scene()

View file

@ -12,6 +12,9 @@
#include "Plater.hpp"
#include "libslic3r/Model.hpp"
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
#include "libslic3r/PresetBundle.hpp"
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
#include <GL/glew.h>
@ -58,13 +61,11 @@ bool Selection::Clipboard::is_sla_compliant() const
if (m_mode == Selection::Volume)
return false;
for (const ModelObject* o : m_model->objects)
{
for (const ModelObject* o : m_model->objects) {
if (o->is_multiparts())
return false;
for (const ModelVolume* v : o->volumes)
{
for (const ModelVolume* v : o->volumes) {
if (v->is_modifier())
return false;
}
@ -78,7 +79,8 @@ Selection::Clipboard::Clipboard()
m_model.reset(new Model);
}
void Selection::Clipboard::reset() {
void Selection::Clipboard::reset()
{
m_model->clear_objects();
}
@ -149,7 +151,7 @@ void Selection::set_model(Model* model)
void Selection::add(unsigned int volume_idx, bool as_single_selection, bool check_for_already_contained)
{
if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx))
if (!m_valid || (unsigned int)m_volumes->size() <= volume_idx)
return;
const GLVolume* volume = (*m_volumes)[volume_idx];
@ -167,9 +169,8 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
needs_reset |= as_single_selection && !is_any_modifier() && volume->is_modifier;
needs_reset |= is_any_modifier() && !volume->is_modifier;
if (!already_contained || needs_reset)
{
wxGetApp().plater()->take_snapshot(_(L("Selection-Add")));
if (!already_contained || needs_reset) {
wxGetApp().plater()->take_snapshot(_L("Selection-Add"));
if (needs_reset)
clear();
@ -185,7 +186,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
{
case Volume:
{
if ((volume->volume_idx() >= 0) && (is_empty() || (volume->instance_idx() == get_instance_idx())))
if (volume->volume_idx() >= 0 && (is_empty() || volume->instance_idx() == get_instance_idx()))
do_add_volume(volume_idx);
break;
@ -204,13 +205,13 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
void Selection::remove(unsigned int volume_idx)
{
if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx))
if (!m_valid || (unsigned int)m_volumes->size() <= volume_idx)
return;
if (!contains_volume(volume_idx))
return;
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove")));
wxGetApp().plater()->take_snapshot(_L("Selection-Remove"));
GLVolume* volume = (*m_volumes)[volume_idx];
@ -242,7 +243,7 @@ void Selection::add_object(unsigned int object_idx, bool as_single_selection)
(as_single_selection && matches(volume_idxs)))
return;
wxGetApp().plater()->take_snapshot(_(L("Selection-Add Object")));
wxGetApp().plater()->take_snapshot(_L("Selection-Add Object"));
// resets the current list if needed
if (as_single_selection)
@ -261,7 +262,7 @@ void Selection::remove_object(unsigned int object_idx)
if (!m_valid)
return;
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Object")));
wxGetApp().plater()->take_snapshot(_L("Selection-Remove Object"));
do_remove_object(object_idx);
@ -274,12 +275,12 @@ void Selection::add_instance(unsigned int object_idx, unsigned int instance_idx,
if (!m_valid)
return;
std::vector<unsigned int> volume_idxs = get_volume_idxs_from_instance(object_idx, instance_idx);
const std::vector<unsigned int> volume_idxs = get_volume_idxs_from_instance(object_idx, instance_idx);
if ((!as_single_selection && contains_all_volumes(volume_idxs)) ||
(as_single_selection && matches(volume_idxs)))
return;
wxGetApp().plater()->take_snapshot(_(L("Selection-Add Instance")));
wxGetApp().plater()->take_snapshot(_L("Selection-Add Instance"));
// resets the current list if needed
if (as_single_selection)
@ -298,7 +299,7 @@ void Selection::remove_instance(unsigned int object_idx, unsigned int instance_i
if (!m_valid)
return;
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Instance")));
wxGetApp().plater()->take_snapshot(_L("Selection-Remove Instance"));
do_remove_instance(object_idx, instance_idx);
@ -333,10 +334,9 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx)
if (!m_valid)
return;
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == (int)object_idx) && (v->volume_idx() == (int)volume_idx))
if (v->object_idx() == (int)object_idx && v->volume_idx() == (int)volume_idx)
do_remove_volume(i);
}
@ -358,8 +358,7 @@ void Selection::add_volumes(EMode mode, const std::vector<unsigned int>& volume_
clear();
m_mode = mode;
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (i < (unsigned int)m_volumes->size())
do_add_volume(i);
}
@ -374,8 +373,7 @@ void Selection::remove_volumes(EMode mode, const std::vector<unsigned int>& volu
return;
m_mode = mode;
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (i < (unsigned int)m_volumes->size())
do_remove_volume(i);
}
@ -390,8 +388,7 @@ void Selection::add_all()
return;
unsigned int count = 0;
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
if (!(*m_volumes)[i]->is_wipe_tower)
++count;
}
@ -404,8 +401,7 @@ void Selection::add_all()
m_mode = Instance;
clear();
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
if (!(*m_volumes)[i]->is_wipe_tower)
do_add_volume(i);
}
@ -455,8 +451,7 @@ void Selection::clear()
if (m_list.empty())
return;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
(*m_volumes)[i]->selected = false;
}
@ -522,16 +517,15 @@ bool Selection::is_single_full_instance() const
return false;
int object_idx = m_valid ? get_object_idx() : -1;
if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx))
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
return false;
int instance_idx = (*m_volumes)[*m_list.begin()]->instance_idx();
std::set<int> volumes_idxs;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
const GLVolume* v = (*m_volumes)[i];
if ((object_idx != v->object_idx()) || (instance_idx != v->instance_idx()))
if (object_idx != v->object_idx() || instance_idx != v->instance_idx())
return false;
int volume_idx = v->volume_idx();
@ -544,8 +538,8 @@ bool Selection::is_single_full_instance() const
bool Selection::is_from_single_object() const
{
int idx = get_object_idx();
return (0 <= idx) && (idx < 1000);
const int idx = get_object_idx();
return 0 <= idx && idx < 1000;
}
bool Selection::is_sla_compliant() const
@ -553,8 +547,7 @@ bool Selection::is_sla_compliant() const
if (m_mode == Volume)
return false;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
if ((*m_volumes)[i]->is_modifier)
return false;
}
@ -564,8 +557,7 @@ bool Selection::is_sla_compliant() const
bool Selection::contains_all_volumes(const std::vector<unsigned int>& volume_idxs) const
{
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (m_list.find(i) == m_list.end())
return false;
}
@ -575,8 +567,7 @@ bool Selection::contains_all_volumes(const std::vector<unsigned int>& volume_idx
bool Selection::contains_any_volume(const std::vector<unsigned int>& volume_idxs) const
{
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (m_list.find(i) != m_list.end())
return true;
}
@ -588,8 +579,7 @@ bool Selection::matches(const std::vector<unsigned int>& volume_idxs) const
{
unsigned int count = 0;
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (m_list.find(i) != m_list.end())
++count;
else
@ -614,8 +604,7 @@ int Selection::get_object_idx() const
int Selection::get_instance_idx() const
{
if (m_cache.content.size() == 1)
{
if (m_cache.content.size() == 1) {
const InstanceIdxsList& idxs = m_cache.content.begin()->second;
if (idxs.size() == 1)
return *idxs.begin();
@ -672,25 +661,20 @@ void Selection::translate(const Vec3d& displacement, bool local)
EMode translation_type = m_mode;
for (unsigned int i : m_list)
{
if ((m_mode == Volume) || (*m_volumes)[i]->is_wipe_tower)
{
for (unsigned int i : m_list) {
if (m_mode == Volume || (*m_volumes)[i]->is_wipe_tower) {
if (local)
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + displacement);
else
{
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
else {
const Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
}
}
else if (m_mode == Instance)
{
else if (m_mode == Instance) {
if (is_from_fully_selected_instance(i))
(*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement);
else
{
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
else {
const Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
translation_type = Volume;
}
@ -718,18 +702,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
if (!is_wipe_tower()) {
int rot_axis_max = 0;
if (rotation.isApprox(Vec3d::Zero()))
{
for (unsigned int i : m_list)
{
if (rotation.isApprox(Vec3d::Zero())) {
for (unsigned int i : m_list) {
GLVolume &volume = *(*m_volumes)[i];
if (m_mode == Instance)
{
if (m_mode == Instance) {
volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation());
volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position());
}
else if (m_mode == Volume)
{
else if (m_mode == Volume) {
volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation());
volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position());
}
@ -746,14 +726,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
// For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
std::vector<int> object_instance_first(m_model->objects.size(), -1);
auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) {
int first_volume_idx = object_instance_first[volume.object_idx()];
const int first_volume_idx = object_instance_first[volume.object_idx()];
if (rot_axis_max != 2 && first_volume_idx != -1) {
// Generic rotation, but no rotation around the Z axis.
// Always do a local rotation (do not consider the selection to be a rigid body).
assert(is_approx(rotation.z(), 0.0));
const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
const Vec3d &rotation = first_volume.get_instance_rotation();
double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
}
else {
@ -763,7 +743,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
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.
double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_rotation);
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_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);
@ -771,19 +751,16 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
}
};
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
GLVolume &volume = *(*m_volumes)[i];
if (is_single_full_instance())
rotate_instance(volume, i);
else if (is_single_volume() || is_single_modifier())
{
else if (is_single_volume() || is_single_modifier()) {
if (transformation_type.independent())
volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
else
{
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
else {
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
volume.set_volume_rotation(new_rotation);
}
}
@ -791,15 +768,13 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
{
if (m_mode == Instance)
rotate_instance(volume, i);
else if (m_mode == Volume)
{
else if (m_mode == Volume) {
// extracts rotations from the composed transformation
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
if (transformation_type.joint())
{
Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
if (transformation_type.joint()) {
const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
volume.set_volume_offset(local_pivot + offset);
}
volume.set_volume_rotation(new_rotation);
@ -820,8 +795,8 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
// make sure the wipe tower rotates around its center, not origin
// we can assume that only Z rotation changes
Vec3d center_local = volume.transformed_bounding_box().center() - volume.get_volume_offset();
Vec3d center_local_new = Eigen::AngleAxisd(rotation(2)-volume.get_volume_rotation()(2), Vec3d(0, 0, 1)) * center_local;
const Vec3d center_local = volume.transformed_bounding_box().center() - volume.get_volume_offset();
const Vec3d center_local_new = Eigen::AngleAxisd(rotation(2)-volume.get_volume_rotation()(2), Vec3d(0.0, 0.0, 1.0)) * center_local;
volume.set_volume_rotation(rotation);
volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new);
}
@ -839,8 +814,7 @@ void Selection::flattening_rotate(const Vec3d& normal)
if (!m_valid)
return;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
// Normal transformed from the object coordinate space to the world coordinate space.
const auto &voldata = m_cache.volumes_data[i];
Vec3d tnormal = (Geometry::assemble_transform(
@ -866,12 +840,10 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
if (!m_valid)
return;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
GLVolume &volume = *(*m_volumes)[i];
if (is_single_full_instance()) {
if (transformation_type.relative())
{
if (transformation_type.relative()) {
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
// extracts scaling factors from the composed transformation
@ -881,8 +853,7 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
volume.set_instance_scaling_factor(new_scale);
}
else
{
else {
if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) {
// Non-uniform scaling. Transform the scaling factors into the local coordinate system.
// This is only possible, if the instance rotation is mulitples of ninety degrees.
@ -895,11 +866,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
}
else if (is_single_volume() || is_single_modifier())
volume.set_volume_scaling_factor(scale);
else
{
else {
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
if (m_mode == Instance)
{
if (m_mode == Instance) {
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
// extracts scaling factors from the composed transformation
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
@ -908,13 +877,11 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
volume.set_instance_scaling_factor(new_scale);
}
else if (m_mode == Volume)
{
else if (m_mode == Volume) {
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
// extracts scaling factors from the composed transformation
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
if (transformation_type.joint())
{
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);
volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
}
@ -929,35 +896,36 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
else if (m_mode == Volume)
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
ensure_on_bed();
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA)
ensure_on_bed();
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
this->set_bounding_boxes_dirty();
}
void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
{
if (is_empty() || (m_mode == Volume))
if (is_empty() || m_mode == Volume)
return;
// adds 1/100th of a mm on all sides to avoid false out of print volume detections due to floating-point roundings
Vec3d box_size = get_bounding_box().size() + 0.01 * Vec3d::Ones();
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(config.option("bed_shape"));
if (opt != nullptr)
{
if (opt != nullptr) {
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config.opt_float("max_print_height")));
BoundingBoxf3 print_volume({ unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0 }, { unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config.opt_float("max_print_height") });
Vec3d print_volume_size = print_volume.size();
double sx = (box_size(0) != 0.0) ? print_volume_size(0) / box_size(0) : 0.0;
double sy = (box_size(1) != 0.0) ? print_volume_size(1) / box_size(1) : 0.0;
double sz = (box_size(2) != 0.0) ? print_volume_size(2) / box_size(2) : 0.0;
if ((sx != 0.0) && (sy != 0.0) && (sz != 0.0))
if (sx != 0.0 && sy != 0.0 && sz != 0.0)
{
double s = std::min(sx, std::min(sy, sz));
if (s != 1.0)
{
wxGetApp().plater()->take_snapshot(_(L("Scale To Fit")));
if (s != 1.0) {
wxGetApp().plater()->take_snapshot(_L("Scale To Fit"));
TransformationType type;
type.set_world();
@ -987,8 +955,7 @@ void Selection::mirror(Axis axis)
bool single_full_instance = is_single_full_instance();
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
if (single_full_instance)
(*m_volumes)[i]->set_instance_mirror(axis, -(*m_volumes)[i]->get_instance_mirror(axis));
else if (m_mode == Volume)
@ -1010,8 +977,7 @@ void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
if (!m_valid)
return;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
GLVolume* v = (*m_volumes)[i];
if (v->object_idx() == (int)object_idx)
v->set_instance_offset(v->get_instance_offset() + displacement);
@ -1020,8 +986,7 @@ void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
std::set<unsigned int> done; // prevent processing volumes twice
done.insert(m_list.begin(), m_list.end());
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
if (done.size() == m_volumes->size())
break;
@ -1030,8 +995,7 @@ void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
continue;
// Process unselected volumes of the object.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (done.size() == m_volumes->size())
break;
@ -1055,18 +1019,16 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
if (!m_valid)
return;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
if (v->object_idx() == (int)object_idx && v->instance_idx() == (int)instance_idx)
v->set_instance_offset(v->get_instance_offset() + displacement);
}
std::set<unsigned int> done; // prevent processing volumes twice
done.insert(m_list.begin(), m_list.end());
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
if (done.size() == m_volumes->size())
break;
@ -1075,8 +1037,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
continue;
// Process unselected volumes of the object.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (done.size() == m_volumes->size())
break;
@ -1084,7 +1045,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
continue;
GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->instance_idx() != (int)instance_idx))
if (v->object_idx() != object_idx || v->instance_idx() != (int)instance_idx)
continue;
v->set_instance_offset(v->get_instance_offset() + displacement);
@ -1799,18 +1760,16 @@ void Selection::render_synchronized_volumes() const
float color[3] = { 1.0f, 1.0f, 0.0f };
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
int volume_idx = volume->volume_idx();
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (i == j)
continue;
const GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx))
if (v->object_idx() != object_idx || v->volume_idx() != volume_idx)
continue;
render_bounding_box(v->transformed_convex_hull_bounding_box(), color);
@ -2032,9 +1991,9 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
#ifndef NDEBUG
static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Vec3d axis = angle_axis.axis();
double angle = angle_axis.angle();
const Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
const Vec3d axis = angle_axis.axis();
const double angle = angle_axis.angle();
if (std::abs(angle) < 1e-8)
return true;
assert(std::abs(axis.x()) < 1e-8);
@ -2071,24 +2030,22 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
std::set<unsigned int> done; // prevent processing volumes twice
done.insert(m_list.begin(), m_list.end());
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
if (done.size() == m_volumes->size())
break;
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
const int object_idx = volume->object_idx();
if (object_idx >= 1000)
continue;
int instance_idx = volume->instance_idx();
const int instance_idx = volume->instance_idx();
const Vec3d& rotation = volume->get_instance_rotation();
const Vec3d& scaling_factor = volume->get_instance_scaling_factor();
const Vec3d& mirror = volume->get_instance_mirror();
// Process unselected instances.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (done.size() == m_volumes->size())
break;
@ -2096,24 +2053,36 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
continue;
GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->instance_idx() == instance_idx))
if (v->object_idx() != object_idx || v->instance_idx() == instance_idx)
continue;
assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()));
switch (sync_rotation_type) {
case SYNC_ROTATION_NONE:
case SYNC_ROTATION_NONE: {
#if ENABLE_ALLOW_NEGATIVE_Z
// z only rotation -> synch instance z
// The X,Y rotations should be synchronized from start to end of the rotation.
assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation()));
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
v->set_instance_offset(Z, volume->get_instance_offset().z());
break;
#else
// z only rotation -> keep instance z
// The X,Y rotations should be synchronized from start to end of the rotation.
assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation()));
break;
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
case SYNC_ROTATION_FULL:
// rotation comes from place on face -> force given z
v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2)));
v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() });
break;
case SYNC_ROTATION_GENERAL:
// generic rotation -> update instance z with the delta of the rotation.
double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff });
break;
}
@ -2131,27 +2100,25 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
void Selection::synchronize_unselected_volumes()
{
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
const int object_idx = volume->object_idx();
if (object_idx >= 1000)
continue;
int volume_idx = volume->volume_idx();
const int volume_idx = volume->volume_idx();
const Vec3d& offset = volume->get_volume_offset();
const Vec3d& rotation = volume->get_volume_rotation();
const Vec3d& scaling_factor = volume->get_volume_scaling_factor();
const Vec3d& mirror = volume->get_volume_mirror();
// Process unselected volumes.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (j == i)
continue;
GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx))
if (v->object_idx() != object_idx || v->volume_idx() != volume_idx)
continue;
v->set_volume_offset(offset);
@ -2167,10 +2134,8 @@ void Selection::ensure_on_bed()
typedef std::map<std::pair<int, int>, double> InstancesToZMap;
InstancesToZMap instances_min_z;
for (GLVolume* volume : *m_volumes)
{
if (!volume->is_wipe_tower && !volume->is_modifier)
{
for (GLVolume* volume : *m_volumes) {
if (!volume->is_wipe_tower && !volume->is_modifier) {
double min_z = volume->transformed_convex_hull_bounding_box().min(2);
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
InstancesToZMap::iterator it = instances_min_z.find(instance);
@ -2181,8 +2146,7 @@ void Selection::ensure_on_bed()
}
}
for (GLVolume* volume : *m_volumes)
{
for (GLVolume* volume : *m_volumes) {
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
InstancesToZMap::iterator it = instances_min_z.find(instance);
if (it != instances_min_z.end())

View file

@ -129,7 +129,7 @@ private:
TransformCache m_instance;
public:
VolumeCache() {}
VolumeCache() = default;
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
const Vec3d& get_volume_position() const { return m_volume.position; }