Merge remote-tracking branch 'origin/et_negative_z'
This commit is contained in:
commit
51ef2a98e6
17 changed files with 535 additions and 395 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)); }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Add table
Reference in a new issue