mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 14:08:59 +08:00
Merge branch 'master' into fs_emboss_temp
This commit is contained in:
commit
4da355e55e
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,9 @@ struct SlopeDetection
|
|||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
uniform bool use_color_clip_plane;
|
||||||
|
uniform vec4 uniform_color_clip_plane_1;
|
||||||
|
uniform vec4 uniform_color_clip_plane_2;
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
@ -34,6 +37,7 @@ uniform SlopeDetection slope;
|
|||||||
uniform PrintVolumeDetection print_volume;
|
uniform PrintVolumeDetection print_volume;
|
||||||
|
|
||||||
varying vec3 clipping_planes_dots;
|
varying vec3 clipping_planes_dots;
|
||||||
|
varying float color_clip_plane_dot;
|
||||||
|
|
||||||
// x = diffuse, y = specular;
|
// x = diffuse, y = specular;
|
||||||
varying vec2 intensity;
|
varying vec2 intensity;
|
||||||
@ -46,12 +50,18 @@ void main()
|
|||||||
{
|
{
|
||||||
if (any(lessThan(clipping_planes_dots, ZERO)))
|
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||||
discard;
|
discard;
|
||||||
vec3 color = uniform_color.rgb;
|
|
||||||
float alpha = uniform_color.a;
|
vec4 color;
|
||||||
|
if (use_color_clip_plane) {
|
||||||
|
color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb;
|
||||||
|
color.a = uniform_color.a;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
color = uniform_color;
|
||||||
|
|
||||||
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);
|
color.rgb = vec3(0.7, 0.7, 1.0);
|
||||||
alpha = 1.0;
|
color.a = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the fragment is outside the print volume -> use darker color
|
// if the fragment is outside the print volume -> use darker color
|
||||||
@ -68,12 +78,12 @@ void main()
|
|||||||
pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x);
|
pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x);
|
||||||
pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y);
|
pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y);
|
||||||
}
|
}
|
||||||
color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color;
|
color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
if (use_environment_tex)
|
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);
|
gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha);
|
gl_FragColor = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ uniform SlopeDetection slope;
|
|||||||
uniform vec2 z_range;
|
uniform vec2 z_range;
|
||||||
// Clipping plane - general orientation. Used by the SLA gizmo.
|
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||||
uniform vec4 clipping_plane;
|
uniform vec4 clipping_plane;
|
||||||
|
// Color clip plane - general orientation. Used by the cut gizmo.
|
||||||
|
uniform vec4 color_clip_plane;
|
||||||
|
|
||||||
attribute vec3 v_position;
|
attribute vec3 v_position;
|
||||||
attribute vec3 v_normal;
|
attribute vec3 v_normal;
|
||||||
@ -43,6 +45,7 @@ attribute vec3 v_normal;
|
|||||||
varying vec2 intensity;
|
varying vec2 intensity;
|
||||||
|
|
||||||
varying vec3 clipping_planes_dots;
|
varying vec3 clipping_planes_dots;
|
||||||
|
varying float color_clip_plane_dot;
|
||||||
|
|
||||||
varying vec4 world_pos;
|
varying vec4 world_pos;
|
||||||
varying float world_normal_z;
|
varying float world_normal_z;
|
||||||
@ -74,4 +77,5 @@ void main()
|
|||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
|
// 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);
|
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||||
|
color_clip_plane_dot = dot(world_pos, color_clip_plane);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,9 @@ struct SlopeDetection
|
|||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
uniform bool use_color_clip_plane;
|
||||||
|
uniform vec4 uniform_color_clip_plane_1;
|
||||||
|
uniform vec4 uniform_color_clip_plane_2;
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
@ -34,6 +37,7 @@ uniform SlopeDetection slope;
|
|||||||
uniform PrintVolumeDetection print_volume;
|
uniform PrintVolumeDetection print_volume;
|
||||||
|
|
||||||
in vec3 clipping_planes_dots;
|
in vec3 clipping_planes_dots;
|
||||||
|
in float color_clip_plane_dot;
|
||||||
|
|
||||||
// x = diffuse, y = specular;
|
// x = diffuse, y = specular;
|
||||||
in vec2 intensity;
|
in vec2 intensity;
|
||||||
@ -48,12 +52,18 @@ void main()
|
|||||||
{
|
{
|
||||||
if (any(lessThan(clipping_planes_dots, ZERO)))
|
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||||
discard;
|
discard;
|
||||||
vec3 color = uniform_color.rgb;
|
|
||||||
float alpha = uniform_color.a;
|
vec4 color;
|
||||||
|
if (use_color_clip_plane) {
|
||||||
|
color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb;
|
||||||
|
color.a = uniform_color.a;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
color = uniform_color;
|
||||||
|
|
||||||
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);
|
color.rgb = vec3(0.7, 0.7, 1.0);
|
||||||
alpha = 1.0;
|
color.a = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the fragment is outside the print volume -> use darker color
|
// if the fragment is outside the print volume -> use darker color
|
||||||
@ -70,12 +80,12 @@ void main()
|
|||||||
pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x);
|
pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x);
|
||||||
pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y);
|
pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y);
|
||||||
}
|
}
|
||||||
color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color;
|
color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
if (use_environment_tex)
|
if (use_environment_tex)
|
||||||
out_color = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha);
|
out_color = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
out_color = vec4(vec3(intensity.y) + color * intensity.x, alpha);
|
out_color = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ uniform SlopeDetection slope;
|
|||||||
uniform vec2 z_range;
|
uniform vec2 z_range;
|
||||||
// Clipping plane - general orientation. Used by the SLA gizmo.
|
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||||
uniform vec4 clipping_plane;
|
uniform vec4 clipping_plane;
|
||||||
|
// Color clip plane - general orientation. Used by the cut gizmo.
|
||||||
|
uniform vec4 color_clip_plane;
|
||||||
|
|
||||||
in vec3 v_position;
|
in vec3 v_position;
|
||||||
in vec3 v_normal;
|
in vec3 v_normal;
|
||||||
@ -43,6 +45,7 @@ in vec3 v_normal;
|
|||||||
out vec2 intensity;
|
out vec2 intensity;
|
||||||
|
|
||||||
out vec3 clipping_planes_dots;
|
out vec3 clipping_planes_dots;
|
||||||
|
out float color_clip_plane_dot;
|
||||||
|
|
||||||
out vec4 world_pos;
|
out vec4 world_pos;
|
||||||
out float world_normal_z;
|
out float world_normal_z;
|
||||||
@ -74,4 +77,5 @@ void main()
|
|||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
|
// 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);
|
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||||
|
color_clip_plane_dot = dot(world_pos, color_clip_plane);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,9 @@ struct SlopeDetection
|
|||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
uniform bool use_color_clip_plane;
|
||||||
|
uniform vec4 uniform_color_clip_plane_1;
|
||||||
|
uniform vec4 uniform_color_clip_plane_2;
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
@ -36,6 +39,7 @@ uniform SlopeDetection slope;
|
|||||||
uniform PrintVolumeDetection print_volume;
|
uniform PrintVolumeDetection print_volume;
|
||||||
|
|
||||||
varying vec3 clipping_planes_dots;
|
varying vec3 clipping_planes_dots;
|
||||||
|
varying float color_clip_plane_dot;
|
||||||
|
|
||||||
// x = diffuse, y = specular;
|
// x = diffuse, y = specular;
|
||||||
varying vec2 intensity;
|
varying vec2 intensity;
|
||||||
@ -48,12 +52,18 @@ void main()
|
|||||||
{
|
{
|
||||||
if (any(lessThan(clipping_planes_dots, ZERO)))
|
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||||
discard;
|
discard;
|
||||||
vec3 color = uniform_color.rgb;
|
|
||||||
float alpha = uniform_color.a;
|
vec4 color;
|
||||||
|
if (use_color_clip_plane) {
|
||||||
|
color.rgb = (color_clip_plane_dot < 0.0) ? uniform_color_clip_plane_1.rgb : uniform_color_clip_plane_2.rgb;
|
||||||
|
color.a = uniform_color.a;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
color = uniform_color;
|
||||||
|
|
||||||
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);
|
color.rgb = vec3(0.7, 0.7, 1.0);
|
||||||
alpha = 1.0;
|
color.a = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the fragment is outside the print volume -> use darker color
|
// if the fragment is outside the print volume -> use darker color
|
||||||
@ -70,12 +80,12 @@ void main()
|
|||||||
pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x);
|
pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x);
|
||||||
pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y);
|
pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y);
|
||||||
}
|
}
|
||||||
color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color;
|
color.rgb = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color.rgb, ZERO, 0.3333) : color.rgb;
|
||||||
|
|
||||||
#ifdef ENABLE_ENVIRONMENT_MAP
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
if (use_environment_tex)
|
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);
|
gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha);
|
gl_FragColor = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ uniform SlopeDetection slope;
|
|||||||
uniform vec2 z_range;
|
uniform vec2 z_range;
|
||||||
// Clipping plane - general orientation. Used by the SLA gizmo.
|
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||||
uniform vec4 clipping_plane;
|
uniform vec4 clipping_plane;
|
||||||
|
// Color clip plane - general orientation. Used by the cut gizmo.
|
||||||
|
uniform vec4 color_clip_plane;
|
||||||
|
|
||||||
attribute vec3 v_position;
|
attribute vec3 v_position;
|
||||||
attribute vec3 v_normal;
|
attribute vec3 v_normal;
|
||||||
@ -43,6 +45,7 @@ attribute vec3 v_normal;
|
|||||||
varying vec2 intensity;
|
varying vec2 intensity;
|
||||||
|
|
||||||
varying vec3 clipping_planes_dots;
|
varying vec3 clipping_planes_dots;
|
||||||
|
varying float color_clip_plane_dot;
|
||||||
|
|
||||||
varying vec4 world_pos;
|
varying vec4 world_pos;
|
||||||
varying float world_normal_z;
|
varying float world_normal_z;
|
||||||
@ -74,4 +77,5 @@ void main()
|
|||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
|
// 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);
|
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||||
|
color_clip_plane_dot = dot(world_pos, color_clip_plane);
|
||||||
}
|
}
|
||||||
|
@ -1194,7 +1194,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
m_placeholder_parser.set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
m_placeholder_parser.set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||||
|
|
||||||
std::vector<unsigned char> is_extruder_used(print.config().nozzle_diameter.size(), 0);
|
std::vector<unsigned char> is_extruder_used(print.config().nozzle_diameter.size(), 0);
|
||||||
for (unsigned int extruder_id : print.extruders())
|
for (unsigned int extruder_id : tool_ordering.all_extruders())
|
||||||
is_extruder_used[extruder_id] = true;
|
is_extruder_used[extruder_id] = true;
|
||||||
m_placeholder_parser.set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
|
m_placeholder_parser.set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
|
||||||
}
|
}
|
||||||
@ -2793,8 +2793,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
acceleration = m_config.first_layer_acceleration_over_raft.value;
|
acceleration = m_config.first_layer_acceleration_over_raft.value;
|
||||||
} else if (m_config.bridge_acceleration.value > 0 && path.role().is_bridge()) {
|
} else if (m_config.bridge_acceleration.value > 0 && path.role().is_bridge()) {
|
||||||
acceleration = m_config.bridge_acceleration.value;
|
acceleration = m_config.bridge_acceleration.value;
|
||||||
|
} else if (m_config.top_solid_infill_acceleration > 0 && path.role() == ExtrusionRole::TopSolidInfill) {
|
||||||
|
acceleration = m_config.top_solid_infill_acceleration.value;
|
||||||
|
} else if (m_config.solid_infill_acceleration > 0 && path.role().is_solid_infill()) {
|
||||||
|
acceleration = m_config.solid_infill_acceleration.value;
|
||||||
} else if (m_config.infill_acceleration.value > 0 && path.role().is_infill()) {
|
} else if (m_config.infill_acceleration.value > 0 && path.role().is_infill()) {
|
||||||
acceleration = m_config.infill_acceleration.value;
|
acceleration = m_config.infill_acceleration.value;
|
||||||
|
} else if (m_config.external_perimeter_acceleration > 0 && path.role().is_external_perimeter()) {
|
||||||
|
acceleration = m_config.external_perimeter_acceleration.value;
|
||||||
} else if (m_config.perimeter_acceleration.value > 0 && path.role().is_perimeter()) {
|
} else if (m_config.perimeter_acceleration.value > 0 && path.role().is_perimeter()) {
|
||||||
acceleration = m_config.perimeter_acceleration.value;
|
acceleration = m_config.perimeter_acceleration.value;
|
||||||
} else {
|
} else {
|
||||||
|
@ -720,28 +720,26 @@ void Transformation::reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
|
void Transformation::reset_rotation()
|
||||||
|
{
|
||||||
|
const Geometry::TransformationSVD svd(*this);
|
||||||
|
m_matrix = get_offset_matrix() * Transform3d(svd.v * svd.s * svd.v.transpose()) * svd.mirror_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transformation::reset_scaling_factor()
|
||||||
|
{
|
||||||
|
const Geometry::TransformationSVD svd(*this);
|
||||||
|
m_matrix = get_offset_matrix() * Transform3d(svd.u) * Transform3d(svd.v.transpose()) * svd.mirror_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
void Transformation::reset_skew()
|
void Transformation::reset_skew()
|
||||||
{
|
{
|
||||||
Matrix3d rotation;
|
auto new_scale_factor = [](const Matrix3d& s) {
|
||||||
Matrix3d scale;
|
return pow(s(0, 0) * s(1, 1) * s(2, 2), 1. / 3.); // scale average
|
||||||
m_matrix.computeRotationScaling(&rotation, &scale);
|
};
|
||||||
|
|
||||||
const double average_scale = std::cbrt(scale(0, 0) * scale(1, 1) * scale(2, 2));
|
const Geometry::TransformationSVD svd(*this);
|
||||||
|
m_matrix = get_offset_matrix() * Transform3d(svd.u) * scale_transform(new_scale_factor(svd.s)) * Transform3d(svd.v.transpose()) * svd.mirror_matrix();
|
||||||
scale(0, 0) = is_left_handed() ? -average_scale : average_scale;
|
|
||||||
scale(1, 1) = average_scale;
|
|
||||||
scale(2, 2) = average_scale;
|
|
||||||
|
|
||||||
scale(0, 1) = 0.0;
|
|
||||||
scale(0, 2) = 0.0;
|
|
||||||
scale(1, 0) = 0.0;
|
|
||||||
scale(1, 2) = 0.0;
|
|
||||||
scale(2, 0) = 0.0;
|
|
||||||
scale(2, 1) = 0.0;
|
|
||||||
|
|
||||||
const Vec3d offset = get_offset();
|
|
||||||
m_matrix = rotation * scale;
|
|
||||||
m_matrix.translation() = offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform3d Transformation::get_matrix_no_offset() const
|
Transform3d Transformation::get_matrix_no_offset() const
|
||||||
@ -838,6 +836,43 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
|
|||||||
}
|
}
|
||||||
#endif // !ENABLE_WORLD_COORDINATE
|
#endif // !ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
|
#if ENABLE_WORLD_COORDINATE
|
||||||
|
TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||||
|
{
|
||||||
|
const auto &m0 = trafo.matrix().block<3, 3>(0, 0);
|
||||||
|
mirror = m0.determinant() < 0.0;
|
||||||
|
|
||||||
|
Matrix3d m;
|
||||||
|
if (mirror)
|
||||||
|
m = m0 * Eigen::DiagonalMatrix<double, 3, 3>(-1.0, 1.0, 1.0);
|
||||||
|
else
|
||||||
|
m = m0;
|
||||||
|
const Eigen::JacobiSVD<Matrix3d> svd(m, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||||
|
u = svd.matrixU();
|
||||||
|
v = svd.matrixV();
|
||||||
|
s = svd.singularValues().asDiagonal();
|
||||||
|
|
||||||
|
scale = !s.isApprox(Matrix3d::Identity());
|
||||||
|
anisotropic_scale = ! is_approx(s(0, 0), s(1, 1)) || ! is_approx(s(1, 1), s(2, 2));
|
||||||
|
rotation = !v.isApprox(u);
|
||||||
|
|
||||||
|
if (anisotropic_scale) {
|
||||||
|
rotation_90_degrees = true;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
const Vec3d row = v.row(i).cwiseAbs();
|
||||||
|
size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
||||||
|
size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
||||||
|
if (num_zeros != 2 || num_ones != 1) {
|
||||||
|
rotation_90_degrees = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
skew = ! rotation_90_degrees;
|
||||||
|
} else
|
||||||
|
skew = false;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
// For parsing a transformation matrix from 3MF / AMF.
|
// For parsing a transformation matrix from 3MF / AMF.
|
||||||
Transform3d transform3d_from_string(const std::string& transform_str)
|
Transform3d transform3d_from_string(const std::string& transform_str)
|
||||||
{
|
{
|
||||||
|
@ -492,8 +492,8 @@ public:
|
|||||||
void reset();
|
void reset();
|
||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
void reset_offset() { set_offset(Vec3d::Zero()); }
|
void reset_offset() { set_offset(Vec3d::Zero()); }
|
||||||
void reset_rotation() { set_rotation(Vec3d::Zero()); }
|
void reset_rotation();
|
||||||
void reset_scaling_factor() { set_scaling_factor(Vec3d::Ones()); }
|
void reset_scaling_factor();
|
||||||
void reset_mirror() { set_mirror(Vec3d::Ones()); }
|
void reset_mirror() { set_mirror(Vec3d::Ones()); }
|
||||||
void reset_skew();
|
void reset_skew();
|
||||||
|
|
||||||
@ -538,6 +538,27 @@ private:
|
|||||||
#endif // ENABLE_WORLD_COORDINATE
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_WORLD_COORDINATE
|
||||||
|
struct TransformationSVD
|
||||||
|
{
|
||||||
|
Matrix3d u = Matrix3d::Identity();
|
||||||
|
Matrix3d s = Matrix3d::Identity();
|
||||||
|
Matrix3d v = Matrix3d::Identity();
|
||||||
|
|
||||||
|
bool mirror{ false };
|
||||||
|
bool scale{ false };
|
||||||
|
bool anisotropic_scale{ false };
|
||||||
|
bool rotation{ false };
|
||||||
|
bool rotation_90_degrees{ false };
|
||||||
|
bool skew{ false };
|
||||||
|
|
||||||
|
explicit TransformationSVD(const Transformation& trafo) : TransformationSVD(trafo.get_matrix()) {}
|
||||||
|
explicit TransformationSVD(const Transform3d& trafo);
|
||||||
|
|
||||||
|
Eigen::DiagonalMatrix<double, 3, 3> mirror_matrix() const { return Eigen::DiagonalMatrix<double, 3, 3>(this->mirror ? -1. : 1., 1., 1.); }
|
||||||
|
};
|
||||||
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
// For parsing a transformation matrix from 3MF / AMF.
|
// For parsing a transformation matrix from 3MF / AMF.
|
||||||
extern Transform3d transform3d_from_string(const std::string& transform_str);
|
extern Transform3d transform3d_from_string(const std::string& transform_str);
|
||||||
|
|
||||||
|
@ -127,9 +127,7 @@ static void connect_layer_slices(
|
|||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
auto assert_intersection_valid = [this](int i, int j) {
|
auto assert_intersection_valid = [this](int i, int j) {
|
||||||
assert(i != j);
|
assert(i < j);
|
||||||
if (i > j)
|
|
||||||
std::swap(i, j);
|
|
||||||
assert(i >= m_offset_below);
|
assert(i >= m_offset_below);
|
||||||
assert(i < m_offset_above);
|
assert(i < m_offset_above);
|
||||||
assert(j >= m_offset_above);
|
assert(j >= m_offset_above);
|
||||||
@ -140,35 +138,47 @@ static void connect_layer_slices(
|
|||||||
if (polynode.Contour.size() >= 3) {
|
if (polynode.Contour.size() >= 3) {
|
||||||
// If there is an intersection point, it should indicate which contours (one from layer below, the other from layer above) intersect.
|
// If there is an intersection point, it should indicate which contours (one from layer below, the other from layer above) intersect.
|
||||||
// Otherwise the contour is fully inside another contour.
|
// Otherwise the contour is fully inside another contour.
|
||||||
int32_t i = 0, j = 0;
|
int32_t i = -1, j = -1;
|
||||||
for (int icontour = 0; icontour <= polynode.ChildCount(); ++ icontour) {
|
for (int icontour = 0; icontour <= polynode.ChildCount(); ++ icontour) {
|
||||||
const bool first = icontour == 0;
|
const ClipperLib_Z::Path &contour = icontour == 0 ? polynode.Contour : polynode.Childs[icontour - 1]->Contour;
|
||||||
const ClipperLib_Z::Path &contour = first ? polynode.Contour : polynode.Childs[icontour - 1]->Contour;
|
|
||||||
if (contour.size() >= 3) {
|
if (contour.size() >= 3) {
|
||||||
if (first) {
|
|
||||||
i = contour.front().z();
|
|
||||||
j = i;
|
|
||||||
if (i < 0) {
|
|
||||||
std::tie(i, j) = m_intersections[-i - 1];
|
|
||||||
assert(assert_intersection_valid(i, j));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const ClipperLib_Z::IntPoint &pt : contour) {
|
for (const ClipperLib_Z::IntPoint &pt : contour) {
|
||||||
j = pt.z();
|
j = pt.z();
|
||||||
if (j < 0) {
|
if (j < 0) {
|
||||||
|
const auto &intersection = m_intersections[-j - 1];
|
||||||
|
assert(intersection.first <= intersection.second);
|
||||||
|
if (intersection.second < m_offset_above) {
|
||||||
|
// Ignore intersection of polygons on the 1st layer.
|
||||||
|
assert(intersection.first >= m_offset_below);
|
||||||
|
j = i;
|
||||||
|
} else if (intersection.first >= m_offset_above) {
|
||||||
|
// Ignore intersection of polygons on the 2nd layer
|
||||||
|
assert(intersection.second < m_offset_end);
|
||||||
|
j = i;
|
||||||
|
} else {
|
||||||
std::tie(i, j) = m_intersections[-j - 1];
|
std::tie(i, j) = m_intersections[-j - 1];
|
||||||
assert(assert_intersection_valid(i, j));
|
assert(assert_intersection_valid(i, j));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (i != j)
|
} else if (i == -1) {
|
||||||
|
// First source contour of this expolygon was found.
|
||||||
|
i = j;
|
||||||
|
} else if (i != j) {
|
||||||
|
// Second source contour of this expolygon was found.
|
||||||
|
if (i > j)
|
||||||
|
std::swap(i, j);
|
||||||
|
assert(assert_intersection_valid(i, j));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
end:
|
end:
|
||||||
bool found = false;
|
bool found = false;
|
||||||
if (i == j) {
|
if (i == -1) {
|
||||||
|
// This should not happen. It may only happen if the source contours had just self intersections or intersections with contours at the same layer.
|
||||||
|
assert(false);
|
||||||
|
} else if (i == j) {
|
||||||
// The contour is completely inside another contour.
|
// The contour is completely inside another contour.
|
||||||
Point pt(polynode.Contour.front().x(), polynode.Contour.front().y());
|
Point pt(polynode.Contour.front().x(), polynode.Contour.front().y());
|
||||||
if (i < m_offset_above) {
|
if (i < m_offset_above) {
|
||||||
@ -202,8 +212,6 @@ static void connect_layer_slices(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(assert_intersection_valid(i, j));
|
assert(assert_intersection_valid(i, j));
|
||||||
if (i > j)
|
|
||||||
std::swap(i, j);
|
|
||||||
i -= m_offset_below;
|
i -= m_offset_below;
|
||||||
j -= m_offset_above;
|
j -= m_offset_above;
|
||||||
assert(i >= 0 && i < m_below.lslices_ex.size());
|
assert(i >= 0 && i < m_below.lslices_ex.size());
|
||||||
|
@ -1305,7 +1305,9 @@ void ModelObject::synchronize_model_after_cut()
|
|||||||
void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes)
|
void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes)
|
||||||
{
|
{
|
||||||
// we don't save cut information, if result will not contains all parts of initial object
|
// we don't save cut information, if result will not contains all parts of initial object
|
||||||
if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || !attributes.has(ModelObjectCutAttribute::KeepLower))
|
if (!attributes.has(ModelObjectCutAttribute::KeepUpper) ||
|
||||||
|
!attributes.has(ModelObjectCutAttribute::KeepLower) ||
|
||||||
|
attributes.has(ModelObjectCutAttribute::InvalidateCutInfo))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cut_id.id().invalid())
|
if (cut_id.id().invalid())
|
||||||
@ -1425,7 +1427,7 @@ void ModelObject::process_modifier_cut(ModelVolume* volume, const Transform3d& i
|
|||||||
lower->add_volume(*volume);
|
lower->add_volume(*volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix)
|
static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix, const std::string& suffix = {})
|
||||||
{
|
{
|
||||||
if (mesh.empty())
|
if (mesh.empty())
|
||||||
return;
|
return;
|
||||||
@ -1433,7 +1435,7 @@ static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelV
|
|||||||
mesh.transform(cut_matrix);
|
mesh.transform(cut_matrix);
|
||||||
ModelVolume* vol = object->add_volume(mesh);
|
ModelVolume* vol = object->add_volume(mesh);
|
||||||
|
|
||||||
vol->name = src_volume->name;
|
vol->name = src_volume->name + suffix;
|
||||||
// Don't copy the config's ID.
|
// Don't copy the config's ID.
|
||||||
vol->config.assign_config(src_volume->config);
|
vol->config.assign_config(src_volume->config);
|
||||||
assert(vol->config.id().valid());
|
assert(vol->config.id().valid());
|
||||||
@ -1477,6 +1479,12 @@ void ModelObject::process_solid_part_cut(ModelVolume* volume, const Transform3d&
|
|||||||
|
|
||||||
// Add required cut parts to the objects
|
// Add required cut parts to the objects
|
||||||
|
|
||||||
|
if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) {
|
||||||
|
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A");
|
||||||
|
add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper))
|
if (attributes.has(ModelObjectCutAttribute::KeepUpper))
|
||||||
add_cut_volume(upper_mesh, upper, volume, cut_matrix);
|
add_cut_volume(upper_mesh, upper, volume, cut_matrix);
|
||||||
|
|
||||||
@ -1560,7 +1568,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix,
|
|||||||
clone_for_cut(&upper);
|
clone_for_cut(&upper);
|
||||||
|
|
||||||
ModelObject* lower{ nullptr };
|
ModelObject* lower{ nullptr };
|
||||||
if (attributes.has(ModelObjectCutAttribute::KeepLower))
|
if (attributes.has(ModelObjectCutAttribute::KeepLower) && !attributes.has(ModelObjectCutAttribute::KeepAsParts))
|
||||||
clone_for_cut(&lower);
|
clone_for_cut(&lower);
|
||||||
|
|
||||||
std::vector<ModelObject*> dowels;
|
std::vector<ModelObject*> dowels;
|
||||||
@ -1608,6 +1616,11 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix,
|
|||||||
|
|
||||||
ModelObjectPtrs res;
|
ModelObjectPtrs res;
|
||||||
|
|
||||||
|
if (attributes.has(ModelObjectCutAttribute::KeepAsParts) && !upper->volumes.empty()) {
|
||||||
|
reset_instance_transformation(upper, instance, cut_matrix);
|
||||||
|
res.push_back(upper);
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper->volumes.empty()) {
|
if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper->volumes.empty()) {
|
||||||
invalidate_translations(upper, instances[instance]);
|
invalidate_translations(upper, instances[instance]);
|
||||||
|
|
||||||
@ -1638,6 +1651,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix,
|
|||||||
res.push_back(dowel);
|
res.push_back(dowel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
|
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ enum class ModelVolumeType : int {
|
|||||||
SUPPORT_ENFORCER,
|
SUPPORT_ENFORCER,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels };
|
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo };
|
||||||
using ModelObjectCutAttributes = enum_bitmask<ModelObjectCutAttribute>;
|
using ModelObjectCutAttributes = enum_bitmask<ModelObjectCutAttribute>;
|
||||||
ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute);
|
ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute);
|
||||||
|
|
||||||
|
@ -443,6 +443,7 @@ static std::vector<std::string> s_Preset_print_options {
|
|||||||
"enable_dynamic_overhang_speeds", "dynamic_overhang_speeds", "overhang_overlap_levels",
|
"enable_dynamic_overhang_speeds", "dynamic_overhang_speeds", "overhang_overlap_levels",
|
||||||
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
||||||
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
|
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
|
||||||
|
"external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration",
|
||||||
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
||||||
"min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
"min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
||||||
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
|
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
|
||||||
@ -457,7 +458,7 @@ static std::vector<std::string> s_Preset_print_options {
|
|||||||
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
||||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
||||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects",
|
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio",
|
||||||
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||||
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
|
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
|
||||||
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||||
|
@ -74,6 +74,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
|||||||
"duplicate_distance",
|
"duplicate_distance",
|
||||||
"end_gcode",
|
"end_gcode",
|
||||||
"end_filament_gcode",
|
"end_filament_gcode",
|
||||||
|
"external_perimeter_acceleration",
|
||||||
"extrusion_axis",
|
"extrusion_axis",
|
||||||
"extruder_clearance_height",
|
"extruder_clearance_height",
|
||||||
"extruder_clearance_radius",
|
"extruder_clearance_radius",
|
||||||
@ -125,10 +126,12 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
|||||||
"retract_speed",
|
"retract_speed",
|
||||||
"single_extruder_multi_material_priming",
|
"single_extruder_multi_material_priming",
|
||||||
"slowdown_below_layer_time",
|
"slowdown_below_layer_time",
|
||||||
|
"solid_infill_acceleration",
|
||||||
"standby_temperature_delta",
|
"standby_temperature_delta",
|
||||||
"start_gcode",
|
"start_gcode",
|
||||||
"start_filament_gcode",
|
"start_filament_gcode",
|
||||||
"toolchange_gcode",
|
"toolchange_gcode",
|
||||||
|
"top_solid_infill_acceleration",
|
||||||
"thumbnails",
|
"thumbnails",
|
||||||
"thumbnails_format",
|
"thumbnails_format",
|
||||||
"use_firmware_retraction",
|
"use_firmware_retraction",
|
||||||
|
@ -598,14 +598,6 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloat(0.f));
|
def->set_default_value(new ConfigOptionFloat(0.f));
|
||||||
|
|
||||||
def = this->add("clip_multipart_objects", coBool);
|
|
||||||
def->label = L("Clip multi-part objects");
|
|
||||||
def->tooltip = L("When printing multi-material objects, this settings will make Slic3r "
|
|
||||||
"to clip the overlapping object parts one by the other "
|
|
||||||
"(2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc).");
|
|
||||||
def->mode = comExpert;
|
|
||||||
def->set_default_value(new ConfigOptionBool(true));
|
|
||||||
|
|
||||||
def = this->add("colorprint_heights", coFloats);
|
def = this->add("colorprint_heights", coFloats);
|
||||||
def->label = L("Colorprint height");
|
def->label = L("Colorprint height");
|
||||||
def->tooltip = L("Heights at which a filament change is to occur.");
|
def->tooltip = L("Heights at which a filament change is to occur.");
|
||||||
@ -1404,6 +1396,25 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comExpert;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionFloat(0));
|
def->set_default_value(new ConfigOptionFloat(0));
|
||||||
|
|
||||||
|
def = this->add("solid_infill_acceleration", coFloat);
|
||||||
|
def->label = L("Solid infill");
|
||||||
|
def->tooltip = L("This is the acceleration your printer will use for solid infill. Set zero to use "
|
||||||
|
"the value for infill.");
|
||||||
|
def->sidetext = L("mm/s²");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0));
|
||||||
|
|
||||||
|
def = this->add("top_solid_infill_acceleration", coFloat);
|
||||||
|
def->label = L("Top solid infill");
|
||||||
|
def->tooltip = L("This is the acceleration your printer will use for top solid infill. Set zero to use "
|
||||||
|
"the value for solid infill.");
|
||||||
|
def->sidetext = L("mm/s²");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0));
|
||||||
|
|
||||||
|
|
||||||
def = this->add("infill_every_layers", coInt);
|
def = this->add("infill_every_layers", coInt);
|
||||||
def->label = L("Combine infill every");
|
def->label = L("Combine infill every");
|
||||||
def->category = L("Infill");
|
def->category = L("Infill");
|
||||||
@ -1950,6 +1961,14 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comExpert;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionFloat(0));
|
def->set_default_value(new ConfigOptionFloat(0));
|
||||||
|
|
||||||
|
def = this->add("external_perimeter_acceleration", coFloat);
|
||||||
|
def->label = L("External perimeters");
|
||||||
|
def->tooltip = L("This is the acceleration your printer will use for external perimeters. "
|
||||||
|
"Set zero to use the value for perimeters.");
|
||||||
|
def->sidetext = L("mm/s²");
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0));
|
||||||
|
|
||||||
def = this->add("perimeter_extruder", coInt);
|
def = this->add("perimeter_extruder", coInt);
|
||||||
def->label = L("Perimeter extruder");
|
def->label = L("Perimeter extruder");
|
||||||
def->category = L("Extruders");
|
def->category = L("Extruders");
|
||||||
@ -4025,6 +4044,22 @@ void PrintConfigDef::init_sla_params()
|
|||||||
def->set_default_value(new ConfigOptionFloat(0.001));
|
def->set_default_value(new ConfigOptionFloat(0.001));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore the following obsolete configuration keys:
|
||||||
|
static std::set<std::string> PrintConfigDef_ignore = {
|
||||||
|
"clip_multipart_objects",
|
||||||
|
"duplicate_x", "duplicate_y", "gcode_arcs", "multiply_x", "multiply_y",
|
||||||
|
"support_material_tool", "acceleration", "adjust_overhang_flow",
|
||||||
|
"standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid",
|
||||||
|
"start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start",
|
||||||
|
"seal_position", "vibration_limit", "bed_size",
|
||||||
|
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe",
|
||||||
|
"serial_port", "serial_speed",
|
||||||
|
// Introduced in some PrusaSlicer 2.3.1 alpha, later renamed or removed.
|
||||||
|
"fuzzy_skin_perimeter_mode", "fuzzy_skin_shape",
|
||||||
|
// Introduced in PrusaSlicer 2.3.0-alpha2, later replaced by automatic calculation based on extrusion width.
|
||||||
|
"wall_add_middle_threshold", "wall_split_middle_threshold",
|
||||||
|
};
|
||||||
|
|
||||||
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
|
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
|
||||||
{
|
{
|
||||||
// handle legacy options
|
// handle legacy options
|
||||||
@ -4098,32 +4133,17 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// Ignore the following obsolete configuration keys:
|
|
||||||
static std::set<std::string> ignore = {
|
|
||||||
"duplicate_x", "duplicate_y", "gcode_arcs", "multiply_x", "multiply_y",
|
|
||||||
"support_material_tool", "acceleration", "adjust_overhang_flow",
|
|
||||||
"standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid",
|
|
||||||
"start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start",
|
|
||||||
"seal_position", "vibration_limit", "bed_size",
|
|
||||||
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe",
|
|
||||||
"serial_port", "serial_speed",
|
|
||||||
// Introduced in some PrusaSlicer 2.3.1 alpha, later renamed or removed.
|
|
||||||
"fuzzy_skin_perimeter_mode", "fuzzy_skin_shape",
|
|
||||||
// Introduced in PrusaSlicer 2.3.0-alpha2, later replaced by automatic calculation based on extrusion width.
|
|
||||||
"wall_add_middle_threshold", "wall_split_middle_threshold",
|
|
||||||
};
|
|
||||||
|
|
||||||
// In PrusaSlicer 2.3.0-alpha0 the "monotonous" infill was introduced, which was later renamed to "monotonic".
|
// In PrusaSlicer 2.3.0-alpha0 the "monotonous" infill was introduced, which was later renamed to "monotonic".
|
||||||
if (value == "monotonous" && (opt_key == "top_fill_pattern" || opt_key == "bottom_fill_pattern" || opt_key == "fill_pattern"))
|
if (value == "monotonous" && (opt_key == "top_fill_pattern" || opt_key == "bottom_fill_pattern" || opt_key == "fill_pattern"))
|
||||||
value = "monotonic";
|
value = "monotonic";
|
||||||
|
|
||||||
if (ignore.find(opt_key) != ignore.end()) {
|
if (PrintConfigDef_ignore.find(opt_key) != PrintConfigDef_ignore.end()) {
|
||||||
opt_key = "";
|
opt_key = {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! print_config_def.has(opt_key)) {
|
if (! print_config_def.has(opt_key)) {
|
||||||
opt_key = "";
|
opt_key = {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,7 +487,6 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||||||
((ConfigOptionFloat, brim_separation))
|
((ConfigOptionFloat, brim_separation))
|
||||||
((ConfigOptionEnum<BrimType>, brim_type))
|
((ConfigOptionEnum<BrimType>, brim_type))
|
||||||
((ConfigOptionFloat, brim_width))
|
((ConfigOptionFloat, brim_width))
|
||||||
((ConfigOptionBool, clip_multipart_objects))
|
|
||||||
((ConfigOptionBool, dont_support_bridges))
|
((ConfigOptionBool, dont_support_bridges))
|
||||||
((ConfigOptionFloat, elefant_foot_compensation))
|
((ConfigOptionFloat, elefant_foot_compensation))
|
||||||
((ConfigOptionFloatOrPercent, extrusion_width))
|
((ConfigOptionFloatOrPercent, extrusion_width))
|
||||||
@ -755,6 +754,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
|||||||
((ConfigOptionInts, disable_fan_first_layers))
|
((ConfigOptionInts, disable_fan_first_layers))
|
||||||
((ConfigOptionEnum<DraftShield>, draft_shield))
|
((ConfigOptionEnum<DraftShield>, draft_shield))
|
||||||
((ConfigOptionFloat, duplicate_distance))
|
((ConfigOptionFloat, duplicate_distance))
|
||||||
|
((ConfigOptionFloat, external_perimeter_acceleration))
|
||||||
((ConfigOptionFloat, extruder_clearance_height))
|
((ConfigOptionFloat, extruder_clearance_height))
|
||||||
((ConfigOptionFloat, extruder_clearance_radius))
|
((ConfigOptionFloat, extruder_clearance_radius))
|
||||||
((ConfigOptionStrings, extruder_colour))
|
((ConfigOptionStrings, extruder_colour))
|
||||||
@ -797,12 +797,14 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
|||||||
((ConfigOptionInt, skirt_height))
|
((ConfigOptionInt, skirt_height))
|
||||||
((ConfigOptionInt, skirts))
|
((ConfigOptionInt, skirts))
|
||||||
((ConfigOptionInts, slowdown_below_layer_time))
|
((ConfigOptionInts, slowdown_below_layer_time))
|
||||||
|
((ConfigOptionFloat, solid_infill_acceleration))
|
||||||
((ConfigOptionBool, spiral_vase))
|
((ConfigOptionBool, spiral_vase))
|
||||||
((ConfigOptionInt, standby_temperature_delta))
|
((ConfigOptionInt, standby_temperature_delta))
|
||||||
((ConfigOptionInts, temperature))
|
((ConfigOptionInts, temperature))
|
||||||
((ConfigOptionInt, threads))
|
((ConfigOptionInt, threads))
|
||||||
((ConfigOptionPoints, thumbnails))
|
((ConfigOptionPoints, thumbnails))
|
||||||
((ConfigOptionEnum<GCodeThumbnailsFormat>, thumbnails_format))
|
((ConfigOptionEnum<GCodeThumbnailsFormat>, thumbnails_format))
|
||||||
|
((ConfigOptionFloat, top_solid_infill_acceleration))
|
||||||
((ConfigOptionBools, wipe))
|
((ConfigOptionBools, wipe))
|
||||||
((ConfigOptionBool, wipe_tower))
|
((ConfigOptionBool, wipe_tower))
|
||||||
((ConfigOptionFloat, wipe_tower_x))
|
((ConfigOptionFloat, wipe_tower_x))
|
||||||
|
@ -620,8 +620,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||||||
|| opt_key == "slicing_mode") {
|
|| opt_key == "slicing_mode") {
|
||||||
steps.emplace_back(posSlice);
|
steps.emplace_back(posSlice);
|
||||||
} else if (
|
} else if (
|
||||||
opt_key == "clip_multipart_objects"
|
opt_key == "elefant_foot_compensation"
|
||||||
|| opt_key == "elefant_foot_compensation"
|
|
||||||
|| opt_key == "support_material_contact_distance"
|
|| opt_key == "support_material_contact_distance"
|
||||||
|| opt_key == "xy_size_compensation") {
|
|| opt_key == "xy_size_compensation") {
|
||||||
steps.emplace_back(posSlice);
|
steps.emplace_back(posSlice);
|
||||||
|
@ -237,9 +237,6 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
|
|||||||
const PrintObjectRegions &print_object_regions,
|
const PrintObjectRegions &print_object_regions,
|
||||||
const std::vector<float> &zs,
|
const std::vector<float> &zs,
|
||||||
std::vector<VolumeSlices> &&volume_slices,
|
std::vector<VolumeSlices> &&volume_slices,
|
||||||
// If clipping is disabled, then ExPolygons produced by different volumes will never be merged, thus they will be allowed to overlap.
|
|
||||||
// It is up to the model designer to handle these overlaps.
|
|
||||||
const bool clip_multipart_objects,
|
|
||||||
const std::function<void()> &throw_on_cancel_callback)
|
const std::function<void()> &throw_on_cancel_callback)
|
||||||
{
|
{
|
||||||
model_volumes_sort_by_id(model_volumes);
|
model_volumes_sort_by_id(model_volumes);
|
||||||
@ -308,7 +305,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
|
|||||||
}
|
}
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<size_t>(0, zs_complex.size()),
|
tbb::blocked_range<size_t>(0, zs_complex.size()),
|
||||||
[&slices_by_region, &print_object_regions, &zs_complex, &layer_ranges_regions_to_slices, clip_multipart_objects, &throw_on_cancel_callback]
|
[&slices_by_region, &print_object_regions, &zs_complex, &layer_ranges_regions_to_slices, &throw_on_cancel_callback]
|
||||||
(const tbb::blocked_range<size_t> &range) {
|
(const tbb::blocked_range<size_t> &range) {
|
||||||
float z = zs_complex[range.begin()].second;
|
float z = zs_complex[range.begin()].second;
|
||||||
auto it_layer_range = layer_range_first(print_object_regions.layer_ranges, z);
|
auto it_layer_range = layer_range_first(print_object_regions.layer_ranges, z);
|
||||||
@ -359,7 +356,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
|
|||||||
if (next_region_same_modifier)
|
if (next_region_same_modifier)
|
||||||
// To be used in the following iteration.
|
// To be used in the following iteration.
|
||||||
temp_slices[idx_region + 1].expolygons = std::move(source);
|
temp_slices[idx_region + 1].expolygons = std::move(source);
|
||||||
} else if ((region.model_volume->is_model_part() && clip_multipart_objects) || region.model_volume->is_negative_volume()) {
|
} else if (region.model_volume->is_model_part() || region.model_volume->is_negative_volume()) {
|
||||||
// Clip every non-zero region preceding it.
|
// Clip every non-zero region preceding it.
|
||||||
for (int idx_region2 = 0; idx_region2 < idx_region; ++ idx_region2)
|
for (int idx_region2 = 0; idx_region2 < idx_region; ++ idx_region2)
|
||||||
if (! temp_slices[idx_region2].expolygons.empty()) {
|
if (! temp_slices[idx_region2].expolygons.empty()) {
|
||||||
@ -388,10 +385,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
|
|||||||
merged = true;
|
merged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Don't unite the regions if ! clip_multipart_objects. In that case it is user's responsibility
|
if (merged)
|
||||||
// to handle region overlaps. Indeed, one may intentionally let the regions overlap to produce crossing perimeters
|
|
||||||
// for example.
|
|
||||||
if (merged && clip_multipart_objects)
|
|
||||||
expolygons = closing_ex(expolygons, float(scale_(EPSILON)));
|
expolygons = closing_ex(expolygons, float(scale_(EPSILON)));
|
||||||
slices_by_region[temp_slices[i].region_id][z_idx] = std::move(expolygons);
|
slices_by_region[temp_slices[i].region_id][z_idx] = std::move(expolygons);
|
||||||
i = j;
|
i = j;
|
||||||
@ -696,7 +690,6 @@ void PrintObject::slice_volumes()
|
|||||||
slice_volumes_inner(
|
slice_volumes_inner(
|
||||||
print->config(), this->config(), this->trafo_centered(),
|
print->config(), this->config(), this->trafo_centered(),
|
||||||
this->model_object()->volumes, m_shared_regions->layer_ranges, slice_zs, throw_on_cancel_callback),
|
this->model_object()->volumes, m_shared_regions->layer_ranges, slice_zs, throw_on_cancel_callback),
|
||||||
m_config.clip_multipart_objects,
|
|
||||||
throw_on_cancel_callback);
|
throw_on_cancel_callback);
|
||||||
|
|
||||||
for (size_t region_id = 0; region_id < region_slices.size(); ++ region_id) {
|
for (size_t region_id = 0; region_id < region_slices.size(); ++ region_id) {
|
||||||
|
@ -269,7 +269,8 @@ void set_current_thread_qos()
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// OSX specific: Set Quality of Service to "user initiated", so that the threads will be scheduled to high performance
|
// OSX specific: Set Quality of Service to "user initiated", so that the threads will be scheduled to high performance
|
||||||
// cores if available.
|
// cores if available.
|
||||||
pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
|
// With QOS_CLASS_USER_INITIATED the worker threads drop priority once slicer loses user focus.
|
||||||
|
pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,6 +814,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||||||
|
|
||||||
shader->set_uniform("z_range", m_z_range);
|
shader->set_uniform("z_range", m_z_range);
|
||||||
shader->set_uniform("clipping_plane", m_clipping_plane);
|
shader->set_uniform("clipping_plane", m_clipping_plane);
|
||||||
|
shader->set_uniform("use_color_clip_plane", m_use_color_clip_plane);
|
||||||
|
shader->set_uniform("color_clip_plane", m_color_clip_plane);
|
||||||
|
shader->set_uniform("uniform_color_clip_plane_1", m_color_clip_plane_colors[0]);
|
||||||
|
shader->set_uniform("uniform_color_clip_plane_2", m_color_clip_plane_colors[1]);
|
||||||
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
|
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
|
||||||
shader->set_uniform("print_volume.xy_data", m_print_volume.data);
|
shader->set_uniform("print_volume.xy_data", m_print_volume.data);
|
||||||
shader->set_uniform("print_volume.z_data", m_print_volume.zs);
|
shader->set_uniform("print_volume.z_data", m_print_volume.zs);
|
||||||
|
@ -387,6 +387,12 @@ private:
|
|||||||
// plane coeffs for clipping in shaders
|
// plane coeffs for clipping in shaders
|
||||||
std::array<double, 4> m_clipping_plane;
|
std::array<double, 4> m_clipping_plane;
|
||||||
|
|
||||||
|
// plane coeffs for render volumes with different colors in shaders
|
||||||
|
// used by cut gizmo
|
||||||
|
std::array<double, 4> m_color_clip_plane;
|
||||||
|
bool m_use_color_clip_plane{ false };
|
||||||
|
std::array<ColorRGBA, 2> m_color_clip_plane_colors{ ColorRGBA::RED(), ColorRGBA::BLUE() };
|
||||||
|
|
||||||
struct Slope
|
struct Slope
|
||||||
{
|
{
|
||||||
// toggle for slope rendering
|
// toggle for slope rendering
|
||||||
@ -445,6 +451,14 @@ public:
|
|||||||
const std::array<float, 2>& get_z_range() const { return m_z_range; }
|
const std::array<float, 2>& get_z_range() const { return m_z_range; }
|
||||||
const std::array<double, 4>& get_clipping_plane() const { return m_clipping_plane; }
|
const std::array<double, 4>& get_clipping_plane() const { return m_clipping_plane; }
|
||||||
|
|
||||||
|
void set_use_color_clip_plane(bool use) { m_use_color_clip_plane = use; }
|
||||||
|
void set_color_clip_plane(const Vec3d& cp_normal, double offset) {
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
m_color_clip_plane[i] = -cp_normal[i];
|
||||||
|
m_color_clip_plane[3] = offset;
|
||||||
|
}
|
||||||
|
void set_color_clip_plane_colors(const std::array<ColorRGBA, 2>& colors) { m_color_clip_plane_colors = colors; }
|
||||||
|
|
||||||
bool is_slope_active() const { return m_slope.active; }
|
bool is_slope_active() const { return m_slope.active; }
|
||||||
void set_slope_active(bool active) { m_slope.active = active; }
|
void set_slope_active(bool active) { m_slope.active = active; }
|
||||||
|
|
||||||
|
@ -261,7 +261,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||||||
toggle_field(el, has_top_solid_infill || (has_spiral_vase && has_bottom_solid_infill));
|
toggle_field(el, has_top_solid_infill || (has_spiral_vase && has_bottom_solid_infill));
|
||||||
|
|
||||||
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
|
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
|
||||||
for (auto el : { "perimeter_acceleration", "infill_acceleration",
|
for (auto el : { "perimeter_acceleration", "infill_acceleration", "top_solid_infill_acceleration",
|
||||||
|
"solid_infill_acceleration", "external_perimeter_acceleration"
|
||||||
"bridge_acceleration", "first_layer_acceleration" })
|
"bridge_acceleration", "first_layer_acceleration" })
|
||||||
toggle_field(el, have_default_acceleration);
|
toggle_field(el, have_default_acceleration);
|
||||||
|
|
||||||
|
@ -3175,6 +3175,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
|||||||
|
|
||||||
// apply materials in app_config
|
// apply materials in app_config
|
||||||
for (const std::string& section_name : {AppConfig::SECTION_FILAMENTS, AppConfig::SECTION_MATERIALS})
|
for (const std::string& section_name : {AppConfig::SECTION_FILAMENTS, AppConfig::SECTION_MATERIALS})
|
||||||
|
if (appconfig_new.has_section(section_name))
|
||||||
app_config->set_section(section_name, appconfig_new.get_section(section_name));
|
app_config->set_section(section_name, appconfig_new.get_section(section_name));
|
||||||
|
|
||||||
app_config->set_vendors(appconfig_new);
|
app_config->set_vendors(appconfig_new);
|
||||||
|
@ -3947,8 +3947,8 @@ void GLCanvas3D::update_sequential_clearance()
|
|||||||
// the results are then cached for following displacements
|
// the results are then cached for following displacements
|
||||||
if (m_sequential_print_clearance_first_displacement) {
|
if (m_sequential_print_clearance_first_displacement) {
|
||||||
m_sequential_print_clearance.m_hull_2d_cache.clear();
|
m_sequential_print_clearance.m_hull_2d_cache.clear();
|
||||||
float shrink_factor = static_cast<float>(scale_(0.5 * fff_print()->config().extruder_clearance_radius.value - EPSILON));
|
const float shrink_factor = static_cast<float>(scale_(0.5 * fff_print()->config().extruder_clearance_radius.value - EPSILON));
|
||||||
double mitter_limit = scale_(0.1);
|
const double mitter_limit = scale_(0.1);
|
||||||
m_sequential_print_clearance.m_hull_2d_cache.reserve(m_model->objects.size());
|
m_sequential_print_clearance.m_hull_2d_cache.reserve(m_model->objects.size());
|
||||||
for (size_t i = 0; i < m_model->objects.size(); ++i) {
|
for (size_t i = 0; i < m_model->objects.size(); ++i) {
|
||||||
ModelObject* model_object = m_model->objects[i];
|
ModelObject* model_object = m_model->objects[i];
|
||||||
@ -3956,7 +3956,7 @@ void GLCanvas3D::update_sequential_clearance()
|
|||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
Geometry::Transformation trafo = model_instance0->get_transformation();
|
Geometry::Transformation trafo = model_instance0->get_transformation();
|
||||||
trafo.set_offset({ 0.0, 0.0, model_instance0->get_offset().z() });
|
trafo.set_offset({ 0.0, 0.0, model_instance0->get_offset().z() });
|
||||||
Polygon hull_2d = offset(model_object->convex_hull_2d(trafo.get_matrix()),
|
const Polygon hull_2d = offset(model_object->convex_hull_2d(trafo.get_matrix()),
|
||||||
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
|
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
|
||||||
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
||||||
shrink_factor,
|
shrink_factor,
|
||||||
@ -3984,13 +3984,8 @@ void GLCanvas3D::update_sequential_clearance()
|
|||||||
polygons.reserve(instances_count);
|
polygons.reserve(instances_count);
|
||||||
for (size_t i = 0; i < instance_transforms.size(); ++i) {
|
for (size_t i = 0; i < instance_transforms.size(); ++i) {
|
||||||
const auto& instances = instance_transforms[i];
|
const auto& instances = instance_transforms[i];
|
||||||
double rotation_z0 = instances.front()->get_rotation().z();
|
|
||||||
for (const auto& instance : instances) {
|
for (const auto& instance : instances) {
|
||||||
Geometry::Transformation transformation;
|
const Transform3d& trafo = instance->get_matrix();
|
||||||
const Vec3d& offset = instance->get_offset();
|
|
||||||
transformation.set_offset({ offset.x(), offset.y(), 0.0 });
|
|
||||||
transformation.set_rotation(Z, instance->get_rotation().z() - rotation_z0);
|
|
||||||
const Transform3d& trafo = transformation.get_matrix();
|
|
||||||
const Pointf3s& hull_2d = m_sequential_print_clearance.m_hull_2d_cache[i];
|
const Pointf3s& hull_2d = m_sequential_print_clearance.m_hull_2d_cache[i];
|
||||||
Points inst_pts;
|
Points inst_pts;
|
||||||
inst_pts.reserve(hull_2d.size());
|
inst_pts.reserve(hull_2d.size());
|
||||||
|
@ -712,6 +712,10 @@ public:
|
|||||||
bool get_use_clipping_planes() const { return m_use_clipping_planes; }
|
bool get_use_clipping_planes() const { return m_use_clipping_planes; }
|
||||||
const std::array<ClippingPlane, 2> &get_clipping_planes() const { return m_clipping_planes; };
|
const std::array<ClippingPlane, 2> &get_clipping_planes() const { return m_clipping_planes; };
|
||||||
|
|
||||||
|
void set_use_color_clip_plane(bool use) { m_volumes.set_use_color_clip_plane(use); }
|
||||||
|
void set_color_clip_plane(const Vec3d& cp_normal, double offset) { m_volumes.set_color_clip_plane(cp_normal, offset); }
|
||||||
|
void set_color_clip_plane_colors(const std::array<ColorRGBA, 2>& colors) { m_volumes.set_color_clip_plane_colors(colors); }
|
||||||
|
|
||||||
void refresh_camera_scene_box();
|
void refresh_camera_scene_box();
|
||||||
|
|
||||||
BoundingBoxf3 volumes_bounding_box() const;
|
BoundingBoxf3 volumes_bounding_box() const;
|
||||||
|
@ -448,14 +448,21 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
if (selection.is_single_volume_or_modifier())
|
if (selection.is_single_volume_or_modifier()) {
|
||||||
|
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
||||||
|
Geometry::Transformation trafo = vol->get_volume_transformation();
|
||||||
|
trafo.reset_rotation();
|
||||||
|
vol->set_volume_transformation(trafo);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (selection.is_single_volume() || selection.is_single_modifier())
|
if (selection.is_single_volume() || selection.is_single_modifier())
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_rotation(Vec3d::Zero());
|
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_rotation(Vec3d::Zero());
|
||||||
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
else if (selection.is_single_full_instance()) {
|
else if (selection.is_single_full_instance()) {
|
||||||
|
Geometry::Transformation trafo = selection.get_first_volume()->get_instance_transformation();
|
||||||
|
trafo.reset_rotation();
|
||||||
for (unsigned int idx : selection.get_volume_idxs()) {
|
for (unsigned int idx : selection.get_volume_idxs()) {
|
||||||
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
|
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_transformation(trafo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -484,24 +491,22 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
if (selection.is_single_volume_or_modifier()) {
|
if (selection.is_single_volume_or_modifier()) {
|
||||||
const bool is_left_handed = selection.get_first_volume()->get_volume_transformation().is_left_handed();
|
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
||||||
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_scaling_factor(Vec3d::Ones());
|
Geometry::Transformation trafo = vol->get_volume_transformation();
|
||||||
if (is_left_handed)
|
trafo.reset_scaling_factor();
|
||||||
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_mirror({ -1.0 , 1.0, 1.0 });
|
vol->set_volume_transformation(trafo);
|
||||||
}
|
}
|
||||||
else if (selection.is_single_full_instance()) {
|
else if (selection.is_single_full_instance()) {
|
||||||
const bool is_left_handed = selection.get_first_volume()->get_instance_transformation().is_left_handed();
|
Geometry::Transformation trafo = selection.get_first_volume()->get_instance_transformation();
|
||||||
|
trafo.reset_scaling_factor();
|
||||||
for (unsigned int idx : selection.get_volume_idxs()) {
|
for (unsigned int idx : selection.get_volume_idxs()) {
|
||||||
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_scaling_factor(Vec3d::Ones());
|
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_transformation(trafo);
|
||||||
if (is_left_handed)
|
|
||||||
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_mirror({ -1.0 , 1.0, 1.0 });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas->do_scale(L("Reset scale"));
|
canvas->do_scale(L("Reset scale"));
|
||||||
|
|
||||||
UpdateAndShow(true);
|
UpdateAndShow(true);
|
||||||
#else
|
#else
|
||||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale"));
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale"));
|
||||||
@ -740,7 +745,6 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||||||
m_new_rotate_label_string = L("Rotate (relative)");
|
m_new_rotate_label_string = L("Rotate (relative)");
|
||||||
m_new_position = Vec3d::Zero();
|
m_new_position = Vec3d::Zero();
|
||||||
m_new_rotation = Vec3d::Zero();
|
m_new_rotation = Vec3d::Zero();
|
||||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
|
||||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||||
#else
|
#else
|
||||||
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
||||||
@ -927,93 +931,48 @@ void ObjectManipulation::update_if_dirty()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if ENABLE_WORLD_COORDINATE
|
||||||
void ObjectManipulation::update_reset_buttons_visibility()
|
void ObjectManipulation::update_reset_buttons_visibility()
|
||||||
{
|
{
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
if (!canvas)
|
if (!canvas)
|
||||||
return;
|
return;
|
||||||
const Selection& selection = canvas->get_selection();
|
|
||||||
|
|
||||||
|
bool show_drop_to_bed = false;
|
||||||
bool show_rotation = false;
|
bool show_rotation = false;
|
||||||
bool show_scale = false;
|
bool show_scale = false;
|
||||||
bool show_drop_to_bed = false;
|
bool show_mirror = false;
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
bool show_skew = false;
|
bool show_skew = false;
|
||||||
bool show_mirror_warning = false;
|
|
||||||
|
|
||||||
|
const Selection& selection = canvas->get_selection();
|
||||||
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
|
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
|
||||||
const double min_z = selection.is_single_full_instance() ? selection.get_scaled_instance_bounding_box().min.z() :
|
const double min_z = selection.is_single_full_instance() ? selection.get_scaled_instance_bounding_box().min.z() :
|
||||||
get_volume_min_z(*selection.get_first_volume());
|
get_volume_min_z(*selection.get_first_volume());
|
||||||
|
|
||||||
show_drop_to_bed = std::abs(min_z) > EPSILON;
|
show_drop_to_bed = std::abs(min_z) > EPSILON;
|
||||||
const GLVolume* volume = selection.get_first_volume();
|
const GLVolume* volume = selection.get_first_volume();
|
||||||
Geometry::Transformation trafo;
|
const Geometry::Transformation trafo = selection.is_single_full_instance() ? volume->get_instance_transformation() : volume->get_volume_transformation();
|
||||||
#else
|
|
||||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
|
||||||
const GLVolume* volume = selection.get_first_volume();
|
|
||||||
Vec3d rotation;
|
|
||||||
Vec3d scale;
|
|
||||||
double min_z = 0.0;
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
|
|
||||||
if (selection.is_single_full_instance()) {
|
const Geometry::TransformationSVD trafo_svd(trafo);
|
||||||
#if ENABLE_WORLD_COORDINATE
|
show_rotation = trafo_svd.rotation;
|
||||||
trafo = volume->get_instance_transformation();
|
show_scale = trafo_svd.scale;
|
||||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
show_mirror = trafo_svd.mirror;
|
||||||
for (unsigned int id : idxs) {
|
show_skew = trafo_svd.skew;
|
||||||
const Geometry::Transformation world_trafo(selection.get_volume(id)->world_matrix());
|
|
||||||
show_skew |= world_trafo.has_skew();
|
|
||||||
show_mirror_warning |= world_trafo.get_matrix().matrix().determinant() < 0.0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
rotation = volume->get_instance_rotation();
|
|
||||||
scale = volume->get_instance_scaling_factor();
|
|
||||||
min_z = selection.get_scaled_instance_bounding_box().min.z();
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
Geometry::Transformation trafo = volume->get_volume_transformation();
|
|
||||||
const Geometry::Transformation world_trafo(volume->world_matrix());
|
|
||||||
show_skew |= world_trafo.has_skew();
|
|
||||||
show_mirror_warning |= world_trafo.get_matrix().matrix().determinant() < 0.0;
|
|
||||||
#else
|
|
||||||
rotation = volume->get_volume_rotation();
|
|
||||||
scale = volume->get_volume_scaling_factor();
|
|
||||||
min_z = get_volume_min_z(*volume);
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
}
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
const Transform3d rotation = trafo.get_rotation_matrix();
|
|
||||||
const Transform3d scale = trafo.get_scaling_factor_matrix();
|
|
||||||
show_rotation = show_mirror_warning ? !trafo.get_matrix().matrix().block<3, 3>(0, 0).isDiagonal() : !rotation.isApprox(Transform3d::Identity());
|
|
||||||
show_scale = !scale.isApprox(Transform3d::Identity());
|
|
||||||
#else
|
|
||||||
show_rotation = !rotation.isApprox(Vec3d::Zero());
|
|
||||||
show_scale = !scale.isApprox(Vec3d::Ones());
|
|
||||||
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
wxGetApp().CallAfter([this, show_drop_to_bed, show_rotation, show_scale, show_mirror, show_skew] {
|
||||||
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed, show_skew, show_mirror_warning] {
|
|
||||||
#else
|
|
||||||
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
// There is a case (under OSX), when this function is called after the Manipulation panel is hidden
|
// There is a case (under OSX), when this function is called after the Manipulation panel is hidden
|
||||||
// So, let check if Manipulation panel is still shown for this moment
|
// So, let check if Manipulation panel is still shown for this moment
|
||||||
if (!this->IsShown())
|
if (!this->IsShown())
|
||||||
return;
|
return;
|
||||||
|
m_drop_to_bed_button->Show(show_drop_to_bed);
|
||||||
m_reset_rotation_button->Show(show_rotation);
|
m_reset_rotation_button->Show(show_rotation);
|
||||||
m_reset_scale_button->Show(show_scale);
|
m_reset_scale_button->Show(show_scale);
|
||||||
m_drop_to_bed_button->Show(show_drop_to_bed);
|
m_mirror_warning_bitmap->SetBitmap(show_mirror ? m_manifold_warning_bmp.bmp() : wxNullBitmap);
|
||||||
#if ENABLE_WORLD_COORDINATE
|
m_mirror_warning_bitmap->SetMinSize(show_mirror ? m_manifold_warning_bmp.GetSize() : wxSize(0, 0));
|
||||||
|
m_mirror_warning_bitmap->SetToolTip(show_mirror ? _L("Left handed") : "");
|
||||||
m_reset_skew_button->Show(show_skew);
|
m_reset_skew_button->Show(show_skew);
|
||||||
m_skew_label->Show(show_skew);
|
m_skew_label->Show(show_skew);
|
||||||
m_mirror_warning_bitmap->SetBitmap(show_mirror_warning ? m_manifold_warning_bmp.bmp() : wxNullBitmap);
|
|
||||||
m_mirror_warning_bitmap->SetMinSize(show_mirror_warning ? m_manifold_warning_bmp.GetSize() : wxSize(0, 0));
|
|
||||||
m_mirror_warning_bitmap->SetToolTip(show_mirror_warning ? _L("Left handed") : "");
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
|
|
||||||
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
|
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
|
||||||
Sidebar& panel = wxGetApp().sidebar();
|
Sidebar& panel = wxGetApp().sidebar();
|
||||||
@ -1024,23 +983,75 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
void ObjectManipulation::update_reset_buttons_visibility()
|
||||||
|
{
|
||||||
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
|
if (!canvas)
|
||||||
|
return;
|
||||||
|
const Selection& selection = canvas->get_selection();
|
||||||
|
|
||||||
|
bool show_rotation = false;
|
||||||
|
bool show_scale = false;
|
||||||
|
bool show_drop_to_bed = false;
|
||||||
|
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||||
|
const GLVolume* volume = selection.get_first_volume();
|
||||||
|
Vec3d rotation;
|
||||||
|
Vec3d scale;
|
||||||
|
double min_z = 0.0;
|
||||||
|
|
||||||
|
if (selection.is_single_full_instance()) {
|
||||||
|
rotation = volume->get_instance_rotation();
|
||||||
|
scale = volume->get_instance_scaling_factor();
|
||||||
|
min_z = selection.get_scaled_instance_bounding_box().min.z();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rotation = volume->get_volume_rotation();
|
||||||
|
scale = volume->get_volume_scaling_factor();
|
||||||
|
min_z = get_volume_min_z(*volume);
|
||||||
|
}
|
||||||
|
show_rotation = !rotation.isApprox(Vec3d::Zero());
|
||||||
|
show_scale = !scale.isApprox(Vec3d::Ones());
|
||||||
|
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
|
||||||
|
// There is a case (under OSX), when this function is called after the Manipulation panel is hidden
|
||||||
|
// So, let check if Manipulation panel is still shown for this moment
|
||||||
|
if (!this->IsShown())
|
||||||
|
return;
|
||||||
|
m_reset_rotation_button->Show(show_rotation);
|
||||||
|
m_reset_scale_button->Show(show_scale);
|
||||||
|
m_drop_to_bed_button->Show(show_drop_to_bed);
|
||||||
|
|
||||||
|
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
|
||||||
|
Sidebar& panel = wxGetApp().sidebar();
|
||||||
|
if (!panel.IsFrozen()) {
|
||||||
|
panel.Freeze();
|
||||||
|
panel.Layout();
|
||||||
|
panel.Thaw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ObjectManipulation::update_mirror_buttons_visibility()
|
void ObjectManipulation::update_mirror_buttons_visibility()
|
||||||
{
|
{
|
||||||
|
#if ENABLE_WORLD_COORDINATE
|
||||||
|
const bool can_mirror = wxGetApp().plater()->can_mirror();
|
||||||
|
for (ScalableButton* button : m_mirror_buttons) {
|
||||||
|
button->Enable(can_mirror);
|
||||||
|
}
|
||||||
|
#else
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
if (is_local_coordinates()) {
|
|
||||||
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
|
|
||||||
#else
|
|
||||||
std::array<MirrorButtonState, 3> new_states = { mbHidden, mbHidden, mbHidden };
|
std::array<MirrorButtonState, 3> new_states = { mbHidden, mbHidden, mbHidden };
|
||||||
|
|
||||||
if (!m_world_coordinates) {
|
if (!m_world_coordinates) {
|
||||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
const GLVolume* volume = selection.get_first_volume();
|
const GLVolume* volume = selection.get_first_volume();
|
||||||
Vec3d mirror;
|
Vec3d mirror;
|
||||||
|
|
||||||
@ -1049,19 +1060,10 @@ void ObjectManipulation::update_mirror_buttons_visibility()
|
|||||||
else
|
else
|
||||||
mirror = volume->get_volume_mirror();
|
mirror = volume->get_volume_mirror();
|
||||||
|
|
||||||
#if !ENABLE_WORLD_COORDINATE
|
|
||||||
for (unsigned char i=0; i<3; ++i)
|
for (unsigned char i=0; i<3; ++i)
|
||||||
new_states[i] = (mirror[i] < 0. ? mbActive : mbShown);
|
new_states[i] = (mirror[i] < 0. ? mbActive : mbShown);
|
||||||
#endif // !ENABLE_WORLD_COORDINATE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
const bool can_mirror = wxGetApp().plater()->can_mirror();
|
|
||||||
for (ScalableButton* button : m_mirror_buttons) {
|
|
||||||
button->Enable(can_mirror);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
else {
|
else {
|
||||||
// the mirroring buttons should be hidden in world coordinates,
|
// the mirroring buttons should be hidden in world coordinates,
|
||||||
// unless we make it actually mirror in world coords.
|
// unless we make it actually mirror in world coords.
|
||||||
|
@ -198,16 +198,23 @@ void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoBase::render_grabbers(float size) const
|
void GLGizmoBase::render_grabbers(float size) const
|
||||||
|
{
|
||||||
|
render_grabbers(0, m_grabbers.size() - 1, size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::render_grabbers(size_t first, size_t last, float size, bool force_hover) const
|
||||||
{
|
{
|
||||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||||
if (shader == nullptr)
|
if (shader == nullptr)
|
||||||
return;
|
return;
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
shader->set_uniform("emission_factor", 0.1f);
|
shader->set_uniform("emission_factor", 0.1f);
|
||||||
for (int i = 0; i < (int)m_grabbers.size(); ++i) {
|
glsafe(::glDisable(GL_CULL_FACE));
|
||||||
|
for (size_t i = first; i <= last; ++i) {
|
||||||
if (m_grabbers[i].enabled)
|
if (m_grabbers[i].enabled)
|
||||||
m_grabbers[i].render(m_hover_id == i, size);
|
m_grabbers[i].render(force_hover ? true : m_hover_id == (int)i, size);
|
||||||
}
|
}
|
||||||
|
glsafe(::glEnable(GL_CULL_FACE));
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,6 +219,7 @@ protected:
|
|||||||
|
|
||||||
void render_grabbers(const BoundingBoxf3& box) const;
|
void render_grabbers(const BoundingBoxf3& box) const;
|
||||||
void render_grabbers(float size) const;
|
void render_grabbers(float size) const;
|
||||||
|
void render_grabbers(size_t first, size_t last, float size, bool force_hover) const;
|
||||||
|
|
||||||
std::string format(float value, unsigned int decimals) const;
|
std::string format(float value, unsigned int decimals) const;
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ namespace Slic3r {
|
|||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW();
|
static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW();
|
||||||
|
static const ColorRGBA UPPER_PART_COLOR = ColorRGBA::CYAN();
|
||||||
|
static const ColorRGBA LOWER_PART_COLOR = ColorRGBA::MAGENTA();
|
||||||
|
|
||||||
// connector colors
|
// connector colors
|
||||||
static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW();
|
static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW();
|
||||||
@ -196,7 +198,7 @@ static void init_from_angle_arc(GLModel& model, double angle, double radius)
|
|||||||
|
|
||||||
GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||||
, m_connectors_group_id (3)
|
, m_connectors_group_id (GrabberID::Count)
|
||||||
, m_connector_type (CutConnectorType::Plug)
|
, m_connector_type (CutConnectorType::Plug)
|
||||||
, m_connector_style (size_t(CutConnectorStyle::Prizm))
|
, m_connector_style (size_t(CutConnectorStyle::Prizm))
|
||||||
, m_connector_shape_id (size_t(CutConnectorShape::Circle))
|
, m_connector_shape_id (size_t(CutConnectorShape::Circle))
|
||||||
@ -227,13 +229,19 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename,
|
|||||||
|
|
||||||
m_axis_names = { "X", "Y", "Z" };
|
m_axis_names = { "X", "Y", "Z" };
|
||||||
|
|
||||||
|
m_part_orientation_names = {
|
||||||
|
{"none", _L("Keep orientation")},
|
||||||
|
{"on_cut", _L("Place on cut")},
|
||||||
|
{"flip", _L("Flip upside down")},
|
||||||
|
};
|
||||||
|
|
||||||
update_connector_shape();
|
update_connector_shape();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GLGizmoCut3D::get_tooltip() const
|
std::string GLGizmoCut3D::get_tooltip() const
|
||||||
{
|
{
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
if (m_hover_id == Z) {
|
if (m_hover_id == Z || (m_dragging && m_hover_id == CutPlane)) {
|
||||||
double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0;
|
double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0;
|
||||||
std::string unit_str = " " + (m_imperial_units ? _u8L("inch") : _u8L("mm"));
|
std::string unit_str = " " + (m_imperial_units ? _u8L("inch") : _u8L("mm"));
|
||||||
const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center);
|
const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center);
|
||||||
@ -249,6 +257,11 @@ std::string GLGizmoCut3D::get_tooltip() const
|
|||||||
}
|
}
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_dragging && m_hover_id == CutPlane)
|
||||||
|
return _u8L("Click to flip the cut plane\n"
|
||||||
|
"Drag to move the cut plane");
|
||||||
|
|
||||||
if (tooltip.empty() && (m_hover_id == X || m_hover_id == Y)) {
|
if (tooltip.empty() && (m_hover_id == X || m_hover_id == Y)) {
|
||||||
std::string axis = m_hover_id == X ? "X" : "Y";
|
std::string axis = m_hover_id == X ? "X" : "Y";
|
||||||
return axis + ": " + format(float(rad2deg(m_angle)), 1) + _u8L("°");
|
return axis + ": " + format(float(rad2deg(m_angle)), 1) + _u8L("°");
|
||||||
@ -264,6 +277,8 @@ bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event)
|
|||||||
|
|
||||||
if (mouse_event.ShiftDown() && mouse_event.LeftDown())
|
if (mouse_event.ShiftDown() && mouse_event.LeftDown())
|
||||||
return gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown());
|
return gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown());
|
||||||
|
if (mouse_event.CmdDown() && mouse_event.LeftDown())
|
||||||
|
return false;
|
||||||
if (cut_line_processing()) {
|
if (cut_line_processing()) {
|
||||||
if (mouse_event.ShiftDown()) {
|
if (mouse_event.ShiftDown()) {
|
||||||
if (mouse_event.Moving()|| mouse_event.Dragging())
|
if (mouse_event.Moving()|| mouse_event.Dragging())
|
||||||
@ -283,6 +298,12 @@ bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event)
|
|||||||
if (mouse_event.LeftUp() && !mouse_event.ShiftDown())
|
if (mouse_event.LeftUp() && !mouse_event.ShiftDown())
|
||||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown());
|
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown());
|
||||||
}
|
}
|
||||||
|
else if (m_hover_id == CutPlane) {
|
||||||
|
if (mouse_event.LeftDown())
|
||||||
|
m_was_cut_plane_dragged = false;
|
||||||
|
else if (mouse_event.LeftUp() && !m_was_cut_plane_dragged)
|
||||||
|
flip_cut_plane();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,9 +413,18 @@ void GLGizmoCut3D::update_clipper()
|
|||||||
|
|
||||||
// calculate normal for cut plane
|
// calculate normal for cut plane
|
||||||
Vec3d normal = m_cut_normal = end - beg;
|
Vec3d normal = m_cut_normal = end - beg;
|
||||||
m_cut_normal.normalize();
|
|
||||||
|
// calculate normal and offset for clipping plane
|
||||||
|
double dist = (m_plane_center - beg).norm();
|
||||||
|
dist = std::clamp(dist, 0.0001, normal.norm());
|
||||||
|
normal.normalize();
|
||||||
|
m_clp_normal = normal;
|
||||||
|
double offset = normal.dot(beg) + dist;
|
||||||
|
|
||||||
|
m_parent.set_color_clip_plane(normal, offset);
|
||||||
|
|
||||||
if (!is_looking_forward()) {
|
if (!is_looking_forward()) {
|
||||||
|
// recalculate normal and offset for clipping plane, if camera is looking downward to cut plane
|
||||||
end = beg = m_plane_center;
|
end = beg = m_plane_center;
|
||||||
beg[Z] = box.center().z() + m_radius;
|
beg[Z] = box.center().z() + m_radius;
|
||||||
end[Z] = box.center().z() - m_radius;
|
end[Z] = box.center().z() - m_radius;
|
||||||
@ -402,18 +432,16 @@ void GLGizmoCut3D::update_clipper()
|
|||||||
rotate_vec3d_around_plane_center(beg);
|
rotate_vec3d_around_plane_center(beg);
|
||||||
rotate_vec3d_around_plane_center(end);
|
rotate_vec3d_around_plane_center(end);
|
||||||
|
|
||||||
// recalculate normal for clipping plane, if camera is looking downward to cut plane
|
|
||||||
normal = end - beg;
|
normal = end - beg;
|
||||||
if (normal == Vec3d::Zero())
|
if (normal == Vec3d::Zero())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// calculate normal and offset for clipping plane
|
dist = (m_plane_center - beg).norm();
|
||||||
double dist = (m_plane_center - beg).norm();
|
|
||||||
dist = std::clamp(dist, 0.0001, normal.norm());
|
dist = std::clamp(dist, 0.0001, normal.norm());
|
||||||
normal.normalize();
|
normal.normalize();
|
||||||
m_clp_normal = normal;
|
m_clp_normal = normal;
|
||||||
const double offset = normal.dot(beg) + dist;
|
offset = normal.dot(beg) + dist;
|
||||||
|
}
|
||||||
|
|
||||||
m_c->object_clipper()->set_range_and_pos(normal, offset, dist);
|
m_c->object_clipper()->set_range_and_pos(normal, offset, dist);
|
||||||
|
|
||||||
@ -656,12 +684,15 @@ void GLGizmoCut3D::render_cut_plane()
|
|||||||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
|
|
||||||
if (can_perform_cut() && has_valid_contour())
|
if (can_perform_cut() && has_valid_contour()) {
|
||||||
// m_plane.set_color({ 0.8f, 0.8f, 0.8f, 0.5f });
|
if (m_hover_id == CutPlane)
|
||||||
m_plane.set_color({ 0.9f, 0.9f, 0.9f, 0.5f });
|
m_plane.model.set_color({ 0.9f, 0.9f, 0.9f, 0.5f });
|
||||||
else
|
else
|
||||||
m_plane.set_color({ 1.0f, 0.8f, 0.8f, 0.5f });
|
m_plane.model.set_color({ 0.8f, 0.8f, 0.8f, 0.5f });
|
||||||
m_plane.render();
|
}
|
||||||
|
else
|
||||||
|
m_plane.model.set_color({ 1.0f, 0.8f, 0.8f, 0.5f });
|
||||||
|
m_plane.model.render();
|
||||||
|
|
||||||
glsafe(::glEnable(GL_CULL_FACE));
|
glsafe(::glEnable(GL_CULL_FACE));
|
||||||
glsafe(::glDisable(GL_BLEND));
|
glsafe(::glDisable(GL_BLEND));
|
||||||
@ -717,7 +748,7 @@ void GLGizmoCut3D::render_line(GLModel& line_model, const ColorRGBA& color, Tran
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::render_rotation_snapping(Axis axis, const ColorRGBA& color)
|
void GLGizmoCut3D::render_rotation_snapping(GrabberID axis, const ColorRGBA& color)
|
||||||
{
|
{
|
||||||
GLShaderProgram* line_shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
|
GLShaderProgram* line_shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
|
||||||
if (!line_shader)
|
if (!line_shader)
|
||||||
@ -760,49 +791,34 @@ void GLGizmoCut3D::render_cut_plane_grabbers()
|
|||||||
{
|
{
|
||||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||||
|
|
||||||
ColorRGBA color = m_hover_id == Z ? complementary(GRABBER_COLOR) : GRABBER_COLOR;
|
ColorRGBA color = ColorRGBA::GRAY();
|
||||||
|
|
||||||
const Transform3d view_matrix = wxGetApp().plater()->get_camera().get_view_matrix() * translation_transform(m_plane_center) * m_rotation_m;
|
const Transform3d view_matrix = wxGetApp().plater()->get_camera().get_view_matrix() * translation_transform(m_plane_center) * m_rotation_m;
|
||||||
|
|
||||||
const double mean_size = get_grabber_mean_size(bounding_box());
|
const double mean_size = get_grabber_mean_size(bounding_box());
|
||||||
|
double size;
|
||||||
|
|
||||||
double size = m_dragging && m_hover_id == Z ? get_dragging_half_size(mean_size) : get_half_size(mean_size);
|
const bool dragging_by_cut_plane = m_dragging && m_hover_id == CutPlane;
|
||||||
|
|
||||||
Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
if (!dragging_by_cut_plane) {
|
||||||
Vec3d offset = 1.25 * size * Vec3d::UnitZ();
|
render_grabber_connection(GRABBER_COLOR, view_matrix);
|
||||||
|
|
||||||
// render Z grabber
|
// render sphere grabber
|
||||||
|
|
||||||
if (!m_dragging && m_hover_id < 0)
|
|
||||||
render_grabber_connection(color, view_matrix);
|
|
||||||
render_model(m_sphere.model, color, view_matrix * scale_transform(size));
|
|
||||||
|
|
||||||
if ((!m_dragging && m_hover_id < 0) || m_hover_id == Z)
|
|
||||||
{
|
|
||||||
const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center);
|
|
||||||
if (tbb.min.z() <= 0.0)
|
|
||||||
render_model(m_cone.model, color, view_matrix * translation_transform(-offset) * rotation_transform(PI * Vec3d::UnitX()) * scale_transform(cone_scale));
|
|
||||||
|
|
||||||
if (tbb.max.z() >= 0.0)
|
|
||||||
render_model(m_cone.model, color, view_matrix * translation_transform(offset) * scale_transform(cone_scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
// render top sphere for X/Y grabbers
|
|
||||||
|
|
||||||
if ((!m_dragging && m_hover_id < 0) || m_hover_id == X || m_hover_id == Y)
|
|
||||||
{
|
|
||||||
size = m_dragging ? get_dragging_half_size(mean_size) : get_half_size(mean_size);
|
size = m_dragging ? get_dragging_half_size(mean_size) : get_half_size(mean_size);
|
||||||
color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) :
|
color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) :
|
||||||
m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::GRAY();
|
m_hover_id == X ? complementary(ColorRGBA::RED()) :
|
||||||
|
m_hover_id == Z ? GRABBER_COLOR : ColorRGBA::GRAY();
|
||||||
render_model(m_sphere.model, color, view_matrix * translation_transform(m_grabber_connection_len * Vec3d::UnitZ()) * scale_transform(size));
|
render_model(m_sphere.model, color, view_matrix * translation_transform(m_grabber_connection_len * Vec3d::UnitZ()) * scale_transform(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool no_one_grabber_hovered = !m_dragging && (m_hover_id < 0 || m_hover_id == CutPlane);
|
||||||
|
|
||||||
// render X grabber
|
// render X grabber
|
||||||
|
|
||||||
if ((!m_dragging && m_hover_id < 0) || m_hover_id == X)
|
if (no_one_grabber_hovered || m_hover_id == X)
|
||||||
{
|
{
|
||||||
size = m_dragging && m_hover_id == X ? get_dragging_half_size(mean_size) : get_half_size(mean_size);
|
size = m_dragging && m_hover_id == X ? get_dragging_half_size(mean_size) : get_half_size(mean_size);
|
||||||
cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
const Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
||||||
color = m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::RED();
|
color = m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::RED();
|
||||||
|
|
||||||
if (m_hover_id == X) {
|
if (m_hover_id == X) {
|
||||||
@ -810,7 +826,7 @@ void GLGizmoCut3D::render_cut_plane_grabbers()
|
|||||||
render_rotation_snapping(X, color);
|
render_rotation_snapping(X, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len);
|
Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len);
|
||||||
render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale));
|
render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale));
|
||||||
offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len);
|
offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len);
|
||||||
render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale));
|
render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(cone_scale));
|
||||||
@ -818,10 +834,10 @@ void GLGizmoCut3D::render_cut_plane_grabbers()
|
|||||||
|
|
||||||
// render Y grabber
|
// render Y grabber
|
||||||
|
|
||||||
if ((!m_dragging && m_hover_id < 0) || m_hover_id == Y)
|
if (no_one_grabber_hovered || m_hover_id == Y)
|
||||||
{
|
{
|
||||||
size = m_dragging && m_hover_id == Y ? get_dragging_half_size(mean_size) : get_half_size(mean_size);
|
size = m_dragging && m_hover_id == Y ? get_dragging_half_size(mean_size) : get_half_size(mean_size);
|
||||||
cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
const Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
||||||
color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : ColorRGBA::GREEN();
|
color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : ColorRGBA::GREEN();
|
||||||
|
|
||||||
if (m_hover_id == Y) {
|
if (m_hover_id == Y) {
|
||||||
@ -829,7 +845,7 @@ void GLGizmoCut3D::render_cut_plane_grabbers()
|
|||||||
render_rotation_snapping(Y, color);
|
render_rotation_snapping(Y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len);
|
Vec3d offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len);
|
||||||
render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale));
|
render_model(m_cone.model, color, view_matrix * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale));
|
||||||
offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len);
|
offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len);
|
||||||
render_model(m_cone.model, color, view_matrix * translation_transform(offset)* rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale));
|
render_model(m_cone.model, color, view_matrix * translation_transform(offset)* rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(cone_scale));
|
||||||
@ -898,6 +914,9 @@ std::string GLGizmoCut3D::on_get_name() const
|
|||||||
void GLGizmoCut3D::on_set_state()
|
void GLGizmoCut3D::on_set_state()
|
||||||
{
|
{
|
||||||
if (m_state == On) {
|
if (m_state == On) {
|
||||||
|
m_parent.set_use_color_clip_plane(true);
|
||||||
|
m_parent.set_color_clip_plane_colors({ UPPER_PART_COLOR , LOWER_PART_COLOR });
|
||||||
|
|
||||||
update_bb();
|
update_bb();
|
||||||
m_connectors_editing = !m_selected.empty();
|
m_connectors_editing = !m_selected.empty();
|
||||||
|
|
||||||
@ -913,6 +932,7 @@ void GLGizmoCut3D::on_set_state()
|
|||||||
oc->release();
|
oc->release();
|
||||||
}
|
}
|
||||||
m_selected.clear();
|
m_selected.clear();
|
||||||
|
m_parent.set_use_color_clip_plane(false);
|
||||||
}
|
}
|
||||||
force_update_clipper_on_render = m_state == On;
|
force_update_clipper_on_render = m_state == On;
|
||||||
}
|
}
|
||||||
@ -940,8 +960,8 @@ void GLGizmoCut3D::on_register_raycasters_for_picking()
|
|||||||
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Y, *m_cone.mesh_raycaster, Transform3d::Identity()));
|
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Y, *m_cone.mesh_raycaster, Transform3d::Identity()));
|
||||||
|
|
||||||
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_sphere.mesh_raycaster, Transform3d::Identity()));
|
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_sphere.mesh_raycaster, Transform3d::Identity()));
|
||||||
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_cone.mesh_raycaster, Transform3d::Identity()));
|
|
||||||
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_cone.mesh_raycaster, Transform3d::Identity()));
|
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CutPlane, *m_plane.mesh_raycaster, Transform3d::Identity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
update_raycasters_for_picking_transform();
|
update_raycasters_for_picking_transform();
|
||||||
@ -1018,20 +1038,22 @@ void GLGizmoCut3D::update_raycasters_for_picking_transform()
|
|||||||
const double size = get_half_size(get_grabber_mean_size(box));
|
const double size = get_half_size(get_grabber_mean_size(box));
|
||||||
Vec3d scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
Vec3d scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
||||||
|
|
||||||
|
int id = 0;
|
||||||
|
|
||||||
Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len);
|
Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len);
|
||||||
m_raycasters[0]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(scale));
|
m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitX()) * scale_transform(scale));
|
||||||
offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len);
|
offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len);
|
||||||
m_raycasters[1]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(scale));
|
m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitX()) * scale_transform(scale));
|
||||||
|
|
||||||
offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len);
|
offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len);
|
||||||
m_raycasters[2]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(scale));
|
m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(0.5 * PI * Vec3d::UnitY()) * scale_transform(scale));
|
||||||
offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len);
|
offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len);
|
||||||
m_raycasters[3]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(scale));
|
m_raycasters[id++]->set_transform(trafo * translation_transform(offset) * rotation_transform(-0.5 * PI * Vec3d::UnitY()) * scale_transform(scale));
|
||||||
|
|
||||||
offset = 1.25 * size * Vec3d::UnitZ();
|
offset = 1.25 * size * Vec3d::UnitZ();
|
||||||
m_raycasters[4]->set_transform(trafo * scale_transform(size));
|
m_raycasters[id++]->set_transform(trafo * translation_transform(m_grabber_connection_len * Vec3d::UnitZ()) * scale_transform(size));
|
||||||
m_raycasters[5]->set_transform(trafo * translation_transform(-offset) * rotation_transform(PI * Vec3d::UnitX()) * scale_transform(scale));
|
|
||||||
m_raycasters[6]->set_transform(trafo * translation_transform(offset) * scale_transform(scale));
|
m_raycasters[id++]->set_transform(trafo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1046,25 +1068,16 @@ bool GLGizmoCut3D::on_is_activable() const
|
|||||||
if (object_idx < 0 || selection.is_wipe_tower())
|
if (object_idx < 0 || selection.is_wipe_tower())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool is_dowel_object = false;
|
if (const ModelObject* mo = wxGetApp().plater()->model().objects[object_idx];
|
||||||
if (const ModelObject* mo = wxGetApp().plater()->model().objects[object_idx]; mo->is_cut()) {
|
mo->is_cut() && mo->volumes.size() == 1) {
|
||||||
int solid_connector_cnt = 0;
|
const ModelVolume* volume = mo->volumes[0];
|
||||||
int connectors_cnt = 0;
|
if (volume->is_cut_connector() && volume->cut_info.connector_type == CutConnectorType::Dowel)
|
||||||
for (const ModelVolume* volume : mo->volumes) {
|
return false;
|
||||||
if (volume->is_cut_connector()) {
|
|
||||||
connectors_cnt++;
|
|
||||||
if (volume->is_model_part())
|
|
||||||
solid_connector_cnt++;
|
|
||||||
}
|
|
||||||
if (connectors_cnt > 1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
is_dowel_object = connectors_cnt == 1 && solid_connector_cnt == 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is assumed in GLCanvas3D::do_rotate, do not change this
|
// This is assumed in GLCanvas3D::do_rotate, do not change this
|
||||||
// without updating that function too.
|
// without updating that function too.
|
||||||
return selection.is_single_full_instance() && !is_dowel_object && !m_parent.is_layers_editing_enabled();
|
return selection.is_single_full_instance() && !m_parent.is_layers_editing_enabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLGizmoCut3D::on_is_selectable() const
|
bool GLGizmoCut3D::on_is_selectable() const
|
||||||
@ -1072,7 +1085,7 @@ bool GLGizmoCut3D::on_is_selectable() const
|
|||||||
return wxGetApp().get_mode() != comSimple;
|
return wxGetApp().get_mode() != comSimple;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3d GLGizmoCut3D::mouse_position_in_local_plane(Axis axis, const Linef3& mouse_ray) const
|
Vec3d GLGizmoCut3D::mouse_position_in_local_plane(GrabberID axis, const Linef3& mouse_ray) const
|
||||||
{
|
{
|
||||||
double half_pi = 0.5 * PI;
|
double half_pi = 0.5 * PI;
|
||||||
|
|
||||||
@ -1108,39 +1121,39 @@ Vec3d GLGizmoCut3D::mouse_position_in_local_plane(Axis axis, const Linef3& mouse
|
|||||||
|
|
||||||
void GLGizmoCut3D::dragging_grabber_z(const GLGizmoBase::UpdateData &data)
|
void GLGizmoCut3D::dragging_grabber_z(const GLGizmoBase::UpdateData &data)
|
||||||
{
|
{
|
||||||
Vec3d starting_box_center = m_plane_center - Vec3d::UnitZ(); // some Margin
|
const Vec3d grabber_init_pos = (m_hover_id == CutPlane ? 0. : m_grabber_connection_len) * Vec3d::UnitZ();
|
||||||
rotate_vec3d_around_plane_center(starting_box_center);
|
const Vec3d starting_drag_position = translation_transform(m_plane_center) * m_rotation_m * grabber_init_pos;
|
||||||
|
|
||||||
const Vec3d&starting_drag_position = m_plane_center;
|
|
||||||
double projection = 0.0;
|
double projection = 0.0;
|
||||||
|
|
||||||
Vec3d starting_vec = starting_drag_position - starting_box_center;
|
Vec3d starting_vec = m_rotation_m * Vec3d::UnitZ();
|
||||||
if (starting_vec.norm() != 0.0) {
|
if (starting_vec.norm() != 0.0) {
|
||||||
Vec3d mouse_dir = data.mouse_ray.unit_vector();
|
const Vec3d mouse_dir = data.mouse_ray.unit_vector();
|
||||||
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
|
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
|
||||||
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
||||||
// in our case plane normal and ray direction are the same (orthogonal view)
|
// in our case plane normal and ray direction are the same (orthogonal view)
|
||||||
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
||||||
Vec3d inters = data.mouse_ray.a + (starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
|
const Vec3d inters = data.mouse_ray.a + (starting_drag_position - data.mouse_ray.a).dot(mouse_dir) * mouse_dir;
|
||||||
// vector from the starting position to the found intersection
|
// vector from the starting position to the found intersection
|
||||||
Vec3d inters_vec = inters - starting_drag_position;
|
const Vec3d inters_vec = inters - starting_drag_position;
|
||||||
|
|
||||||
starting_vec.normalize();
|
starting_vec.normalize();
|
||||||
// finds projection of the vector along the staring direction
|
// finds projection of the vector along the staring direction
|
||||||
projection = inters_vec.dot(starting_vec);
|
projection = inters_vec.dot(starting_vec);
|
||||||
}
|
}
|
||||||
if (wxGetKeyState(WXK_SHIFT))
|
if (wxGetKeyState(WXK_SHIFT))
|
||||||
projection = m_snap_step * (double)std::round(projection / m_snap_step);
|
projection = m_snap_step * std::round(projection / m_snap_step);
|
||||||
|
|
||||||
const Vec3d shift = starting_vec * projection;
|
const Vec3d shift = starting_vec * projection;
|
||||||
|
|
||||||
// move cut plane center
|
// move cut plane center
|
||||||
set_center(m_plane_center + shift);
|
set_center(m_plane_center + shift);
|
||||||
|
|
||||||
|
m_was_cut_plane_dragged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data)
|
void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data)
|
||||||
{
|
{
|
||||||
const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane((Axis)m_hover_id, data.mouse_ray));
|
const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane((GrabberID)m_hover_id, data.mouse_ray));
|
||||||
|
|
||||||
const Vec2d orig_dir = Vec2d::UnitX();
|
const Vec2d orig_dir = Vec2d::UnitX();
|
||||||
const Vec2d new_dir = mouse_pos.normalized();
|
const Vec2d new_dir = mouse_pos.normalized();
|
||||||
@ -1197,7 +1210,7 @@ void GLGizmoCut3D::on_dragging(const UpdateData& data)
|
|||||||
{
|
{
|
||||||
if (m_hover_id < 0)
|
if (m_hover_id < 0)
|
||||||
return;
|
return;
|
||||||
if (m_hover_id == Z)
|
if (m_hover_id == Z || m_hover_id == CutPlane)
|
||||||
dragging_grabber_z(data);
|
dragging_grabber_z(data);
|
||||||
else if (m_hover_id == X || m_hover_id == Y)
|
else if (m_hover_id == X || m_hover_id == Y)
|
||||||
dragging_grabber_xy(data);
|
dragging_grabber_xy(data);
|
||||||
@ -1223,7 +1236,8 @@ void GLGizmoCut3D::on_stop_dragging()
|
|||||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Rotate cut plane"), UndoRedo::SnapshotType::GizmoAction);
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Rotate cut plane"), UndoRedo::SnapshotType::GizmoAction);
|
||||||
m_start_dragging_m = m_rotation_m;
|
m_start_dragging_m = m_rotation_m;
|
||||||
}
|
}
|
||||||
else if (m_hover_id == Z) {
|
else if (m_hover_id == Z || m_hover_id == CutPlane) {
|
||||||
|
if (m_was_cut_plane_dragged)
|
||||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction);
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction);
|
||||||
m_ar_plane_center = m_plane_center;
|
m_ar_plane_center = m_plane_center;
|
||||||
}
|
}
|
||||||
@ -1332,7 +1346,7 @@ bool GLGizmoCut3D::update_bb()
|
|||||||
set_center_pos(m_bb_center, true);
|
set_center_pos(m_bb_center, true);
|
||||||
|
|
||||||
m_radius = box.radius();
|
m_radius = box.radius();
|
||||||
m_grabber_connection_len = 0.75 * m_radius;// std::min<double>(0.75 * m_radius, 35.0);
|
m_grabber_connection_len = 0.5 * m_radius;// std::min<double>(0.75 * m_radius, 35.0);
|
||||||
m_grabber_radius = m_grabber_connection_len * 0.85;
|
m_grabber_radius = m_grabber_connection_len * 0.85;
|
||||||
|
|
||||||
m_snap_coarse_in_radius = m_grabber_radius / 3.0;
|
m_snap_coarse_in_radius = m_grabber_radius / 3.0;
|
||||||
@ -1372,6 +1386,14 @@ void GLGizmoCut3D::init_picking_models()
|
|||||||
m_sphere.model.init_from(its);
|
m_sphere.model.init_from(its);
|
||||||
m_sphere.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(its)));
|
m_sphere.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(its)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_plane.model.is_initialized() && !m_hide_cut_plane && !m_connectors_editing) {
|
||||||
|
const double cp_width = 0.02 * get_grabber_mean_size(bounding_box());
|
||||||
|
indexed_triangle_set its = its_make_frustum_dowel((double)m_cut_plane_radius_koef * m_radius, cp_width, m_cut_plane_as_circle ? 180 : 4);
|
||||||
|
m_plane.model.init_from(its);
|
||||||
|
m_plane.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(its)));
|
||||||
|
}
|
||||||
|
|
||||||
if (m_shapes.empty())
|
if (m_shapes.empty())
|
||||||
init_connector_shapes();
|
init_connector_shapes();
|
||||||
}
|
}
|
||||||
@ -1392,18 +1414,6 @@ void GLGizmoCut3D::init_rendering_items()
|
|||||||
}
|
}
|
||||||
if (!m_angle_arc.is_initialized() || m_angle != 0.0)
|
if (!m_angle_arc.is_initialized() || m_angle != 0.0)
|
||||||
init_from_angle_arc(m_angle_arc, m_angle, m_grabber_connection_len);
|
init_from_angle_arc(m_angle_arc, m_angle, m_grabber_connection_len);
|
||||||
|
|
||||||
if (!m_plane.is_initialized() && !m_hide_cut_plane && !m_connectors_editing) {
|
|
||||||
#if 1
|
|
||||||
const double cp_width = 0.02 * get_grabber_mean_size(bounding_box());
|
|
||||||
m_plane.init_from(its_make_frustum_dowel((double)m_cut_plane_radius_koef * m_radius, cp_width, m_cut_plane_as_circle ? 180 : 4));
|
|
||||||
#else
|
|
||||||
if (m_cut_plane_as_circle)
|
|
||||||
m_plane.init_from(its_make_frustum_dowel(2. * m_radius, 0.3, 180));
|
|
||||||
else
|
|
||||||
m_plane.init_from(its_make_square_plane(float(m_radius)));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::render_clipper_cut()
|
void GLGizmoCut3D::render_clipper_cut()
|
||||||
@ -1566,6 +1576,8 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors)
|
|||||||
reset_connectors();
|
reset_connectors();
|
||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
|
render_flip_plane_button(m_connectors_editing && connectors.empty());
|
||||||
|
|
||||||
m_imgui->text(_L("Type"));
|
m_imgui->text(_L("Type"));
|
||||||
bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug);
|
bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug);
|
||||||
type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel);
|
type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel);
|
||||||
@ -1660,6 +1672,57 @@ void GLGizmoCut3D::set_connectors_editing(bool connectors_editing)
|
|||||||
m_parent.request_extra_frame();
|
m_parent.request_extra_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLGizmoCut3D::flip_cut_plane()
|
||||||
|
{
|
||||||
|
m_rotation_m = m_rotation_m * rotation_transform(PI * Vec3d::UnitX());
|
||||||
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Flip cut plane"), UndoRedo::SnapshotType::GizmoAction);
|
||||||
|
m_start_dragging_m = m_rotation_m;
|
||||||
|
|
||||||
|
update_clipper();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoCut3D::render_flip_plane_button(bool disable_pred /*=false*/)
|
||||||
|
{
|
||||||
|
ImGui::SameLine(2.5 * m_label_width);
|
||||||
|
|
||||||
|
if (m_hover_id == CutPlane)
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered));
|
||||||
|
|
||||||
|
m_imgui->disabled_begin(disable_pred);
|
||||||
|
if (m_imgui->button(_L("Flip cut plane")))
|
||||||
|
flip_cut_plane();
|
||||||
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
|
if (m_hover_id == CutPlane)
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoCut3D::add_vertical_scaled_interval(float interval)
|
||||||
|
{
|
||||||
|
ImGui::GetCurrentWindow()->DC.CursorPos.y += m_imgui->scaled(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoCut3D::add_horizontal_scaled_interval(float interval)
|
||||||
|
{
|
||||||
|
ImGui::GetCurrentWindow()->DC.CursorPos.x += m_imgui->scaled(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoCut3D::add_horizontal_shift(float shift)
|
||||||
|
{
|
||||||
|
ImGui::GetCurrentWindow()->DC.CursorPos.x += shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoCut3D::render_color_marker(float size, const ImU32& color)
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
const float radius = 0.5f * size;
|
||||||
|
ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos;
|
||||||
|
pos.x += size;
|
||||||
|
pos.y += 1.25f * radius;
|
||||||
|
ImGui::GetCurrentWindow()->DrawList->AddNgonFilled(pos, radius, color, 6);
|
||||||
|
ImGuiWrapper::text(" ");
|
||||||
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
|
void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
|
||||||
{
|
{
|
||||||
// WIP : cut plane mode
|
// WIP : cut plane mode
|
||||||
@ -1667,65 +1730,130 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
|
|||||||
|
|
||||||
if (m_mode == size_t(CutMode::cutPlanar)) {
|
if (m_mode == size_t(CutMode::cutPlanar)) {
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(wxString(ImGui::InfoMarkerSmall));
|
ImGuiWrapper::text(wxString(ImGui::InfoMarkerSmall));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT,
|
ImGuiWrapper::text_colored(ImGuiWrapper::COL_ORANGE_LIGHT,
|
||||||
get_wraped_wxString(_L("Hold SHIFT key and connect some two points of an object to cut by line"), 40));
|
get_wraped_wxString(_L("Hold SHIFT key to draw a cut line"), 40));
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
render_build_size();
|
render_build_size();
|
||||||
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(_L("Cut position: "));
|
ImGuiWrapper::text(_L("Cut position: "));
|
||||||
ImGui::SameLine(m_label_width);
|
ImGui::SameLine(m_label_width);
|
||||||
render_move_center_input(Z);
|
render_move_center_input(Z);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
const bool has_connectors = !connectors.empty();
|
||||||
|
|
||||||
const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && bounding_box().center() == m_plane_center;
|
const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && bounding_box().center() == m_plane_center;
|
||||||
m_imgui->disabled_begin(is_cut_plane_init);
|
m_imgui->disabled_begin(is_cut_plane_init);
|
||||||
if (render_reset_button("cut_plane", _u8L("Reset cutting plane")))
|
if (render_reset_button("cut_plane", _u8L("Reset cutting plane")))
|
||||||
reset_cut_plane();
|
reset_cut_plane();
|
||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower);
|
// render_flip_plane_button();
|
||||||
if (m_imgui->button(_L("Add/Edit connectors")))
|
|
||||||
|
add_vertical_scaled_interval(0.75f);
|
||||||
|
|
||||||
|
m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower || m_keep_as_parts);
|
||||||
|
if (m_imgui->button(has_connectors ? _L("Edit connectors") : _L("Add connectors")))
|
||||||
set_connectors_editing(true);
|
set_connectors_editing(true);
|
||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
|
ImGui::SameLine(2.5f * m_label_width);
|
||||||
|
|
||||||
|
m_imgui->disabled_begin(is_cut_plane_init && !has_connectors);
|
||||||
|
if (m_imgui->button(_L("Reset cut"), _L("Reset cutting plane and remove connectors"))) {
|
||||||
|
reset_cut_plane();
|
||||||
|
reset_connectors();
|
||||||
|
}
|
||||||
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
float label_width = 0;
|
// render "After Cut" section
|
||||||
for (const wxString& label : {_L("Upper part"), _L("Lower part")}) {
|
|
||||||
const float width = m_imgui->calc_text_size(label).x + m_imgui->scaled(1.5f);
|
ImVec2 label_size;
|
||||||
if (label_width < width)
|
for (const auto& item : m_part_orientation_names) {
|
||||||
label_width = width;
|
const ImVec2 text_size = ImGuiWrapper::calc_text_size(item.second);
|
||||||
|
if (label_size.x < text_size.x)
|
||||||
|
label_size.x = text_size.x;
|
||||||
|
if (label_size.y < text_size.y)
|
||||||
|
label_size.y = text_size.y;
|
||||||
|
}
|
||||||
|
const float h_shift = label_size.x + m_imgui->scaled(3.f);
|
||||||
|
const float marker_size = label_size.y;
|
||||||
|
|
||||||
|
auto render_part_name = [this, marker_size, has_connectors](const wxString& name, bool& keep_part, const ImU32& color) {
|
||||||
|
bool keep = true;
|
||||||
|
add_horizontal_shift(m_imgui->scaled(1.2f));
|
||||||
|
m_imgui->checkbox((m_keep_as_parts ? _L("Part") : _L("Object")) + " " + name, has_connectors ? keep : keep_part);
|
||||||
|
render_color_marker(marker_size, color);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto render_part_actions = [this, h_shift] (const wxString& suffix, const bool& keep_part, bool& place_on_cut_part, bool& rotate_part)
|
||||||
|
{
|
||||||
|
float shift = m_imgui->scaled(1.2f);
|
||||||
|
if (suffix == "##lower")
|
||||||
|
shift += h_shift;
|
||||||
|
m_imgui->disabled_begin(!keep_part || m_keep_as_parts);
|
||||||
|
add_horizontal_shift(shift);
|
||||||
|
if (m_imgui->radio_button(m_part_orientation_names.at("none") + suffix, !place_on_cut_part && !rotate_part)) {
|
||||||
|
rotate_part = false;
|
||||||
|
place_on_cut_part = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto render_part_action_line = [this, label_width, connectors](const wxString& label, const wxString& suffix, bool& keep_part, bool& place_on_cut_part, bool& rotate_part) {
|
add_horizontal_shift(shift);
|
||||||
bool keep = true;
|
if (m_imgui->radio_button(m_part_orientation_names.at("on_cut") + suffix, place_on_cut_part)) {
|
||||||
ImGui::AlignTextToFramePadding();
|
place_on_cut_part = !place_on_cut_part;
|
||||||
m_imgui->text(label);
|
|
||||||
|
|
||||||
ImGui::SameLine(label_width);
|
|
||||||
|
|
||||||
m_imgui->disabled_begin(!connectors.empty());
|
|
||||||
m_imgui->checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep);
|
|
||||||
m_imgui->disabled_end();
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
m_imgui->disabled_begin(!keep_part);
|
|
||||||
if (m_imgui->checkbox(_L("Place on cut") + suffix, place_on_cut_part))
|
|
||||||
rotate_part = false;
|
rotate_part = false;
|
||||||
ImGui::SameLine();
|
}
|
||||||
if (m_imgui->checkbox(_L("Flip") + suffix, rotate_part))
|
|
||||||
|
add_horizontal_shift(shift);
|
||||||
|
if (m_imgui->radio_button(m_part_orientation_names.at("flip") + suffix, rotate_part)) {
|
||||||
|
rotate_part = !rotate_part;
|
||||||
place_on_cut_part = false;
|
place_on_cut_part = false;
|
||||||
|
}
|
||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
};
|
};
|
||||||
|
|
||||||
m_imgui->text(_L("After cut") + ": ");
|
ImGuiWrapper::text(_L("After cut") + ": ");
|
||||||
render_part_action_line( _L("Upper part"), "##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper);
|
add_vertical_scaled_interval(0.5f);
|
||||||
render_part_action_line( _L("Lower part"), "##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower);
|
|
||||||
|
m_imgui->disabled_begin(has_connectors || m_keep_as_parts);
|
||||||
|
render_part_name("A", m_keep_upper, m_imgui->to_ImU32(UPPER_PART_COLOR));
|
||||||
|
ImGui::SameLine(h_shift + ImGui::GetCurrentWindow()->WindowPadding.x);
|
||||||
|
render_part_name("B", m_keep_lower, m_imgui->to_ImU32(LOWER_PART_COLOR));
|
||||||
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
|
add_vertical_scaled_interval(0.5f);
|
||||||
|
|
||||||
|
const ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos;
|
||||||
|
render_part_actions("##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper);
|
||||||
|
|
||||||
|
ImGui::GetCurrentWindow()->DC.CursorPos = pos;
|
||||||
|
render_part_actions("##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower);
|
||||||
|
|
||||||
|
add_vertical_scaled_interval(0.75f);
|
||||||
|
|
||||||
|
m_imgui->disabled_begin(has_connectors);
|
||||||
|
add_horizontal_shift(m_imgui->scaled(/*1*/.2f));
|
||||||
|
ImGuiWrapper::text(_L("Cut to") + ":");
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (m_imgui->radio_button(_L("Objects"), !m_keep_as_parts))
|
||||||
|
m_keep_as_parts = false;
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (m_imgui->radio_button(_L("Parts"), m_keep_as_parts))
|
||||||
|
m_keep_as_parts = true;
|
||||||
|
|
||||||
|
if (m_keep_as_parts) {
|
||||||
|
m_keep_upper = m_keep_lower = true;
|
||||||
|
m_place_on_cut_upper = m_place_on_cut_lower = false;
|
||||||
|
m_rotate_upper = m_rotate_lower = false;
|
||||||
|
}
|
||||||
|
m_imgui->disabled_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
@ -2110,11 +2238,13 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
|||||||
plater->cut(object_idx, instance_idx, translation_transform(cut_center_offset) * m_rotation_m,
|
plater->cut(object_idx, instance_idx, translation_transform(cut_center_offset) * m_rotation_m,
|
||||||
only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) |
|
only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) |
|
||||||
only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) |
|
only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) |
|
||||||
|
only_if(has_connectors ? false: m_keep_as_parts, ModelObjectCutAttribute::KeepAsParts) |
|
||||||
only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) |
|
only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) |
|
||||||
only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) |
|
only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) |
|
||||||
only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) |
|
only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) |
|
||||||
only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) |
|
only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) |
|
||||||
only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels));
|
only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels) |
|
||||||
|
only_if(!has_connectors, ModelObjectCutAttribute::InvalidateCutInfo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2349,7 +2479,7 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi
|
|||||||
if (is_dragging() || m_connector_mode == CutConnectorMode::Auto)
|
if (is_dragging() || m_connector_mode == CutConnectorMode::Auto)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ( m_hover_id < 0 && shift_down && ! m_connectors_editing &&
|
if ( (m_hover_id < 0 || m_hover_id == CutPlane) && shift_down && ! m_connectors_editing &&
|
||||||
(action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::Moving) )
|
(action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::Moving) )
|
||||||
return process_cut_line(action, mouse_position);
|
return process_cut_line(action, mouse_position);
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "slic3r/GUI/GLModel.hpp"
|
#include "slic3r/GUI/GLModel.hpp"
|
||||||
#include "libslic3r/TriangleMesh.hpp"
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -20,6 +21,14 @@ enum class SLAGizmoEventType : unsigned char;
|
|||||||
|
|
||||||
class GLGizmoCut3D : public GLGizmoBase
|
class GLGizmoCut3D : public GLGizmoBase
|
||||||
{
|
{
|
||||||
|
enum GrabberID {
|
||||||
|
X = 0,
|
||||||
|
Y,
|
||||||
|
Z,
|
||||||
|
CutPlane,
|
||||||
|
Count,
|
||||||
|
};
|
||||||
|
|
||||||
Transform3d m_rotation_m{ Transform3d::Identity() };
|
Transform3d m_rotation_m{ Transform3d::Identity() };
|
||||||
double m_snap_step{ 1.0 };
|
double m_snap_step{ 1.0 };
|
||||||
int m_connectors_group_id;
|
int m_connectors_group_id;
|
||||||
@ -57,10 +66,10 @@ class GLGizmoCut3D : public GLGizmoBase
|
|||||||
|
|
||||||
Vec2d m_ldown_mouse_position{ Vec2d::Zero() };
|
Vec2d m_ldown_mouse_position{ Vec2d::Zero() };
|
||||||
|
|
||||||
GLModel m_plane;
|
|
||||||
GLModel m_grabber_connection;
|
GLModel m_grabber_connection;
|
||||||
GLModel m_cut_line;
|
GLModel m_cut_line;
|
||||||
|
|
||||||
|
PickingModel m_plane;
|
||||||
PickingModel m_sphere;
|
PickingModel m_sphere;
|
||||||
PickingModel m_cone;
|
PickingModel m_cone;
|
||||||
std::map<CutConnectorAttributes, PickingModel> m_shapes;
|
std::map<CutConnectorAttributes, PickingModel> m_shapes;
|
||||||
@ -90,6 +99,7 @@ class GLGizmoCut3D : public GLGizmoBase
|
|||||||
|
|
||||||
bool m_keep_upper{ true };
|
bool m_keep_upper{ true };
|
||||||
bool m_keep_lower{ true };
|
bool m_keep_lower{ true };
|
||||||
|
bool m_keep_as_parts{ false };
|
||||||
bool m_place_on_cut_upper{ true };
|
bool m_place_on_cut_upper{ true };
|
||||||
bool m_place_on_cut_lower{ false };
|
bool m_place_on_cut_lower{ false };
|
||||||
bool m_rotate_upper{ false };
|
bool m_rotate_upper{ false };
|
||||||
@ -121,6 +131,7 @@ class GLGizmoCut3D : public GLGizmoBase
|
|||||||
GLSelectionRectangle m_selection_rectangle;
|
GLSelectionRectangle m_selection_rectangle;
|
||||||
|
|
||||||
bool m_has_invalid_connector{ false };
|
bool m_has_invalid_connector{ false };
|
||||||
|
bool m_was_cut_plane_dragged { false };
|
||||||
|
|
||||||
bool m_show_shortcuts{ false };
|
bool m_show_shortcuts{ false };
|
||||||
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
||||||
@ -154,6 +165,8 @@ class GLGizmoCut3D : public GLGizmoBase
|
|||||||
|
|
||||||
std::vector<std::string> m_axis_names;
|
std::vector<std::string> m_axis_names;
|
||||||
|
|
||||||
|
std::map<std::string, wxString> m_part_orientation_names;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||||
|
|
||||||
@ -192,7 +205,7 @@ protected:
|
|||||||
void on_set_hover_id() override;
|
void on_set_hover_id() override;
|
||||||
bool on_is_activable() const override;
|
bool on_is_activable() const override;
|
||||||
bool on_is_selectable() const override;
|
bool on_is_selectable() const override;
|
||||||
Vec3d mouse_position_in_local_plane(Axis axis, const Linef3&mouse_ray) const;
|
Vec3d mouse_position_in_local_plane(GrabberID axis, const Linef3&mouse_ray) const;
|
||||||
void dragging_grabber_z(const GLGizmoBase::UpdateData &data);
|
void dragging_grabber_z(const GLGizmoBase::UpdateData &data);
|
||||||
void dragging_grabber_xy(const GLGizmoBase::UpdateData &data);
|
void dragging_grabber_xy(const GLGizmoBase::UpdateData &data);
|
||||||
void dragging_connector(const GLGizmoBase::UpdateData &data);
|
void dragging_connector(const GLGizmoBase::UpdateData &data);
|
||||||
@ -211,6 +224,12 @@ protected:
|
|||||||
void render_build_size();
|
void render_build_size();
|
||||||
void reset_cut_plane();
|
void reset_cut_plane();
|
||||||
void set_connectors_editing(bool connectors_editing);
|
void set_connectors_editing(bool connectors_editing);
|
||||||
|
void flip_cut_plane();
|
||||||
|
void render_flip_plane_button(bool disable_pred = false);
|
||||||
|
void add_vertical_scaled_interval(float interval);
|
||||||
|
void add_horizontal_scaled_interval(float interval);
|
||||||
|
void add_horizontal_shift(float shift);
|
||||||
|
void render_color_marker(float size, const ImU32& color);
|
||||||
void render_cut_plane_input_window(CutConnectors &connectors);
|
void render_cut_plane_input_window(CutConnectors &connectors);
|
||||||
void init_input_window_data(CutConnectors &connectors);
|
void init_input_window_data(CutConnectors &connectors);
|
||||||
void render_input_window_warning() const;
|
void render_input_window_warning() const;
|
||||||
@ -258,7 +277,7 @@ private:
|
|||||||
void render_cut_plane();
|
void render_cut_plane();
|
||||||
void render_model(GLModel& model, const ColorRGBA& color, Transform3d view_model_matrix);
|
void render_model(GLModel& model, const ColorRGBA& color, Transform3d view_model_matrix);
|
||||||
void render_line(GLModel& line_model, const ColorRGBA& color, Transform3d view_model_matrix, float width);
|
void render_line(GLModel& line_model, const ColorRGBA& color, Transform3d view_model_matrix, float width);
|
||||||
void render_rotation_snapping(Axis axis, const ColorRGBA& color);
|
void render_rotation_snapping(GrabberID axis, const ColorRGBA& color);
|
||||||
void render_grabber_connection(const ColorRGBA& color, Transform3d view_matrix);
|
void render_grabber_connection(const ColorRGBA& color, Transform3d view_matrix);
|
||||||
void render_cut_plane_grabbers();
|
void render_cut_plane_grabbers();
|
||||||
void render_cut_line();
|
void render_cut_line();
|
||||||
|
@ -519,6 +519,13 @@ bool GLGizmoFdmSupports::has_backend_supports()
|
|||||||
|
|
||||||
void GLGizmoFdmSupports::auto_generate()
|
void GLGizmoFdmSupports::auto_generate()
|
||||||
{
|
{
|
||||||
|
std::string err = wxGetApp().plater()->fff_print().validate();
|
||||||
|
if (!err.empty()) {
|
||||||
|
MessageDialog dlg(GUI::wxGetApp().plater(), _L("Automatic painting requires valid print setup. \n") + err, _L("Warning"), wxOK);
|
||||||
|
dlg.ShowModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ModelObject *mo = m_c->selection_info()->model_object();
|
ModelObject *mo = m_c->selection_info()->model_object();
|
||||||
bool not_painted = std::all_of(mo->volumes.begin(), mo->volumes.end(), [](const ModelVolume* vol){
|
bool not_painted = std::all_of(mo->volumes.begin(), mo->volumes.end(), [](const ModelVolume* vol){
|
||||||
return vol->type() != ModelVolumeType::MODEL_PART || vol->supported_facets.empty();
|
return vol->type() != ModelVolumeType::MODEL_PART || vol->supported_facets.empty();
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||||
#include "slic3r/GUI/GUI_App.hpp"
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
|
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||||
@ -38,6 +38,7 @@ bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event)
|
|||||||
// Rotate the object so the normal points downward:
|
// Rotate the object so the normal points downward:
|
||||||
selection.flattening_rotate(m_planes[m_hover_id].normal);
|
selection.flattening_rotate(m_planes[m_hover_id].normal);
|
||||||
m_parent.do_rotate(L("Gizmo-Place on Face"));
|
m_parent.do_rotate(L("Gizmo-Place on Face"));
|
||||||
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
|
|||||||
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
||||||
// in our case plane normal and ray direction are the same (orthogonal view)
|
// in our case plane normal and ray direction are the same (orthogonal view)
|
||||||
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
||||||
const Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
|
const Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) * mouse_dir;
|
||||||
// vector from the starting position to the found intersection
|
// vector from the starting position to the found intersection
|
||||||
const Vec3d inters_vec = inters - m_starting_drag_position;
|
const Vec3d inters_vec = inters - m_starting_drag_position;
|
||||||
|
|
||||||
|
@ -238,7 +238,13 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
|||||||
selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system();
|
selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system();
|
||||||
m_bounding_box = box;
|
m_bounding_box = box;
|
||||||
m_center = box_trafo.translation();
|
m_center = box_trafo.translation();
|
||||||
m_orient_matrix = box_trafo;
|
m_orient_matrix = Geometry::translation_transform(m_center);
|
||||||
|
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||||
|
const GLVolume& v = *selection.get_first_volume();
|
||||||
|
m_orient_matrix = m_orient_matrix * v.get_instance_transformation().get_rotation_matrix();
|
||||||
|
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
|
||||||
|
m_orient_matrix = m_orient_matrix * v.get_volume_transformation().get_rotation_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
m_radius = Offset + m_bounding_box.radius();
|
m_radius = Offset + m_bounding_box.radius();
|
||||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||||
|
@ -218,15 +218,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
m_bounding_box = box;
|
m_bounding_box = box;
|
||||||
m_center = box_trafo.translation();
|
m_center = box_trafo.translation();
|
||||||
m_grabbers_transform = box_trafo;
|
m_grabbers_transform = box_trafo;
|
||||||
m_instance_center = Vec3d::Zero();
|
m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
|
||||||
if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates())
|
|
||||||
m_instance_center = selection.get_first_volume()->get_instance_offset();
|
|
||||||
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates())
|
|
||||||
m_instance_center = m_center;
|
|
||||||
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
|
|
||||||
m_instance_center = m_center;
|
|
||||||
else
|
|
||||||
m_instance_center = selection.is_single_full_instance() ? selection.get_first_volume()->get_instance_offset() : m_center;
|
|
||||||
|
|
||||||
// x axis
|
// x axis
|
||||||
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
|
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
|
||||||
@ -264,9 +256,8 @@ void GLGizmoScale3D::on_render()
|
|||||||
#endif // ENABLE_GL_CORE_PROFILE
|
#endif // ENABLE_GL_CORE_PROFILE
|
||||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||||
|
|
||||||
const Transform3d base_matrix = local_transform(selection);
|
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
m_grabbers[i].matrix = base_matrix;
|
m_grabbers[i].matrix = m_grabbers_transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
|
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
|
||||||
@ -281,7 +272,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
|
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_transform);
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
#if ENABLE_GL_CORE_PROFILE
|
#if ENABLE_GL_CORE_PROFILE
|
||||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||||
@ -315,7 +306,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
|
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_transform);
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
#if ENABLE_GL_CORE_PROFILE
|
#if ENABLE_GL_CORE_PROFILE
|
||||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||||
@ -332,8 +323,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
shader->set_uniform("emission_factor", 0.1f);
|
shader->set_uniform("emission_factor", 0.1f);
|
||||||
m_grabbers[0].render(true, grabber_mean_size);
|
render_grabbers(0, 1, grabber_mean_size, true);
|
||||||
m_grabbers[1].render(true, grabber_mean_size);
|
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,7 +337,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
|
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_transform);
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
#if ENABLE_GL_CORE_PROFILE
|
#if ENABLE_GL_CORE_PROFILE
|
||||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||||
@ -364,8 +354,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
shader->set_uniform("emission_factor", 0.1f);
|
shader->set_uniform("emission_factor", 0.1f);
|
||||||
m_grabbers[2].render(true, grabber_mean_size);
|
render_grabbers(2, 3, grabber_mean_size, true);
|
||||||
m_grabbers[3].render(true, grabber_mean_size);
|
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,7 +368,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
|
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_transform);
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
#if ENABLE_GL_CORE_PROFILE
|
#if ENABLE_GL_CORE_PROFILE
|
||||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||||
@ -396,8 +385,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
shader->set_uniform("emission_factor", 0.1f);
|
shader->set_uniform("emission_factor", 0.1f);
|
||||||
m_grabbers[4].render(true, grabber_mean_size);
|
render_grabbers(4, 5, grabber_mean_size, true);
|
||||||
m_grabbers[5].render(true, grabber_mean_size);
|
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -411,7 +399,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
|
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_transform);
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
#if ENABLE_GL_CORE_PROFILE
|
#if ENABLE_GL_CORE_PROFILE
|
||||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||||
@ -431,9 +419,7 @@ void GLGizmoScale3D::on_render()
|
|||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
shader->set_uniform("emission_factor", 0.1f);
|
shader->set_uniform("emission_factor", 0.1f);
|
||||||
for (int i = 6; i < 10; ++i) {
|
render_grabbers(6, 9, grabber_mean_size, true);
|
||||||
m_grabbers[i].render(true, grabber_mean_size);
|
|
||||||
}
|
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -757,7 +743,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||||||
double ratio = calc_ratio(data);
|
double ratio = calc_ratio(data);
|
||||||
if (ratio > 0.0) {
|
if (ratio > 0.0) {
|
||||||
Vec3d curr_scale = m_scale;
|
Vec3d curr_scale = m_scale;
|
||||||
Vec3d starting_scale = m_starting.scale;
|
const Vec3d starting_scale = m_starting.scale;
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||||
|
|
||||||
@ -770,13 +756,6 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||||||
if (m_hover_id == 2 * axis)
|
if (m_hover_id == 2 * axis)
|
||||||
local_offset *= -1.0;
|
local_offset *= -1.0;
|
||||||
|
|
||||||
Vec3d center_offset = m_starting.instance_center - m_starting.center; // world coordinates (== Vec3d::Zero() for single volume selection)
|
|
||||||
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
|
|
||||||
// from world coordinates to instance coordinates
|
|
||||||
center_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix().inverse() * center_offset;
|
|
||||||
|
|
||||||
local_offset += (ratio - 1.0) * center_offset(axis);
|
|
||||||
|
|
||||||
switch (axis)
|
switch (axis)
|
||||||
{
|
{
|
||||||
case X: { m_offset = local_offset * Vec3d::UnitX(); break; }
|
case X: { m_offset = local_offset * Vec3d::UnitX(); break; }
|
||||||
@ -785,10 +764,6 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||||||
default: { m_offset = Vec3d::Zero(); break; }
|
default: { m_offset = Vec3d::Zero(); break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
|
|
||||||
// from instance coordinates to world coordinates
|
|
||||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix() * m_offset;
|
|
||||||
|
|
||||||
if (selection.is_single_volume_or_modifier()) {
|
if (selection.is_single_volume_or_modifier()) {
|
||||||
if (coordinates_type == ECoordinatesType::Instance)
|
if (coordinates_type == ECoordinatesType::Instance)
|
||||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
|
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
|
||||||
@ -849,18 +824,6 @@ void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
|
|||||||
if (m_hover_id == 6 || m_hover_id == 7)
|
if (m_hover_id == 6 || m_hover_id == 7)
|
||||||
m_offset.y() *= -1.0;
|
m_offset.y() *= -1.0;
|
||||||
|
|
||||||
Vec3d center_offset = m_starting.instance_center - m_starting.center; // world coordinates (== Vec3d::Zero() for single volume selection)
|
|
||||||
|
|
||||||
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
|
|
||||||
// from world coordinates to instance coordinates
|
|
||||||
center_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix().inverse() * center_offset;
|
|
||||||
|
|
||||||
m_offset += (ratio - 1.0) * center_offset;
|
|
||||||
|
|
||||||
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
|
|
||||||
// from instance coordinates to world coordinates
|
|
||||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix() * m_offset;
|
|
||||||
|
|
||||||
if (selection.is_single_volume_or_modifier()) {
|
if (selection.is_single_volume_or_modifier()) {
|
||||||
if (coordinates_type == ECoordinatesType::Instance)
|
if (coordinates_type == ECoordinatesType::Instance)
|
||||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
|
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
|
||||||
@ -904,7 +867,7 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
|||||||
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
||||||
// in our case plane normal and ray direction are the same (orthogonal view)
|
// in our case plane normal and ray direction are the same (orthogonal view)
|
||||||
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
||||||
const Vec3d inters = data.mouse_ray.a + (m_starting.drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
|
const Vec3d inters = data.mouse_ray.a + (m_starting.drag_position - data.mouse_ray.a).dot(mouse_dir) * mouse_dir;
|
||||||
// vector from the starting position to the found intersection
|
// vector from the starting position to the found intersection
|
||||||
const Vec3d inters_vec = inters - m_starting.drag_position;
|
const Vec3d inters_vec = inters - m_starting.drag_position;
|
||||||
|
|
||||||
@ -920,20 +883,5 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
|||||||
return ratio;
|
return ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
Transform3d GLGizmoScale3D::local_transform(const Selection& selection) const
|
|
||||||
{
|
|
||||||
Transform3d ret = Geometry::translation_transform(m_center);
|
|
||||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
|
||||||
const GLVolume& v = *selection.get_first_volume();
|
|
||||||
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
|
|
||||||
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
|
|
||||||
orient_matrix = orient_matrix * v.get_volume_transformation().get_rotation_matrix();
|
|
||||||
ret = ret * orient_matrix;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
@ -102,9 +102,6 @@ private:
|
|||||||
void do_scale_uniform(const UpdateData& data);
|
void do_scale_uniform(const UpdateData& data);
|
||||||
|
|
||||||
double calc_ratio(const UpdateData& data) const;
|
double calc_ratio(const UpdateData& data) const;
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
Transform3d local_transform(const Selection& selection) const;
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -453,10 +453,17 @@ void ImGuiWrapper::end()
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGuiWrapper::button(const wxString &label)
|
bool ImGuiWrapper::button(const wxString &label, const wxString& tooltip)
|
||||||
{
|
{
|
||||||
auto label_utf8 = into_u8(label);
|
auto label_utf8 = into_u8(label);
|
||||||
return ImGui::Button(label_utf8.c_str());
|
const bool ret = ImGui::Button(label_utf8.c_str());
|
||||||
|
|
||||||
|
if (!tooltip.IsEmpty() && ImGui::IsItemHovered()) {
|
||||||
|
auto tooltip_utf8 = into_u8(tooltip);
|
||||||
|
ImGui::SetTooltip(tooltip_utf8.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGuiWrapper::button(const wxString& label, float width, float height)
|
bool ImGuiWrapper::button(const wxString& label, float width, float height)
|
||||||
|
@ -91,7 +91,7 @@ public:
|
|||||||
bool begin(const wxString& name, bool* close, int flags = 0);
|
bool begin(const wxString& name, bool* close, int flags = 0);
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
bool button(const wxString &label);
|
bool button(const wxString &label, const wxString& tooltip = {});
|
||||||
bool button(const wxString& label, float width, float height);
|
bool button(const wxString& label, float width, float height);
|
||||||
bool button(const wxString& label, const ImVec2 &size, bool enable); // default size = ImVec2(0.f, 0.f)
|
bool button(const wxString& label, const ImVec2 &size, bool enable); // default size = ImVec2(0.f, 0.f)
|
||||||
bool radio_button(const wxString &label, bool active);
|
bool radio_button(const wxString &label, bool active);
|
||||||
|
@ -1038,6 +1038,15 @@ void ogStaticText::SetText(const wxString& value, bool wrap/* = true*/)
|
|||||||
|
|
||||||
void ogStaticText::SetPathEnd(const std::string& link)
|
void ogStaticText::SetPathEnd(const std::string& link)
|
||||||
{
|
{
|
||||||
|
#ifndef __linux__
|
||||||
|
|
||||||
|
Bind(wxEVT_ENTER_WINDOW, [this, link](wxMouseEvent& event) {
|
||||||
|
SetToolTip(OptionsGroup::get_url(get_app_config()->get("suppress_hyperlinks") != "1" ? link : std::string()));
|
||||||
|
FocusText(true);
|
||||||
|
event.Skip();
|
||||||
|
});
|
||||||
|
Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) { FocusText(false); event.Skip(); });
|
||||||
|
|
||||||
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& event) {
|
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& event) {
|
||||||
if (HasCapture())
|
if (HasCapture())
|
||||||
return;
|
return;
|
||||||
@ -1051,12 +1060,28 @@ void ogStaticText::SetPathEnd(const std::string& link)
|
|||||||
OptionsGroup::launch_browser(link);
|
OptionsGroup::launch_browser(link);
|
||||||
event.Skip();
|
event.Skip();
|
||||||
});
|
});
|
||||||
Bind(wxEVT_ENTER_WINDOW, [this, link](wxMouseEvent& event) {
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Workaround: On Linux wxStaticText doesn't receive wxEVT_ENTER(LEAVE)_WINDOW events,
|
||||||
|
// so implement this behaviour trough wxEVT_MOTION events for this control and it's parent
|
||||||
|
Bind(wxEVT_MOTION, [link, this](wxMouseEvent& event) {
|
||||||
SetToolTip(OptionsGroup::get_url(!get_app_config()->get_bool("suppress_hyperlinks") ? link : std::string()));
|
SetToolTip(OptionsGroup::get_url(!get_app_config()->get_bool("suppress_hyperlinks") ? link : std::string()));
|
||||||
FocusText(true);
|
FocusText(true);
|
||||||
event.Skip();
|
event.Skip();
|
||||||
});
|
});
|
||||||
Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) { FocusText(false); event.Skip(); });
|
GetParent()->Bind(wxEVT_MOTION, [this](wxMouseEvent& event) {
|
||||||
|
FocusText(false);
|
||||||
|
event.Skip();
|
||||||
|
});
|
||||||
|
|
||||||
|
// On Linux a mouse capturing causes a totally application freeze
|
||||||
|
Bind(wxEVT_LEFT_UP, [link, this](wxMouseEvent& event) {
|
||||||
|
OptionsGroup::launch_browser(link);
|
||||||
|
event.Skip();
|
||||||
|
});
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ogStaticText::FocusText(bool focus)
|
void ogStaticText::FocusText(bool focus)
|
||||||
@ -1066,6 +1091,9 @@ void ogStaticText::FocusText(bool focus)
|
|||||||
|
|
||||||
SetFont(focus ? Slic3r::GUI::wxGetApp().link_font() :
|
SetFont(focus ? Slic3r::GUI::wxGetApp().link_font() :
|
||||||
Slic3r::GUI::wxGetApp().normal_font());
|
Slic3r::GUI::wxGetApp().normal_font());
|
||||||
|
#ifdef __linux__
|
||||||
|
this->GetContainingSizer()->Layout();
|
||||||
|
#endif
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
|
|||||||
choice->set_selection();
|
choice->set_selection();
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
update(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicalPrinterDialog::update_printhost_buttons()
|
void PhysicalPrinterDialog::update_printhost_buttons()
|
||||||
@ -632,11 +632,12 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change)
|
|||||||
|
|
||||||
Choice* choice = dynamic_cast<Choice*>(ht);
|
Choice* choice = dynamic_cast<Choice*>(ht);
|
||||||
choice->set_values(types);
|
choice->set_values(types);
|
||||||
int index_in_choice = (printer_change ? 0 : last_in_conf);
|
int dif = (int)ht->m_opt.enum_def->values().size() - (int)types.size();
|
||||||
|
int index_in_choice = (printer_change ? std::clamp(last_in_conf - ((int)ht->m_opt.enum_def->values().size() - (int)types.size()), 0, (int)ht->m_opt.enum_def->values().size() - 1) : last_in_conf);
|
||||||
choice->set_value(index_in_choice);
|
choice->set_value(index_in_choice);
|
||||||
if (link.supported && link.label == _(ht->m_opt.enum_def->label(index_in_choice)))
|
if (link.supported && link.label == _(ht->m_opt.enum_def->label(index_in_choice)))
|
||||||
m_config->set_key_value("host_type", new ConfigOptionEnum<PrintHostType>(htPrusaLink));
|
m_config->set_key_value("host_type", new ConfigOptionEnum<PrintHostType>(htPrusaLink));
|
||||||
else if (link.supported && link.label == _(ht->m_opt.enum_def->label(index_in_choice)))
|
else if (connect.supported && connect.label == _(ht->m_opt.enum_def->label(index_in_choice)))
|
||||||
m_config->set_key_value("host_type", new ConfigOptionEnum<PrintHostType>(htPrusaConnect));
|
m_config->set_key_value("host_type", new ConfigOptionEnum<PrintHostType>(htPrusaConnect));
|
||||||
else {
|
else {
|
||||||
int host_type = std::clamp(index_in_choice + ((int)ht->m_opt.enum_def->values().size() - (int)types.size()), 0, (int)ht->m_opt.enum_def->values().size() - 1);
|
int host_type = std::clamp(index_in_choice + ((int)ht->m_opt.enum_def->values().size() - (int)types.size()), 0, (int)ht->m_opt.enum_def->values().size() - 1);
|
||||||
|
@ -836,108 +836,57 @@ const std::pair<BoundingBoxf3, Transform3d>& Selection::get_bounding_box_in_curr
|
|||||||
|
|
||||||
std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_system(ECoordinatesType type) const
|
std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_system(ECoordinatesType type) const
|
||||||
{
|
{
|
||||||
BoundingBoxf3 original_box;
|
//
|
||||||
|
// trafo to current reference system
|
||||||
|
//
|
||||||
Transform3d trafo;
|
Transform3d trafo;
|
||||||
|
|
||||||
//
|
|
||||||
// calculate box aligned to current reference system
|
|
||||||
//
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ECoordinatesType::World:
|
case ECoordinatesType::World: { trafo = Transform3d::Identity(); break; }
|
||||||
{
|
case ECoordinatesType::Instance: { trafo = get_first_volume()->get_instance_transformation().get_matrix(); break; }
|
||||||
original_box = get_bounding_box();
|
case ECoordinatesType::Local: { trafo = get_first_volume()->world_matrix(); break; }
|
||||||
trafo = Transform3d::Identity();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoordinatesType::Instance: {
|
|
||||||
for (unsigned int id : m_list) {
|
|
||||||
const GLVolume& v = *get_volume(id);
|
|
||||||
original_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
|
|
||||||
}
|
|
||||||
trafo = get_first_volume()->get_instance_transformation().get_matrix();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoordinatesType::Local: {
|
|
||||||
assert(is_single_volume_or_modifier() || is_single_volume_instance());
|
|
||||||
const GLVolume& v = *get_first_volume();
|
|
||||||
original_box = v.bounding_box();
|
|
||||||
trafo = v.world_matrix();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// calculate box size in world coordinates
|
// trafo basis in world coordinates
|
||||||
//
|
//
|
||||||
auto point_to_Vec4d = [](const Vec3d& p) { return Vec4d(p.x(), p.y(), p.z(), 1.0); };
|
Geometry::Transformation t(trafo);
|
||||||
auto Vec4d_to_Vec3d = [](const Vec4d& v) { return Vec3d(v.x(), v.y(), v.z()); };
|
t.reset_scaling_factor();
|
||||||
|
const Transform3d basis_trafo = t.get_matrix_no_offset();
|
||||||
auto apply_transform = [](const std::vector<Vec4d>& original, const Transform3d& trafo, bool normalize) {
|
std::vector<Vec3d> axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
|
||||||
std::vector<Vec4d> transformed(original.size());
|
for (size_t i = 0; i < axes.size(); ++i) {
|
||||||
for (size_t i = 0; i < original.size(); ++i) {
|
axes[i] = basis_trafo * axes[i];
|
||||||
transformed[i] = trafo * original[i];
|
|
||||||
if (normalize)
|
|
||||||
transformed[i].normalize();
|
|
||||||
}
|
|
||||||
return transformed;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto calc_box_size = [point_to_Vec4d, Vec4d_to_Vec3d, apply_transform](const BoundingBoxf3& box, const Transform3d& trafo) {
|
|
||||||
Geometry::Transformation transformation(trafo);
|
|
||||||
|
|
||||||
// box aligned to current reference system
|
|
||||||
std::vector<Vec4d> homo_vertices = {
|
|
||||||
point_to_Vec4d({ box.min.x(), box.min.y(), box.min.z() }),
|
|
||||||
point_to_Vec4d({ box.max.x(), box.min.y(), box.min.z() }),
|
|
||||||
point_to_Vec4d({ box.max.x(), box.max.y(), box.min.z() }),
|
|
||||||
point_to_Vec4d({ box.min.x(), box.max.y(), box.min.z() }),
|
|
||||||
point_to_Vec4d({ box.min.x(), box.min.y(), box.max.z() }),
|
|
||||||
point_to_Vec4d({ box.max.x(), box.min.y(), box.max.z() }),
|
|
||||||
point_to_Vec4d({ box.max.x(), box.max.y(), box.max.z() }),
|
|
||||||
point_to_Vec4d({ box.min.x(), box.max.y(), box.max.z() })
|
|
||||||
};
|
|
||||||
|
|
||||||
// box vertices in world coordinates
|
|
||||||
std::vector<Vec4d> transformed_homo_vertices = apply_transform(homo_vertices, trafo, false);
|
|
||||||
|
|
||||||
// project back to current reference system
|
|
||||||
const std::vector<Vec4d> homo_axes = { Vec4d::UnitX(), Vec4d::UnitY(), Vec4d::UnitZ() };
|
|
||||||
std::vector<Vec4d> transformed_homo_axes = apply_transform(homo_axes, Geometry::Transformation(trafo).get_matrix_no_scaling_factor(), true);
|
|
||||||
std::vector<Vec3d> transformed_axes(transformed_homo_axes.size());
|
|
||||||
for (size_t i = 0; i < transformed_homo_axes.size(); ++i) {
|
|
||||||
transformed_axes[i] = Vec4d_to_Vec3d(transformed_homo_axes[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// calculate bounding box aligned to trafo basis
|
||||||
|
//
|
||||||
Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX };
|
Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX };
|
||||||
Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX };
|
Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX };
|
||||||
|
for (unsigned int id : m_list) {
|
||||||
for (const Vec4d& v_homo : transformed_homo_vertices) {
|
const GLVolume& vol = *get_volume(id);
|
||||||
const Vec3d v = Vec4d_to_Vec3d(v_homo);
|
const Transform3d vol_world_rafo = vol.world_matrix();
|
||||||
|
const TriangleMesh* mesh = vol.convex_hull();
|
||||||
|
if (mesh == nullptr)
|
||||||
|
mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh();
|
||||||
|
assert(mesh != nullptr);
|
||||||
|
for (const stl_vertex& v : mesh->its.vertices) {
|
||||||
|
const Vec3d world_v = vol_world_rafo * v.cast<double>();
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
const double dot_i = v.dot(transformed_axes[i]);
|
const double i_comp = world_v.dot(axes[i]);
|
||||||
min(i) = std::min(min(i), dot_i);
|
min(i) = std::min(min(i), i_comp);
|
||||||
max(i) = std::max(max(i), dot_i);
|
max(i) = std::max(max(i), i_comp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// return size
|
const Vec3d box_size = max - min;
|
||||||
const Vec3d size = max - min;
|
|
||||||
return size;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Vec3d box_size = calc_box_size(original_box, trafo);
|
|
||||||
const std::vector<Vec4d> box_center = { point_to_Vec4d(original_box.center()) };
|
|
||||||
std::vector<Vec4d> transformed_box_center = apply_transform(box_center, trafo, false);
|
|
||||||
|
|
||||||
//
|
|
||||||
// return box centered at 0, 0, 0
|
|
||||||
//
|
|
||||||
const Vec3d half_box_size = 0.5 * box_size;
|
const Vec3d half_box_size = 0.5 * box_size;
|
||||||
BoundingBoxf3 out_box(-half_box_size, half_box_size);
|
BoundingBoxf3 out_box(-half_box_size, half_box_size);
|
||||||
Geometry::Transformation out_trafo(trafo);
|
Geometry::Transformation out_trafo(trafo);
|
||||||
out_trafo.set_offset(Vec4d_to_Vec3d(transformed_box_center[0]));
|
const Vec3d center = 0.5 * (min + max);
|
||||||
|
out_trafo.set_offset(basis_trafo * center);
|
||||||
return { out_box, out_trafo.get_matrix_no_scaling_factor() };
|
return { out_box, out_trafo.get_matrix_no_scaling_factor() };
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
@ -1049,7 +998,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
|||||||
|
|
||||||
assert(transformation_type.relative() || (transformation_type.absolute() && transformation_type.local()));
|
assert(transformation_type.relative() || (transformation_type.absolute() && transformation_type.local()));
|
||||||
|
|
||||||
const Transform3d rotation_matrix = Geometry::rotation_transform(rotation);
|
Transform3d rotation_matrix = Geometry::rotation_transform(rotation);
|
||||||
|
|
||||||
for (unsigned int i : m_list) {
|
for (unsigned int i : m_list) {
|
||||||
GLVolume& v = *(*m_volumes)[i];
|
GLVolume& v = *(*m_volumes)[i];
|
||||||
@ -1074,31 +1023,50 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
|||||||
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (transformation_type.local() && transformation_type.absolute()) {
|
if (transformation_type.instance()) {
|
||||||
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
||||||
Matrix3d vol_rotation, vol_scale;
|
const Geometry::Transformation world_trafo = inst_trafo * vol_trafo;
|
||||||
vol_trafo.get_matrix().computeRotationScaling(&vol_rotation, &vol_scale);
|
// ensure proper sign of rotation for mirrored objects
|
||||||
const Transform3d trafo = vol_trafo.get_rotation_matrix() * rotation_matrix;
|
if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX()))
|
||||||
v.set_volume_transformation(vol_trafo.get_offset_matrix() * trafo * Transform3d(vol_scale));
|
rotation_matrix = rotation_matrix.inverse();
|
||||||
|
|
||||||
|
// ensure that the volume rotates as a rigid body
|
||||||
|
const Geometry::TransformationSVD world_svd(world_trafo);
|
||||||
|
if (world_svd.anisotropic_scale) {
|
||||||
|
const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix();
|
||||||
|
rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix;
|
||||||
|
}
|
||||||
|
const Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix();
|
||||||
|
rotation_matrix = vol_rotation_matrix.inverse() * rotation_matrix * vol_rotation_matrix;
|
||||||
|
|
||||||
|
v.set_volume_transformation(vol_trafo.get_matrix() * rotation_matrix);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (transformation_type.local()) {
|
||||||
|
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
||||||
|
const Geometry::Transformation world_trafo = inst_trafo * vol_trafo;
|
||||||
|
// ensure proper sign of rotation for mirrored objects
|
||||||
|
if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX()))
|
||||||
|
rotation_matrix = rotation_matrix.inverse();
|
||||||
|
|
||||||
|
// ensure that the volume rotates as a rigid body
|
||||||
|
const Geometry::TransformationSVD svd(world_trafo);
|
||||||
|
if (svd.anisotropic_scale) {
|
||||||
|
const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix();
|
||||||
|
rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if !DISABLE_INSTANCES_SYNCH
|
#if !DISABLE_INSTANCES_SYNCH
|
||||||
if (m_mode == Instance) {
|
if (m_mode == Instance) {
|
||||||
int rot_axis_max = 0;
|
int rot_axis_max = 0;
|
||||||
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
||||||
SyncRotationType synch;
|
synchronize_unselected_instances((transformation_type.world() && rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL);
|
||||||
if (transformation_type.world() && rot_axis_max == 2)
|
|
||||||
synch = SyncRotationType::NONE;
|
|
||||||
else if (transformation_type.instance())
|
|
||||||
synch = SyncRotationType::FULL;
|
|
||||||
else
|
|
||||||
synch = SyncRotationType::GENERAL;
|
|
||||||
synchronize_unselected_instances(synch);
|
|
||||||
}
|
}
|
||||||
else if (m_mode == Volume)
|
else if (m_mode == Volume)
|
||||||
synchronize_unselected_volumes();
|
synchronize_unselected_volumes();
|
||||||
@ -1466,17 +1434,12 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation
|
|||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (unsigned int i : m_list) {
|
|
||||||
GLVolume& v = *(*m_volumes)[i];
|
|
||||||
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
|
||||||
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
|
||||||
|
|
||||||
Vec3d relative_scale = scale;
|
Vec3d relative_scale = scale;
|
||||||
|
|
||||||
if (transformation_type.absolute()) {
|
if (transformation_type.absolute()) {
|
||||||
|
// converts to relative scale
|
||||||
if (m_mode == Instance) {
|
if (m_mode == Instance) {
|
||||||
if (is_single_full_instance()) {
|
if (is_single_full_instance()) {
|
||||||
BoundingBoxf3 current_box = m_box.get_bounding_box();
|
BoundingBoxf3 current_box = get_bounding_box_in_current_reference_system().first;
|
||||||
BoundingBoxf3 original_box;
|
BoundingBoxf3 original_box;
|
||||||
if (transformation_type.world())
|
if (transformation_type.world())
|
||||||
original_box = get_full_unscaled_instance_bounding_box();
|
original_box = get_full_unscaled_instance_bounding_box();
|
||||||
@ -1484,12 +1447,15 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation
|
|||||||
original_box = get_full_unscaled_instance_local_bounding_box();
|
original_box = get_full_unscaled_instance_local_bounding_box();
|
||||||
|
|
||||||
relative_scale = original_box.size().cwiseProduct(scale).cwiseQuotient(current_box.size());
|
relative_scale = original_box.size().cwiseProduct(scale).cwiseQuotient(current_box.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
transformation_type.set_relative();
|
transformation_type.set_relative();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
for (unsigned int i : m_list) {
|
||||||
}
|
GLVolume& v = *(*m_volumes)[i];
|
||||||
}
|
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
||||||
|
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
||||||
|
|
||||||
if (m_mode == Instance) {
|
if (m_mode == Instance) {
|
||||||
if (transformation_type.instance()) {
|
if (transformation_type.instance()) {
|
||||||
@ -1529,7 +1495,9 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation
|
|||||||
|
|
||||||
#if !DISABLE_INSTANCES_SYNCH
|
#if !DISABLE_INSTANCES_SYNCH
|
||||||
if (m_mode == Instance)
|
if (m_mode == Instance)
|
||||||
synchronize_unselected_instances(SyncRotationType::NONE);
|
// even if there is no rotation, we pass SyncRotationType::GENERAL to force
|
||||||
|
// synchronize_unselected_instances() to apply the scale to the other instances
|
||||||
|
synchronize_unselected_instances(SyncRotationType::GENERAL);
|
||||||
else if (m_mode == Volume)
|
else if (m_mode == Volume)
|
||||||
synchronize_unselected_volumes();
|
synchronize_unselected_volumes();
|
||||||
#endif // !DISABLE_INSTANCES_SYNCH
|
#endif // !DISABLE_INSTANCES_SYNCH
|
||||||
@ -2196,7 +2164,6 @@ void Selection::update_type()
|
|||||||
unsigned int volumes_count = (unsigned int)model_object->volumes.size();
|
unsigned int volumes_count = (unsigned int)model_object->volumes.size();
|
||||||
unsigned int instances_count = (unsigned int)model_object->instances.size();
|
unsigned int instances_count = (unsigned int)model_object->instances.size();
|
||||||
if (volumes_count * instances_count == 1) {
|
if (volumes_count * instances_count == 1) {
|
||||||
const ModelVolume* model_volume = model_object->volumes[first->volume_idx()];
|
|
||||||
m_type = SingleFullObject;
|
m_type = SingleFullObject;
|
||||||
// ensures the correct mode is selected
|
// ensures the correct mode is selected
|
||||||
m_mode = Instance;
|
m_mode = Instance;
|
||||||
@ -2834,7 +2801,7 @@ void Selection::render_debug_window() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int current_method_idx = 0;
|
static int current_method_idx = 0;
|
||||||
ImGui::Combo("Decomposition method", ¤t_method_idx, "computeRotationScaling\0computeScalingRotation\0");
|
ImGui::Combo("Decomposition method", ¤t_method_idx, "computeRotationScaling\0computeScalingRotation\0SVD\0");
|
||||||
|
|
||||||
const GLVolume& v = *get_volume(current_vol_idx);
|
const GLVolume& v = *get_volume(current_vol_idx);
|
||||||
|
|
||||||
@ -2854,12 +2821,13 @@ void Selection::render_debug_window() const
|
|||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto add_matrices_set = [add_matrix](const std::string& name, const Transform3d& m, size_t method) {
|
auto add_matrices_set = [&imgui, add_matrix](const std::string& name, const Transform3d& m, size_t method) {
|
||||||
static unsigned int counter = 0;
|
static unsigned int counter = 0;
|
||||||
++counter;
|
++counter;
|
||||||
if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
|
if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
add_matrix("Full", m, 4);
|
add_matrix("Full", m, 4);
|
||||||
|
|
||||||
|
if (method == 0 || method == 1) {
|
||||||
Matrix3d rotation;
|
Matrix3d rotation;
|
||||||
Matrix3d scale;
|
Matrix3d scale;
|
||||||
if (method == 0)
|
if (method == 0)
|
||||||
@ -2872,6 +2840,38 @@ void Selection::render_debug_window() const
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
add_matrix("Scale component", Transform3d(scale), 3);
|
add_matrix("Scale component", Transform3d(scale), 3);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
const Geometry::TransformationSVD svd(m);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
add_matrix("U", Transform3d(svd.u), 3);
|
||||||
|
ImGui::SameLine();
|
||||||
|
add_matrix("S", Transform3d(svd.s), 3);
|
||||||
|
ImGui::SameLine();
|
||||||
|
add_matrix("V", Transform3d(svd.v), 3);
|
||||||
|
ImGui::Dummy(ImVec2(0.0f, 0.0f));
|
||||||
|
float spacing = 0.0f;
|
||||||
|
if (svd.rotation) {
|
||||||
|
ImGui::SameLine(0.0f, spacing);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, svd.rotation_90_degrees ? "Rotation 90 degs" : "Rotation");
|
||||||
|
spacing = 10.0f;
|
||||||
|
}
|
||||||
|
if (svd.scale) {
|
||||||
|
ImGui::SameLine(0.0f, spacing);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, svd.anisotropic_scale ? "Anisotropic scale" : "Isotropic scale");
|
||||||
|
spacing = 10.0f;
|
||||||
|
}
|
||||||
|
if (svd.mirror) {
|
||||||
|
ImGui::SameLine(0.0f, spacing);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Mirror");
|
||||||
|
spacing = 10.0f;
|
||||||
|
}
|
||||||
|
if (svd.skew) {
|
||||||
|
ImGui::SameLine(0.0f, spacing);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Skew");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
add_matrices_set("World", v.world_matrix(), current_method_idx);
|
add_matrices_set("World", v.world_matrix(), current_method_idx);
|
||||||
@ -2994,7 +2994,6 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
|
|||||||
const int object_idx = volume_i->object_idx();
|
const int object_idx = volume_i->object_idx();
|
||||||
const int instance_idx = volume_i->instance_idx();
|
const int instance_idx = volume_i->instance_idx();
|
||||||
const Transform3d& curr_inst_trafo_i = volume_i->get_instance_transformation().get_matrix();
|
const Transform3d& curr_inst_trafo_i = volume_i->get_instance_transformation().get_matrix();
|
||||||
const bool curr_inst_left_handed = is_left_handed(curr_inst_trafo_i);
|
|
||||||
const Transform3d& old_inst_trafo_i = m_cache.volumes_data[i].get_instance_transform().get_matrix();
|
const Transform3d& old_inst_trafo_i = m_cache.volumes_data[i].get_instance_transform().get_matrix();
|
||||||
bool mirrored = is_left_handed(curr_inst_trafo_i) != is_left_handed(old_inst_trafo_i);
|
bool mirrored = is_left_handed(curr_inst_trafo_i) != is_left_handed(old_inst_trafo_i);
|
||||||
// bool mirrored = curr_inst_trafo_i.linear().determinant() * old_inst_trafo_i.linear().determinant() < 0;
|
// bool mirrored = curr_inst_trafo_i.linear().determinant() * old_inst_trafo_i.linear().determinant() < 0;
|
||||||
|
@ -499,10 +499,6 @@ public:
|
|||||||
NONE = 0,
|
NONE = 0,
|
||||||
// Synchronize after rotation by an axis not parallel with Z.
|
// Synchronize after rotation by an axis not parallel with Z.
|
||||||
GENERAL = 1,
|
GENERAL = 1,
|
||||||
#if ENABLE_WORLD_COORDINATE
|
|
||||||
// Fully synchronize rotation.
|
|
||||||
FULL = 2,
|
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
|
||||||
};
|
};
|
||||||
void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
|
void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
|
||||||
void synchronize_unselected_volumes();
|
void synchronize_unselected_volumes();
|
||||||
|
@ -1571,7 +1571,10 @@ void TabPrint::build()
|
|||||||
optgroup->append_single_option_line("first_layer_speed_over_raft");
|
optgroup->append_single_option_line("first_layer_speed_over_raft");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Acceleration control (advanced)"));
|
optgroup = page->new_optgroup(L("Acceleration control (advanced)"));
|
||||||
|
optgroup->append_single_option_line("external_perimeter_acceleration");
|
||||||
optgroup->append_single_option_line("perimeter_acceleration");
|
optgroup->append_single_option_line("perimeter_acceleration");
|
||||||
|
optgroup->append_single_option_line("top_solid_infill_acceleration");
|
||||||
|
optgroup->append_single_option_line("solid_infill_acceleration");
|
||||||
optgroup->append_single_option_line("infill_acceleration");
|
optgroup->append_single_option_line("infill_acceleration");
|
||||||
optgroup->append_single_option_line("bridge_acceleration");
|
optgroup->append_single_option_line("bridge_acceleration");
|
||||||
optgroup->append_single_option_line("first_layer_acceleration");
|
optgroup->append_single_option_line("first_layer_acceleration");
|
||||||
@ -1638,9 +1641,6 @@ void TabPrint::build()
|
|||||||
optgroup->append_single_option_line("xy_size_compensation");
|
optgroup->append_single_option_line("xy_size_compensation");
|
||||||
optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487");
|
optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Other"));
|
|
||||||
optgroup->append_single_option_line("clip_multipart_objects");
|
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Arachne perimeter generator"));
|
optgroup = page->new_optgroup(L("Arachne perimeter generator"));
|
||||||
optgroup->append_single_option_line("wall_transition_angle");
|
optgroup->append_single_option_line("wall_transition_angle");
|
||||||
optgroup->append_single_option_line("wall_transition_filter_deviation");
|
optgroup->append_single_option_line("wall_transition_filter_deviation");
|
||||||
@ -1729,9 +1729,7 @@ void TabPrint::update_description_lines()
|
|||||||
if (m_post_process_explanation) {
|
if (m_post_process_explanation) {
|
||||||
m_post_process_explanation->SetText(
|
m_post_process_explanation->SetText(
|
||||||
_L("Post processing scripts shall modify G-code file in place."));
|
_L("Post processing scripts shall modify G-code file in place."));
|
||||||
#ifndef __linux__
|
|
||||||
m_post_process_explanation->SetPathEnd("post-processing-scripts_283913");
|
m_post_process_explanation->SetPathEnd("post-processing-scripts_283913");
|
||||||
#endif // __linux__
|
|
||||||
}
|
}
|
||||||
// upadte G-code substitutions from the current configuration
|
// upadte G-code substitutions from the current configuration
|
||||||
{
|
{
|
||||||
|
@ -734,11 +734,14 @@ bool PrusaLink::get_storage(wxArrayString& output) const
|
|||||||
const auto path = section.second.get_optional<std::string>("path");
|
const auto path = section.second.get_optional<std::string>("path");
|
||||||
const auto space = section.second.get_optional<std::string>("free_space");
|
const auto space = section.second.get_optional<std::string>("free_space");
|
||||||
const auto read_only = section.second.get_optional<bool>("read_only");
|
const auto read_only = section.second.get_optional<bool>("read_only");
|
||||||
|
const auto ro = section.second.get_optional<bool>("ro"); // In PrusaLink 0.7.0RC2 "read_only" value is stored under "ro".
|
||||||
const auto available = section.second.get_optional<bool>("available");
|
const auto available = section.second.get_optional<bool>("available");
|
||||||
if (path && (!available || *available)) {
|
if (path && (!available || *available)) {
|
||||||
StorageInfo si;
|
StorageInfo si;
|
||||||
si.name = boost::nowide::widen(*path);
|
si.name = boost::nowide::widen(*path);
|
||||||
si.read_only = read_only ? *read_only : false; // If read_only is missing, assume it is NOT read only.
|
// If read_only is missing, assume it is NOT read only.
|
||||||
|
// si.read_only = read_only ? *read_only : false; // version without "ro"
|
||||||
|
si.read_only = (read_only ? *read_only : (ro ? *ro : false));
|
||||||
si.free_space = space ? std::stoll(*space) : 1; // If free_space is missing, assume there is free space.
|
si.free_space = space ? std::stoll(*space) : 1; // If free_space is missing, assume there is free space.
|
||||||
storage.emplace_back(std::move(si));
|
storage.emplace_back(std::move(si));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user