Merge branch 'master' into fs_realtime_simplify
This commit is contained in:
commit
7e2691241b
106
resources/shaders/gouraud_mod.fs
Normal file
106
resources/shaders/gouraud_mod.fs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#version 110
|
||||||
|
|
||||||
|
#define INTENSITY_CORRECTION 0.6
|
||||||
|
|
||||||
|
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
|
||||||
|
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||||
|
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SHININESS 20.0
|
||||||
|
|
||||||
|
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
|
||||||
|
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||||
|
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||||
|
|
||||||
|
#define INTENSITY_AMBIENT 0.3
|
||||||
|
|
||||||
|
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||||
|
const vec3 GREEN = vec3(0.0, 0.7, 0.0);
|
||||||
|
const vec3 YELLOW = vec3(0.5, 0.7, 0.0);
|
||||||
|
const vec3 RED = vec3(0.7, 0.0, 0.0);
|
||||||
|
const vec3 WHITE = vec3(1.0, 1.0, 1.0);
|
||||||
|
const float EPSILON = 0.0001;
|
||||||
|
const float BANDS_WIDTH = 10.0;
|
||||||
|
|
||||||
|
struct PrintVolumeDetection
|
||||||
|
{
|
||||||
|
// 0 = rectangle, 1 = circle, 2 = custom, 3 = invalid
|
||||||
|
int type;
|
||||||
|
// type = 0 (rectangle):
|
||||||
|
// x = min.x, y = min.y, z = max.x, w = max.y
|
||||||
|
// type = 1 (circle):
|
||||||
|
// x = center.x, y = center.y, z = radius
|
||||||
|
vec4 xy_data;
|
||||||
|
// x = min z, y = max z
|
||||||
|
vec2 z_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SlopeDetection
|
||||||
|
{
|
||||||
|
bool actived;
|
||||||
|
float normal_z;
|
||||||
|
mat3 volume_world_normal_matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform vec4 uniform_color;
|
||||||
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
|
uniform bool offset_depth_buffer;
|
||||||
|
|
||||||
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
|
uniform sampler2D environment_tex;
|
||||||
|
uniform bool use_environment_tex;
|
||||||
|
#endif // ENABLE_ENVIRONMENT_MAP
|
||||||
|
|
||||||
|
varying vec3 clipping_planes_dots;
|
||||||
|
|
||||||
|
// x = diffuse, y = specular;
|
||||||
|
varying vec2 intensity;
|
||||||
|
|
||||||
|
uniform PrintVolumeDetection print_volume;
|
||||||
|
|
||||||
|
varying vec4 model_pos;
|
||||||
|
varying vec4 world_pos;
|
||||||
|
varying float world_normal_z;
|
||||||
|
varying vec3 eye_normal;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||||
|
discard;
|
||||||
|
vec3 color = uniform_color.rgb;
|
||||||
|
float alpha = uniform_color.a;
|
||||||
|
|
||||||
|
if (slope.actived && world_normal_z < slope.normal_z - EPSILON) {
|
||||||
|
color = vec3(0.7, 0.7, 1.0);
|
||||||
|
alpha = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the fragment is outside the print volume -> use darker color
|
||||||
|
vec3 pv_check_min = ZERO;
|
||||||
|
vec3 pv_check_max = ZERO;
|
||||||
|
if (print_volume.type == 0) {
|
||||||
|
// rectangle
|
||||||
|
pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x);
|
||||||
|
pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y);
|
||||||
|
}
|
||||||
|
else if (print_volume.type == 1) {
|
||||||
|
// circle
|
||||||
|
float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color;
|
||||||
|
|
||||||
|
#ifdef ENABLE_ENVIRONMENT_MAP
|
||||||
|
if (use_environment_tex)
|
||||||
|
gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha);
|
||||||
|
|
||||||
|
// In the support painting gizmo and the seam painting gizmo are painted triangles rendered over the already
|
||||||
|
// rendered object. To resolved z-fighting between previously rendered object and painted triangles, values
|
||||||
|
// inside the depth buffer are offset by small epsilon for painted triangles inside those gizmos.
|
||||||
|
gl_FragDepth = gl_FragCoord.z - (offset_depth_buffer ? EPSILON : 0.0);
|
||||||
|
}
|
73
resources/shaders/gouraud_mod.vs
Normal file
73
resources/shaders/gouraud_mod.vs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#version 110
|
||||||
|
|
||||||
|
#define INTENSITY_CORRECTION 0.6
|
||||||
|
|
||||||
|
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
|
||||||
|
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||||
|
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SHININESS 20.0
|
||||||
|
|
||||||
|
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
|
||||||
|
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||||
|
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||||
|
//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION)
|
||||||
|
//#define LIGHT_FRONT_SHININESS 5.0
|
||||||
|
|
||||||
|
#define INTENSITY_AMBIENT 0.3
|
||||||
|
|
||||||
|
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
struct SlopeDetection
|
||||||
|
{
|
||||||
|
bool actived;
|
||||||
|
float normal_z;
|
||||||
|
mat3 volume_world_normal_matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform mat4 volume_world_matrix;
|
||||||
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
|
// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane.
|
||||||
|
uniform vec2 z_range;
|
||||||
|
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||||
|
uniform vec4 clipping_plane;
|
||||||
|
|
||||||
|
// x = diffuse, y = specular;
|
||||||
|
varying vec2 intensity;
|
||||||
|
|
||||||
|
varying vec3 clipping_planes_dots;
|
||||||
|
|
||||||
|
varying vec4 model_pos;
|
||||||
|
varying vec4 world_pos;
|
||||||
|
varying float world_normal_z;
|
||||||
|
varying vec3 eye_normal;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// First transform the normal into camera space and normalize the result.
|
||||||
|
eye_normal = normalize(gl_NormalMatrix * gl_Normal);
|
||||||
|
|
||||||
|
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
|
||||||
|
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
|
||||||
|
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
|
||||||
|
|
||||||
|
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
|
||||||
|
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
|
||||||
|
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
|
||||||
|
|
||||||
|
// Perform the same lighting calculation for the 2nd light source (no specular applied).
|
||||||
|
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
|
||||||
|
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||||
|
|
||||||
|
model_pos = gl_Vertex;
|
||||||
|
// Point in homogenous coordinates.
|
||||||
|
world_pos = volume_world_matrix * gl_Vertex;
|
||||||
|
|
||||||
|
// z component of normal vector in world coordinate used for slope shading
|
||||||
|
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0;
|
||||||
|
|
||||||
|
gl_Position = ftransform();
|
||||||
|
// 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);
|
||||||
|
}
|
@ -720,6 +720,9 @@ void GCodeProcessor::UsedFilaments::process_caches(GCodeProcessor* processor)
|
|||||||
void GCodeProcessor::Result::reset() {
|
void GCodeProcessor::Result::reset() {
|
||||||
moves = std::vector<GCodeProcessor::MoveVertex>();
|
moves = std::vector<GCodeProcessor::MoveVertex>();
|
||||||
bed_shape = Pointfs();
|
bed_shape = Pointfs();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
max_print_height = 0.0f;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
settings_ids.reset();
|
settings_ids.reset();
|
||||||
extruders_count = 0;
|
extruders_count = 0;
|
||||||
extruder_colors = std::vector<std::string>();
|
extruder_colors = std::vector<std::string>();
|
||||||
@ -734,6 +737,9 @@ void GCodeProcessor::Result::reset() {
|
|||||||
moves.clear();
|
moves.clear();
|
||||||
lines_ends.clear();
|
lines_ends.clear();
|
||||||
bed_shape = Pointfs();
|
bed_shape = Pointfs();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
max_print_height = 0.0f;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
settings_ids.reset();
|
settings_ids.reset();
|
||||||
extruders_count = 0;
|
extruders_count = 0;
|
||||||
extruder_colors = std::vector<std::string>();
|
extruder_colors = std::vector<std::string>();
|
||||||
@ -883,6 +889,10 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
|||||||
const ConfigOptionFloatOrPercent* first_layer_height = config.option<ConfigOptionFloatOrPercent>("first_layer_height");
|
const ConfigOptionFloatOrPercent* first_layer_height = config.option<ConfigOptionFloatOrPercent>("first_layer_height");
|
||||||
if (first_layer_height != nullptr)
|
if (first_layer_height != nullptr)
|
||||||
m_first_layer_height = std::abs(first_layer_height->value);
|
m_first_layer_height = std::abs(first_layer_height->value);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
m_result.max_print_height = config.max_print_height;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||||
@ -1112,6 +1122,12 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
|||||||
const ConfigOptionFloatOrPercent* first_layer_height = config.option<ConfigOptionFloatOrPercent>("first_layer_height");
|
const ConfigOptionFloatOrPercent* first_layer_height = config.option<ConfigOptionFloatOrPercent>("first_layer_height");
|
||||||
if (first_layer_height != nullptr)
|
if (first_layer_height != nullptr)
|
||||||
m_first_layer_height = std::abs(first_layer_height->value);
|
m_first_layer_height = std::abs(first_layer_height->value);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
const ConfigOptionFloat* max_print_height = config.option<ConfigOptionFloat>("max_print_height");
|
||||||
|
if (max_print_height != nullptr)
|
||||||
|
m_result.max_print_height = max_print_height->value;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeProcessor::enable_stealth_time_estimator(bool enabled)
|
void GCodeProcessor::enable_stealth_time_estimator(bool enabled)
|
||||||
|
@ -351,6 +351,9 @@ namespace Slic3r {
|
|||||||
// Positions of ends of lines of the final G-code this->filename after TimeProcessor::post_process() finalizes the G-code.
|
// Positions of ends of lines of the final G-code this->filename after TimeProcessor::post_process() finalizes the G-code.
|
||||||
std::vector<size_t> lines_ends;
|
std::vector<size_t> lines_ends;
|
||||||
Pointfs bed_shape;
|
Pointfs bed_shape;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
float max_print_height;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
SettingsIds settings_ids;
|
SettingsIds settings_ids;
|
||||||
size_t extruders_count;
|
size_t extruders_count;
|
||||||
std::vector<std::string> extruder_colors;
|
std::vector<std::string> extruder_colors;
|
||||||
|
@ -311,6 +311,15 @@ bool directions_parallel(double angle1, double angle2, double max_diff)
|
|||||||
return diff < max_diff || fabs(diff - PI) < max_diff;
|
return diff < max_diff || fabs(diff - PI) < max_diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool directions_perpendicular(double angle1, double angle2, double max_diff)
|
||||||
|
{
|
||||||
|
double diff = fabs(angle1 - angle2);
|
||||||
|
max_diff += EPSILON;
|
||||||
|
return fabs(diff - 0.5 * PI) < max_diff || fabs(diff - 1.5 * PI) < max_diff;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
bool contains(const std::vector<T> &vector, const Point &point)
|
bool contains(const std::vector<T> &vector, const Point &point)
|
||||||
{
|
{
|
||||||
|
@ -84,6 +84,32 @@ static inline bool is_ccw(const Polygon &poly)
|
|||||||
return o == ORIENTATION_CCW;
|
return o == ORIENTATION_CCW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// returns true if the given polygons are identical
|
||||||
|
static inline bool are_approx(const Polygon& lhs, const Polygon& rhs)
|
||||||
|
{
|
||||||
|
if (lhs.points.size() != rhs.points.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t rhs_id = 0;
|
||||||
|
while (rhs_id < rhs.points.size()) {
|
||||||
|
if (rhs.points[rhs_id].isApprox(lhs.points.front()))
|
||||||
|
break;
|
||||||
|
++rhs_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rhs_id == rhs.points.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lhs.points.size(); ++i) {
|
||||||
|
if (!lhs.points[i].isApprox(rhs.points[(i + rhs_id) % lhs.points.size()]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
inline bool ray_ray_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res)
|
inline bool ray_ray_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res)
|
||||||
{
|
{
|
||||||
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
||||||
@ -336,6 +362,9 @@ Polygon convex_hull(Points points);
|
|||||||
Polygon convex_hull(const Polygons &polygons);
|
Polygon convex_hull(const Polygons &polygons);
|
||||||
|
|
||||||
bool directions_parallel(double angle1, double angle2, double max_diff = 0);
|
bool directions_parallel(double angle1, double angle2, double max_diff = 0);
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool directions_perpendicular(double angle1, double angle2, double max_diff = 0);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
template<class T> bool contains(const std::vector<T> &vector, const Point &point);
|
template<class T> bool contains(const std::vector<T> &vector, const Point &point);
|
||||||
template<typename T> T rad2deg(T angle) { return T(180.0) * angle / T(PI); }
|
template<typename T> T rad2deg(T angle) { return T(180.0) * angle / T(PI); }
|
||||||
double rad2deg_dir(double angle);
|
double rad2deg_dir(double angle);
|
||||||
|
@ -63,6 +63,13 @@ bool Line::parallel_to(double angle) const
|
|||||||
return Slic3r::Geometry::directions_parallel(this->direction(), angle);
|
return Slic3r::Geometry::directions_parallel(this->direction(), angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool Line::perpendicular_to(double angle) const
|
||||||
|
{
|
||||||
|
return Slic3r::Geometry::directions_perpendicular(this->direction(), angle);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
bool Line::intersection(const Line &l2, Point *intersection) const
|
bool Line::intersection(const Line &l2, Point *intersection) const
|
||||||
{
|
{
|
||||||
const Line &l1 = *this;
|
const Line &l1 = *this;
|
||||||
|
@ -105,6 +105,10 @@ public:
|
|||||||
double perp_distance_to(const Point &point) const;
|
double perp_distance_to(const Point &point) const;
|
||||||
bool parallel_to(double angle) const;
|
bool parallel_to(double angle) const;
|
||||||
bool parallel_to(const Line &line) const { return this->parallel_to(line.direction()); }
|
bool parallel_to(const Line &line) const { return this->parallel_to(line.direction()); }
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool perpendicular_to(double angle) const;
|
||||||
|
bool perpendicular_to(const Line& line) const { return this->perpendicular_to(line.direction()); }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
double atan2_() const { return atan2(this->b(1) - this->a(1), this->b(0) - this->a(0)); }
|
double atan2_() const { return atan2(this->b(1) - this->a(1), this->b(0) - this->a(0)); }
|
||||||
double orientation() const;
|
double orientation() const;
|
||||||
double direction() const;
|
double direction() const;
|
||||||
|
@ -26,6 +26,35 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z)
|
||||||
|
{
|
||||||
|
if (!Geometry::intersects(printbed_shape, obj_hull_2d))
|
||||||
|
return ModelInstancePVS_Fully_Outside;
|
||||||
|
|
||||||
|
bool contained_xy = true;
|
||||||
|
for (const Point& p : obj_hull_2d) {
|
||||||
|
if (!printbed_shape.contains(p)) {
|
||||||
|
contained_xy = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bool contained_z = -1e10 < obj_min_z && obj_max_z < print_volume_height;
|
||||||
|
return (contained_xy && contained_z) ? ModelInstancePVS_Inside : ModelInstancePVS_Partly_Outside;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box)
|
||||||
|
{
|
||||||
|
const Polygon box_hull_2d({
|
||||||
|
{ scale_(box.min.x()), scale_(box.min.y()) },
|
||||||
|
{ scale_(box.max.x()), scale_(box.min.y()) },
|
||||||
|
{ scale_(box.max.x()), scale_(box.max.y()) },
|
||||||
|
{ scale_(box.min.x()), scale_(box.max.y()) }
|
||||||
|
});
|
||||||
|
return printbed_collision_state(printbed_shape, print_volume_height, box_hull_2d, box.min.z(), box.max.z());
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
Model& Model::assign_copy(const Model &rhs)
|
Model& Model::assign_copy(const Model &rhs)
|
||||||
{
|
{
|
||||||
this->copy_id(rhs);
|
this->copy_id(rhs);
|
||||||
@ -330,6 +359,15 @@ BoundingBoxf3 Model::bounding_box() const
|
|||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
unsigned int Model::update_print_volume_state(const Polygon& printbed_shape, double print_volume_height)
|
||||||
|
{
|
||||||
|
unsigned int num_printable = 0;
|
||||||
|
for (ModelObject* model_object : this->objects)
|
||||||
|
num_printable += model_object->check_instances_print_volume_state(printbed_shape, print_volume_height);
|
||||||
|
return num_printable;
|
||||||
|
}
|
||||||
|
#else
|
||||||
unsigned int Model::update_print_volume_state(const BoundingBoxf3 &print_volume)
|
unsigned int Model::update_print_volume_state(const BoundingBoxf3 &print_volume)
|
||||||
{
|
{
|
||||||
unsigned int num_printable = 0;
|
unsigned int num_printable = 0;
|
||||||
@ -337,6 +375,7 @@ unsigned int Model::update_print_volume_state(const BoundingBoxf3 &print_volume)
|
|||||||
num_printable += model_object->check_instances_print_volume_state(print_volume);
|
num_printable += model_object->check_instances_print_volume_state(print_volume);
|
||||||
return num_printable;
|
return num_printable;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
bool Model::center_instances_around_point(const Vec2d &point)
|
bool Model::center_instances_around_point(const Vec2d &point)
|
||||||
{
|
{
|
||||||
@ -1529,6 +1568,38 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const
|
|||||||
return max_z + inst->get_offset(Z);
|
return max_z + inst->get_offset(Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
unsigned int ModelObject::check_instances_print_volume_state(const Polygon& printbed_shape, double print_volume_height)
|
||||||
|
{
|
||||||
|
unsigned int num_printable = 0;
|
||||||
|
enum {
|
||||||
|
INSIDE = 1,
|
||||||
|
OUTSIDE = 2
|
||||||
|
};
|
||||||
|
for (ModelInstance* model_instance : this->instances) {
|
||||||
|
unsigned int inside_outside = 0;
|
||||||
|
for (const ModelVolume* vol : this->volumes)
|
||||||
|
if (vol->is_model_part()) {
|
||||||
|
const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix();
|
||||||
|
const BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(matrix, 0.0);
|
||||||
|
const Polygon volume_hull_2d = its_convex_hull_2d_above(vol->mesh().its, matrix.cast<float>(), 0.0f);
|
||||||
|
ModelInstanceEPrintVolumeState state = printbed_collision_state(printbed_shape, print_volume_height, volume_hull_2d, bb.min.z(), bb.max.z());
|
||||||
|
if (state == ModelInstancePVS_Inside)
|
||||||
|
inside_outside |= INSIDE;
|
||||||
|
else if (state == ModelInstancePVS_Fully_Outside)
|
||||||
|
inside_outside |= OUTSIDE;
|
||||||
|
else
|
||||||
|
inside_outside |= INSIDE | OUTSIDE;
|
||||||
|
}
|
||||||
|
model_instance->print_volume_state =
|
||||||
|
(inside_outside == (INSIDE | OUTSIDE)) ? ModelInstancePVS_Partly_Outside :
|
||||||
|
(inside_outside == INSIDE) ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside;
|
||||||
|
if (inside_outside == INSIDE)
|
||||||
|
++num_printable;
|
||||||
|
}
|
||||||
|
return num_printable;
|
||||||
|
}
|
||||||
|
#else
|
||||||
unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
||||||
{
|
{
|
||||||
unsigned int num_printable = 0;
|
unsigned int num_printable = 0;
|
||||||
@ -1556,6 +1627,7 @@ unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3
|
|||||||
}
|
}
|
||||||
return num_printable;
|
return num_printable;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
void ModelObject::print_info() const
|
void ModelObject::print_info() const
|
||||||
{
|
{
|
||||||
|
@ -367,7 +367,11 @@ public:
|
|||||||
double get_instance_max_z(size_t instance_idx) const;
|
double get_instance_max_z(size_t instance_idx) const;
|
||||||
|
|
||||||
// Called by Print::validate() from the UI thread.
|
// Called by Print::validate() from the UI thread.
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
unsigned int check_instances_print_volume_state(const Polygon& printbed_shape, double print_volume_height);
|
||||||
|
#else
|
||||||
unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
// Print object statistics to console.
|
// Print object statistics to console.
|
||||||
void print_info() const;
|
void print_info() const;
|
||||||
@ -904,6 +908,14 @@ enum ModelInstanceEPrintVolumeState : unsigned char
|
|||||||
ModelInstanceNum_BedStates
|
ModelInstanceNum_BedStates
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// return the state of the given object's volume (extrusion along z of obj_hull_2d from obj_min_z to obj_max_z)
|
||||||
|
// with respect to the given print volume (extrusion along z of printbed_shape from zero to print_volume_height)
|
||||||
|
ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z);
|
||||||
|
// return the state of the given box
|
||||||
|
// with respect to the given print volume (extrusion along z of printbed_shape from zero to print_volume_height)
|
||||||
|
ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
// A single instance of a ModelObject.
|
// A single instance of a ModelObject.
|
||||||
// Knows the affine transformation of an object.
|
// Knows the affine transformation of an object.
|
||||||
@ -1109,7 +1121,11 @@ public:
|
|||||||
BoundingBoxf3 bounding_box() const;
|
BoundingBoxf3 bounding_box() const;
|
||||||
// Set the print_volume_state of PrintObject::instances,
|
// Set the print_volume_state of PrintObject::instances,
|
||||||
// return total number of printable objects.
|
// return total number of printable objects.
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
unsigned int update_print_volume_state(const Polygon& printbed_shape, double print_volume_height);
|
||||||
|
#else
|
||||||
unsigned int update_print_volume_state(const BoundingBoxf3 &print_volume);
|
unsigned int update_print_volume_state(const BoundingBoxf3 &print_volume);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
// Returns true if any ModelObject was modified.
|
// Returns true if any ModelObject was modified.
|
||||||
bool center_instances_around_point(const Vec2d &point);
|
bool center_instances_around_point(const Vec2d &point);
|
||||||
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
||||||
|
@ -1703,15 +1703,18 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport
|
|||||||
// Don't want to print a layer below the first layer height as it may not stick well.
|
// Don't want to print a layer below the first layer height as it may not stick well.
|
||||||
//FIXME there may be a need for a single layer support, then one may decide to print it either as a bottom contact or a top contact
|
//FIXME there may be a need for a single layer support, then one may decide to print it either as a bottom contact or a top contact
|
||||||
// and it may actually make sense to do it with a thinner layer than the first layer height.
|
// and it may actually make sense to do it with a thinner layer than the first layer height.
|
||||||
const coordf_t min_print_z = slicing_params.raft_layers() > 1 ? slicing_params.raft_interface_top_z + support_layer_height_min + EPSILON : slicing_params.first_print_layer_height - EPSILON;
|
if (print_z < slicing_params.first_print_layer_height - EPSILON) {
|
||||||
if (print_z < min_print_z) {
|
|
||||||
// This contact layer is below the first layer height, therefore not printable. Don't support this surface.
|
// This contact layer is below the first layer height, therefore not printable. Don't support this surface.
|
||||||
return std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupportMaterial::MyLayer*>(nullptr, nullptr);
|
return std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupportMaterial::MyLayer*>(nullptr, nullptr);
|
||||||
} else if (print_z < slicing_params.first_print_layer_height + EPSILON) {
|
}
|
||||||
// Align the layer with the 1st layer height.
|
const bool has_raft = slicing_params.raft_layers() > 1;
|
||||||
print_z = slicing_params.first_print_layer_height;
|
const coordf_t min_print_z = has_raft ? slicing_params.raft_contact_top_z : slicing_params.first_print_layer_height;
|
||||||
bottom_z = 0;
|
if (print_z < min_print_z + support_layer_height_min) {
|
||||||
height = slicing_params.first_print_layer_height;
|
// Align the layer with the 1st layer height or the raft contact layer.
|
||||||
|
// With raft active, any contact layer below the raft_contact_top_z will be brought to raft_contact_top_z to extend the raft area.
|
||||||
|
print_z = min_print_z;
|
||||||
|
bottom_z = has_raft ? slicing_params.raft_interface_top_z : 0;
|
||||||
|
height = has_raft ? slicing_params.contact_raft_layer_height : min_print_z;
|
||||||
} else {
|
} else {
|
||||||
// Don't know the height of the top contact layer yet. The top contact layer is printed with a normal flow and
|
// Don't know the height of the top contact layer yet. The top contact layer is printed with a normal flow and
|
||||||
// its height will be set adaptively later on.
|
// its height will be set adaptively later on.
|
||||||
@ -1727,9 +1730,9 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport
|
|||||||
coordf_t bridging_print_z = layer.print_z - bridging_height - slicing_params.gap_support_object;
|
coordf_t bridging_print_z = layer.print_z - bridging_height - slicing_params.gap_support_object;
|
||||||
if (bridging_print_z >= min_print_z) {
|
if (bridging_print_z >= min_print_z) {
|
||||||
// Not below the first layer height means this layer is printable.
|
// Not below the first layer height means this layer is printable.
|
||||||
if (print_z < slicing_params.first_print_layer_height + EPSILON) {
|
if (print_z < min_print_z + support_layer_height_min) {
|
||||||
// Align the layer with the 1st layer height.
|
// Align the layer with the 1st layer height or the raft contact layer.
|
||||||
bridging_print_z = slicing_params.first_print_layer_height;
|
bridging_print_z = min_print_z;
|
||||||
}
|
}
|
||||||
if (bridging_print_z < print_z - EPSILON) {
|
if (bridging_print_z < print_z - EPSILON) {
|
||||||
// Allocate the new layer.
|
// Allocate the new layer.
|
||||||
@ -3108,7 +3111,7 @@ std::pair<PrintObjectSupportMaterial::MyLayersPtr, PrintObjectSupportMaterial::M
|
|||||||
intermediate_layer.polygons);
|
intermediate_layer.polygons);
|
||||||
if (! bottom.empty()) {
|
if (! bottom.empty()) {
|
||||||
//FIXME Remove non-printable tiny islands, let them be printed using the base support.
|
//FIXME Remove non-printable tiny islands, let them be printed using the base support.
|
||||||
//bottom = offset(offset_ex(std::move(bottom), - minimum_island_radius), minimum_island_radius);
|
//bottom = opening(std::move(bottom), minimum_island_radius);
|
||||||
if (! bottom.empty()) {
|
if (! bottom.empty()) {
|
||||||
MyLayer &layer_new = layer_allocate(layer_storage, layer_storage_mutex, type);
|
MyLayer &layer_new = layer_allocate(layer_storage, layer_storage_mutex, type);
|
||||||
layer_new.polygons = std::move(bottom);
|
layer_new.polygons = std::move(bottom);
|
||||||
|
@ -81,5 +81,9 @@
|
|||||||
// Enable rendering modifiers and similar objects always as transparent
|
// Enable rendering modifiers and similar objects always as transparent
|
||||||
#define ENABLE_MODIFIERS_ALWAYS_TRANSPARENT (1 && ENABLE_2_4_0_ALPHA4)
|
#define ENABLE_MODIFIERS_ALWAYS_TRANSPARENT (1 && ENABLE_2_4_0_ALPHA4)
|
||||||
|
|
||||||
|
// Enable the fix for the detection of the out of bed state for sinking objects
|
||||||
|
// and detection of out of bed using the bed perimeter
|
||||||
|
#define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_2_4_0_ALPHA4)
|
||||||
|
|
||||||
|
|
||||||
#endif // _prusaslicer_technologies_h_
|
#endif // _prusaslicer_technologies_h_
|
||||||
|
@ -435,6 +435,31 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c
|
|||||||
return bbox;
|
return bbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafo, double world_min_z) const
|
||||||
|
{
|
||||||
|
BoundingBoxf3 bbox;
|
||||||
|
const Transform3f ftrafo = trafo.cast<float>();
|
||||||
|
for (const stl_triangle_vertex_indices& tri : its.indices) {
|
||||||
|
const Vec3f pts[3] = { ftrafo * its.vertices[tri(0)], ftrafo * its.vertices[tri(1)], ftrafo * its.vertices[tri(2)] };
|
||||||
|
int iprev = 2;
|
||||||
|
for (int iedge = 0; iedge < 3; ++iedge) {
|
||||||
|
const Vec3f& p1 = pts[iprev];
|
||||||
|
const Vec3f& p2 = pts[iedge];
|
||||||
|
if ((p1.z() < world_min_z && p2.z() > world_min_z) || (p2.z() < world_min_z && p1.z() > world_min_z)) {
|
||||||
|
// Edge crosses the z plane. Calculate intersection point with the plane.
|
||||||
|
const float t = (world_min_z - p1.z()) / (p2.z() - p1.z());
|
||||||
|
bbox.merge(Vec3f(p1.x() + (p2.x() - p1.x()) * t, p1.y() + (p2.y() - p1.y()) * t, world_min_z).cast<double>());
|
||||||
|
}
|
||||||
|
if (p2.z() >= world_min_z)
|
||||||
|
bbox.merge(p2.cast<double>());
|
||||||
|
iprev = iedge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
TriangleMesh TriangleMesh::convex_hull_3d() const
|
TriangleMesh TriangleMesh::convex_hull_3d() const
|
||||||
{
|
{
|
||||||
// The qhull call:
|
// The qhull call:
|
||||||
|
@ -125,6 +125,10 @@ public:
|
|||||||
BoundingBoxf3 bounding_box() const;
|
BoundingBoxf3 bounding_box() const;
|
||||||
// Returns the bbox of this TriangleMesh transformed by the given transformation
|
// Returns the bbox of this TriangleMesh transformed by the given transformation
|
||||||
BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const;
|
BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// Variant returning the bbox of the part of this TriangleMesh above the given world_min_z
|
||||||
|
BoundingBoxf3 transformed_bounding_box(const Transform3d& trafo, double world_min_z) const;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
// Return the size of the mesh in coordinates.
|
// Return the size of the mesh in coordinates.
|
||||||
Vec3d size() const { return m_stats.size.cast<double>(); }
|
Vec3d size() const { return m_stats.size.cast<double>(); }
|
||||||
/// Return the center of the related bounding box.
|
/// Return the center of the related bounding box.
|
||||||
|
@ -7,11 +7,10 @@
|
|||||||
#include "libslic3r/BoundingBox.hpp"
|
#include "libslic3r/BoundingBox.hpp"
|
||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
#include "libslic3r/Tesselate.hpp"
|
#include "libslic3r/Tesselate.hpp"
|
||||||
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
|
||||||
#include "GLCanvas3D.hpp"
|
#include "GLCanvas3D.hpp"
|
||||||
#include "3DScene.hpp"
|
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
@ -154,7 +153,11 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
|||||||
std::string model;
|
std::string model;
|
||||||
std::string texture;
|
std::string texture;
|
||||||
if (force_as_custom)
|
if (force_as_custom)
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
type = EType::Custom;
|
||||||
|
#else
|
||||||
type = Custom;
|
type = Custom;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
else {
|
else {
|
||||||
auto [new_type, system_model, system_texture] = detect_type(shape);
|
auto [new_type, system_model, system_texture] = detect_type(shape);
|
||||||
type = new_type;
|
type = new_type;
|
||||||
@ -174,7 +177,12 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
|||||||
model_filename.clear();
|
model_filename.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
EShapeType shape_type = detect_shape_type(shape);
|
||||||
|
if (m_shape == shape && m_type == type && m_shape_type == shape_type && m_texture_filename == texture_filename && m_model_filename == model_filename)
|
||||||
|
#else
|
||||||
if (m_shape == shape && m_type == type && m_texture_filename == texture_filename && m_model_filename == model_filename)
|
if (m_shape == shape && m_type == type && m_texture_filename == texture_filename && m_model_filename == model_filename)
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
// No change, no need to update the UI.
|
// No change, no need to update the UI.
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -182,6 +190,9 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
|||||||
m_texture_filename = texture_filename;
|
m_texture_filename = texture_filename;
|
||||||
m_model_filename = model_filename;
|
m_model_filename = model_filename;
|
||||||
m_type = type;
|
m_type = type;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
m_shape_type = shape_type;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
calc_bounding_boxes();
|
calc_bounding_boxes();
|
||||||
|
|
||||||
@ -229,6 +240,84 @@ void Bed3D::render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_fact
|
|||||||
render_internal(canvas, bottom, scale_factor, false, false, true);
|
render_internal(canvas, bottom, scale_factor, false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool Bed3D::is_rectangle(const Pointfs& shape, Vec2d* min, Vec2d* max)
|
||||||
|
{
|
||||||
|
const Lines lines = Polygon::new_scale(shape).lines();
|
||||||
|
bool ret = lines.size() == 4 && lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3]) && lines[0].perpendicular_to(lines[1]);
|
||||||
|
if (ret) {
|
||||||
|
if (min != nullptr) {
|
||||||
|
*min = shape.front();
|
||||||
|
for (const Vec2d& pt : shape) {
|
||||||
|
min->x() = std::min(min->x(), pt.x());
|
||||||
|
min->y() = std::min(min->y(), pt.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (max != nullptr) {
|
||||||
|
*max = shape.front();
|
||||||
|
for (const Vec2d& pt : shape) {
|
||||||
|
max->x() = std::max(max->x(), pt.x());
|
||||||
|
max->y() = std::max(max->y(), pt.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bed3D::is_circle(const Pointfs& shape, Vec2d* center, double* radius)
|
||||||
|
{
|
||||||
|
if (shape.size() < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Analyze the array of points.
|
||||||
|
// Do they reside on a circle ?
|
||||||
|
const Vec2d box_center = BoundingBoxf(shape).center();
|
||||||
|
std::vector<double> vertex_distances;
|
||||||
|
double avg_dist = 0.0;
|
||||||
|
for (const Vec2d& pt : shape) {
|
||||||
|
double distance = (pt - box_center).norm();
|
||||||
|
vertex_distances.push_back(distance);
|
||||||
|
avg_dist += distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
avg_dist /= vertex_distances.size();
|
||||||
|
|
||||||
|
double tolerance = avg_dist * 0.01;
|
||||||
|
|
||||||
|
bool defined_value = true;
|
||||||
|
for (double el : vertex_distances) {
|
||||||
|
if (fabs(el - avg_dist) > tolerance)
|
||||||
|
defined_value = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (center != nullptr)
|
||||||
|
*center = box_center;
|
||||||
|
|
||||||
|
if (radius != nullptr)
|
||||||
|
*radius = avg_dist;
|
||||||
|
|
||||||
|
return defined_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bed3D::is_convex(const Pointfs& shape)
|
||||||
|
{
|
||||||
|
return Polygon::new_scale(shape).convex_points().size() == shape.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bed3D::EShapeType Bed3D::detect_shape_type(const Pointfs& shape)
|
||||||
|
{
|
||||||
|
if (shape.size() < 3)
|
||||||
|
return EShapeType::Invalid;
|
||||||
|
else if (is_rectangle(shape))
|
||||||
|
return EShapeType::Rectangle;
|
||||||
|
else if (is_circle(shape))
|
||||||
|
return EShapeType::Circle;
|
||||||
|
else
|
||||||
|
return EShapeType::Custom;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
||||||
bool show_axes, bool show_texture, bool picking)
|
bool show_axes, bool show_texture, bool picking)
|
||||||
{
|
{
|
||||||
@ -244,9 +333,15 @@ void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
|||||||
|
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
case EType::System: { render_system(canvas, bottom, show_texture); break; }
|
||||||
|
default:
|
||||||
|
case EType::Custom: { render_custom(canvas, bottom, show_texture, picking); break; }
|
||||||
|
#else
|
||||||
case System: { render_system(canvas, bottom, show_texture); break; }
|
case System: { render_system(canvas, bottom, show_texture); break; }
|
||||||
default:
|
default:
|
||||||
case Custom: { render_custom(canvas, bottom, show_texture, picking); break; }
|
case Custom: { render_custom(canvas, bottom, show_texture, picking); break; }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
@ -320,7 +415,11 @@ std::tuple<Bed3D::EType, std::string, std::string> Bed3D::detect_type(const Poin
|
|||||||
std::string model_filename = PresetUtils::system_printer_bed_model(*curr);
|
std::string model_filename = PresetUtils::system_printer_bed_model(*curr);
|
||||||
std::string texture_filename = PresetUtils::system_printer_bed_texture(*curr);
|
std::string texture_filename = PresetUtils::system_printer_bed_texture(*curr);
|
||||||
if (!model_filename.empty() && !texture_filename.empty())
|
if (!model_filename.empty() && !texture_filename.empty())
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
return { EType::System, model_filename, texture_filename };
|
||||||
|
#else
|
||||||
return { System, model_filename, texture_filename };
|
return { System, model_filename, texture_filename };
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +427,11 @@ std::tuple<Bed3D::EType, std::string, std::string> Bed3D::detect_type(const Poin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
return { EType::Custom, "", "" };
|
||||||
|
#else
|
||||||
return { Custom, "", "" };
|
return { Custom, "", "" };
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::render_axes() const
|
void Bed3D::render_axes() const
|
||||||
|
@ -62,15 +62,36 @@ class Bed3D
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
enum class EType : unsigned char
|
||||||
|
{
|
||||||
|
System,
|
||||||
|
Custom
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class EShapeType : unsigned char
|
||||||
|
{
|
||||||
|
Rectangle,
|
||||||
|
Circle,
|
||||||
|
Custom,
|
||||||
|
Invalid
|
||||||
|
};
|
||||||
|
#else
|
||||||
enum EType : unsigned char
|
enum EType : unsigned char
|
||||||
{
|
{
|
||||||
System,
|
System,
|
||||||
Custom,
|
Custom,
|
||||||
Num_Types
|
Num_Types
|
||||||
};
|
};
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
EType m_type{ EType::Custom };
|
||||||
|
EShapeType m_shape_type{ EShapeType::Invalid };
|
||||||
|
#else
|
||||||
EType m_type{ Custom };
|
EType m_type{ Custom };
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
Pointfs m_shape;
|
Pointfs m_shape;
|
||||||
std::string m_texture_filename;
|
std::string m_texture_filename;
|
||||||
std::string m_model_filename;
|
std::string m_model_filename;
|
||||||
@ -94,16 +115,18 @@ public:
|
|||||||
~Bed3D() { reset(); }
|
~Bed3D() { reset(); }
|
||||||
|
|
||||||
EType get_type() const { return m_type; }
|
EType get_type() const { return m_type; }
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
EShapeType get_shape_type() const { return m_shape_type; }
|
||||||
|
bool is_custom() const { return m_type == EType::Custom; }
|
||||||
|
#else
|
||||||
bool is_custom() const { return m_type == Custom; }
|
bool is_custom() const { return m_type == Custom; }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
const Pointfs& get_shape() const { return m_shape; }
|
const Pointfs& get_shape() const { return m_shape; }
|
||||||
// Return true if the bed shape changed, so the calee will update the UI.
|
// Return true if the bed shape changed, so the calee will update the UI.
|
||||||
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false);
|
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false);
|
||||||
|
|
||||||
const BoundingBoxf3& get_bounding_box(bool extended) const {
|
const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; }
|
||||||
return extended ? m_extended_bounding_box : m_bounding_box;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains(const Point& point) const;
|
bool contains(const Point& point) const;
|
||||||
Point point_projection(const Point& point) const;
|
Point point_projection(const Point& point) const;
|
||||||
@ -113,6 +136,13 @@ public:
|
|||||||
|
|
||||||
void render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor);
|
void render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
static bool is_rectangle(const Pointfs& shape, Vec2d* min = nullptr, Vec2d* max = nullptr);
|
||||||
|
static bool is_circle(const Pointfs& shape, Vec2d* center = nullptr, double* radius = nullptr);
|
||||||
|
static bool is_convex(const Pointfs& shape);
|
||||||
|
static EShapeType detect_shape_type(const Pointfs& shape);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calc_bounding_boxes() const;
|
void calc_bounding_boxes() const;
|
||||||
void calc_triangles(const ExPolygon& poly);
|
void calc_triangles(const ExPolygon& poly);
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
#include "GLShader.hpp"
|
#include "GLShader.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
|
#include "BitmapCache.hpp"
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
#include "3DBed.hpp"
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||||
@ -17,7 +21,6 @@
|
|||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/SLAPrint.hpp"
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
#include "libslic3r/Slicing.hpp"
|
#include "libslic3r/Slicing.hpp"
|
||||||
#include "slic3r/GUI/BitmapCache.hpp"
|
|
||||||
#include "libslic3r/Format/STL.hpp"
|
#include "libslic3r/Format/STL.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/AppConfig.hpp"
|
#include "libslic3r/AppConfig.hpp"
|
||||||
@ -37,6 +40,12 @@
|
|||||||
|
|
||||||
#include <Eigen/Dense>
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
#include <libqhullcpp/Qhull.h>
|
||||||
|
#include <libqhullcpp/QhullFacetList.h>
|
||||||
|
#include <libqhullcpp/QhullVertexSet.h>
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
#ifdef HAS_GLSAFE
|
#ifdef HAS_GLSAFE
|
||||||
void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char* function_name)
|
void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char* function_name)
|
||||||
{
|
{
|
||||||
@ -261,6 +270,12 @@ void GLIndexedVertexArray::render(
|
|||||||
const std::pair<size_t, size_t>& tverts_range,
|
const std::pair<size_t, size_t>& tverts_range,
|
||||||
const std::pair<size_t, size_t>& qverts_range) const
|
const std::pair<size_t, size_t>& qverts_range) const
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// this method has been called before calling finalize() ?
|
||||||
|
if (this->vertices_and_normals_interleaved_VBO_id == 0 && !this->vertices_and_normals_interleaved.empty())
|
||||||
|
return;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
|
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
|
||||||
assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
|
assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
|
||||||
|
|
||||||
@ -319,19 +334,7 @@ void GLVolume::SinkingContours::update()
|
|||||||
MeshSlicingParams slicing_params;
|
MeshSlicingParams slicing_params;
|
||||||
slicing_params.trafo = m_parent.world_matrix();
|
slicing_params.trafo = m_parent.world_matrix();
|
||||||
Polygons polygons = union_(slice_mesh(mesh.its, 0.0f, slicing_params));
|
Polygons polygons = union_(slice_mesh(mesh.its, 0.0f, slicing_params));
|
||||||
for (Polygon& polygon : polygons) {
|
for (ExPolygon &expoly : diff_ex(expand(polygons, float(scale_(HalfWidth))), shrink(polygons, float(scale_(HalfWidth))))) {
|
||||||
if (polygon.is_clockwise())
|
|
||||||
polygon.reverse();
|
|
||||||
Polygons outer_polys = offset(polygon, float(scale_(HalfWidth)));
|
|
||||||
assert(outer_polys.size() == 1);
|
|
||||||
if (outer_polys.empty())
|
|
||||||
// no outer contour, skip
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ExPolygon expoly(std::move(outer_polys.front()));
|
|
||||||
expoly.holes = offset(polygon, -float(scale_(HalfWidth)));
|
|
||||||
polygons_reverse(expoly.holes);
|
|
||||||
|
|
||||||
GUI::GLModel::InitializationData::Entity entity;
|
GUI::GLModel::InitializationData::Entity entity;
|
||||||
entity.type = GUI::GLModel::PrimitiveType::Triangles;
|
entity.type = GUI::GLModel::PrimitiveType::Triangles;
|
||||||
const std::vector<Vec3d> triangulation = triangulate_expolygon_3d(expoly);
|
const std::vector<Vec3d> triangulation = triangulate_expolygon_3d(expoly);
|
||||||
@ -529,6 +532,23 @@ BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &
|
|||||||
bounding_box().transformed(trafo);
|
bounding_box().transformed(trafo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
BoundingBoxf3 GLVolume::transformed_non_sinking_bounding_box(const Transform3d& trafo) const
|
||||||
|
{
|
||||||
|
return GUI::wxGetApp().plater()->model().objects[object_idx()]->volumes[volume_idx()]->mesh().transformed_bounding_box(trafo, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const
|
||||||
|
{
|
||||||
|
if (!m_transformed_non_sinking_bounding_box.has_value()) {
|
||||||
|
std::optional<BoundingBoxf3>* trans_box = const_cast<std::optional<BoundingBoxf3>*>(&m_transformed_non_sinking_bounding_box);
|
||||||
|
const Transform3d& trafo = world_matrix();
|
||||||
|
*trans_box = transformed_non_sinking_bounding_box(trafo);
|
||||||
|
}
|
||||||
|
return *m_transformed_non_sinking_bounding_box;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
void GLVolume::set_range(double min_z, double max_z)
|
void GLVolume::set_range(double min_z, double max_z)
|
||||||
{
|
{
|
||||||
this->qverts_range.first = 0;
|
this->qverts_range.first = 0;
|
||||||
@ -603,6 +623,106 @@ void GLVolume::render_sinking_contours()
|
|||||||
m_sinking_contours.render();
|
m_sinking_contours.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
void GLVolume::calc_convex_hull_3d()
|
||||||
|
{
|
||||||
|
if (this->indexed_vertex_array.vertices_and_normals_interleaved.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
TriangleMesh mesh;
|
||||||
|
for (size_t i = 0; i < this->indexed_vertex_array.vertices_and_normals_interleaved.size(); i += 6) {
|
||||||
|
const size_t v_id = 3 + i;
|
||||||
|
mesh.its.vertices.push_back({ this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 0],
|
||||||
|
this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 1],
|
||||||
|
this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 2]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Vec3f>& vertices = mesh.its.vertices;
|
||||||
|
|
||||||
|
// The qhull call:
|
||||||
|
orgQhull::Qhull qhull;
|
||||||
|
qhull.disableOutputStream(); // we want qhull to be quiet
|
||||||
|
std::vector<realT> src_vertices;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if REALfloat
|
||||||
|
qhull.runQhull("", 3, (int)vertices.size(), (const realT*)(vertices.front().data()), "Qt");
|
||||||
|
#else
|
||||||
|
src_vertices.reserve(vertices.size() * 3);
|
||||||
|
// We will now fill the vector with input points for computation:
|
||||||
|
for (const stl_vertex& v : vertices)
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
src_vertices.emplace_back(v(i));
|
||||||
|
qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::cout << "GLVolume::calc_convex_hull_3d() - Unable to create convex hull" << std::endl;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's collect results:
|
||||||
|
std::vector<Vec3f> dst_vertices;
|
||||||
|
std::vector<Vec3i> dst_facets;
|
||||||
|
// Map of QHull's vertex ID to our own vertex ID (pointing to dst_vertices).
|
||||||
|
std::vector<int> map_dst_vertices;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
Vec3f centroid = Vec3f::Zero();
|
||||||
|
for (const auto& pt : vertices)
|
||||||
|
centroid += pt;
|
||||||
|
centroid /= float(vertices.size());
|
||||||
|
#endif // NDEBUG
|
||||||
|
for (const orgQhull::QhullFacet& facet : qhull.facetList()) {
|
||||||
|
// Collect face vertices first, allocate unique vertices in dst_vertices based on QHull's vertex ID.
|
||||||
|
Vec3i indices;
|
||||||
|
int cnt = 0;
|
||||||
|
for (const orgQhull::QhullVertex vertex : facet.vertices()) {
|
||||||
|
const int id = vertex.id();
|
||||||
|
assert(id >= 0);
|
||||||
|
if (id >= int(map_dst_vertices.size()))
|
||||||
|
map_dst_vertices.resize(next_highest_power_of_2(size_t(id + 1)), -1);
|
||||||
|
if (int i = map_dst_vertices[id]; i == -1) {
|
||||||
|
// Allocate a new vertex.
|
||||||
|
i = int(dst_vertices.size());
|
||||||
|
map_dst_vertices[id] = i;
|
||||||
|
orgQhull::QhullPoint pt(vertex.point());
|
||||||
|
dst_vertices.emplace_back(pt[0], pt[1], pt[2]);
|
||||||
|
indices[cnt] = i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Reuse existing vertex.
|
||||||
|
indices[cnt] = i;
|
||||||
|
|
||||||
|
if (cnt++ == 3)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(cnt == 3);
|
||||||
|
if (cnt == 3) {
|
||||||
|
// QHull sorts vertices of a face lexicographically by their IDs, not by face normals.
|
||||||
|
// Calculate face normal based on the order of vertices.
|
||||||
|
const Vec3f n = (dst_vertices[indices(1)] - dst_vertices[indices(0)]).cross(dst_vertices[indices(2)] - dst_vertices[indices(1)]);
|
||||||
|
auto* n2 = facet.getBaseT()->normal;
|
||||||
|
const auto d = n.x() * n2[0] + n.y() * n2[1] + n.z() * n2[2];
|
||||||
|
#ifndef NDEBUG
|
||||||
|
const Vec3f n3 = (dst_vertices[indices(0)] - centroid);
|
||||||
|
const auto d3 = n.dot(n3);
|
||||||
|
assert((d < 0.f) == (d3 < 0.f));
|
||||||
|
#endif // NDEBUG
|
||||||
|
// Get the face normal from QHull.
|
||||||
|
if (d < 0.f)
|
||||||
|
// Fix face orientation.
|
||||||
|
std::swap(indices[1], indices[2]);
|
||||||
|
dst_facets.emplace_back(indices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh out_mesh{ std::move(dst_vertices), std::move(dst_facets) };
|
||||||
|
this->set_convex_hull(out_mesh);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
std::vector<int> GLVolumeCollection::load_object(
|
std::vector<int> GLVolumeCollection::load_object(
|
||||||
const ModelObject *model_object,
|
const ModelObject *model_object,
|
||||||
int obj_idx,
|
int obj_idx,
|
||||||
@ -761,6 +881,9 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||||||
volumes.emplace_back(new GLVolume(color));
|
volumes.emplace_back(new GLVolume(color));
|
||||||
GLVolume& v = *volumes.back();
|
GLVolume& v = *volumes.back();
|
||||||
v.indexed_vertex_array.load_mesh(mesh);
|
v.indexed_vertex_array.load_mesh(mesh);
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
v.set_convex_hull(mesh.convex_hull_3d());
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||||
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
|
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
|
||||||
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
|
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
|
||||||
@ -867,10 +990,17 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||||||
shader->set_uniform("uniform_color", volume.first->render_color);
|
shader->set_uniform("uniform_color", volume.first->render_color);
|
||||||
shader->set_uniform("z_range", m_z_range, 2);
|
shader->set_uniform("z_range", m_z_range, 2);
|
||||||
shader->set_uniform("clipping_plane", m_clipping_plane, 4);
|
shader->set_uniform("clipping_plane", m_clipping_plane, 4);
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
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.z_data", m_print_volume.zs);
|
||||||
|
shader->set_uniform("volume_world_matrix", volume.first->world_matrix());
|
||||||
|
#else
|
||||||
shader->set_uniform("print_box.min", m_print_box_min, 3);
|
shader->set_uniform("print_box.min", m_print_box_min, 3);
|
||||||
shader->set_uniform("print_box.max", m_print_box_max, 3);
|
shader->set_uniform("print_box.max", m_print_box_max, 3);
|
||||||
shader->set_uniform("print_box.actived", volume.first->shader_outside_printer_detection_enabled);
|
shader->set_uniform("print_box.actived", volume.first->shader_outside_printer_detection_enabled);
|
||||||
shader->set_uniform("print_box.volume_world_matrix", volume.first->world_matrix());
|
shader->set_uniform("print_box.volume_world_matrix", volume.first->world_matrix());
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
shader->set_uniform("slope.actived", m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower);
|
shader->set_uniform("slope.actived", m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower);
|
||||||
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
|
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
|
||||||
shader->set_uniform("slope.normal_z", m_slope.normal_z);
|
shader->set_uniform("slope.normal_z", m_slope.normal_z);
|
||||||
@ -919,7 +1049,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||||||
glsafe(::glDisable(GL_BLEND));
|
glsafe(::glDisable(GL_BLEND));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state, bool as_toolpaths) const
|
||||||
|
#else
|
||||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const
|
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
{
|
{
|
||||||
if (config == nullptr)
|
if (config == nullptr)
|
||||||
return false;
|
return false;
|
||||||
@ -928,22 +1062,95 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||||||
if (opt == nullptr)
|
if (opt == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast<float>(scale_(BedEpsilon))).front();
|
||||||
|
const float bed_height = config->opt_float("max_print_height");
|
||||||
|
const BoundingBox bed_box_2D = get_extents(bed_poly);
|
||||||
|
BoundingBoxf3 print_volume({ unscale<double>(bed_box_2D.min.x()), unscale<double>(bed_box_2D.min.y()), -1e10 },
|
||||||
|
{ unscale<double>(bed_box_2D.max.x()), unscale<double>(bed_box_2D.max.y()), bed_height });
|
||||||
|
|
||||||
|
auto check_against_rectangular_bed = [&print_volume](GLVolume& volume, ModelInstanceEPrintVolumeState& state) {
|
||||||
|
const BoundingBoxf3* const bb = volume.is_sinking() ? &volume.transformed_non_sinking_bounding_box() : &volume.transformed_convex_hull_bounding_box();
|
||||||
|
volume.is_outside = !print_volume.contains(*bb);
|
||||||
|
if (volume.printable) {
|
||||||
|
if (state == ModelInstancePVS_Inside && volume.is_outside)
|
||||||
|
state = ModelInstancePVS_Fully_Outside;
|
||||||
|
if (state == ModelInstancePVS_Fully_Outside && volume.is_outside && print_volume.intersects(*bb))
|
||||||
|
state = ModelInstancePVS_Partly_Outside;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto check_against_circular_bed = [](GLVolume& volume, ModelInstanceEPrintVolumeState& state, const Vec2d& center, double radius) {
|
||||||
|
const TriangleMesh* mesh = volume.is_sinking() ? &GUI::wxGetApp().plater()->model().objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : volume.convex_hull();
|
||||||
|
const Polygon volume_hull_2d = its_convex_hull_2d_above(mesh->its, volume.world_matrix().cast<float>(), 0.0f);
|
||||||
|
size_t outside_count = 0;
|
||||||
|
const double sq_radius = sqr(radius);
|
||||||
|
for (const Point& p : volume_hull_2d.points) {
|
||||||
|
if (sq_radius < (unscale(p) - center).squaredNorm())
|
||||||
|
++outside_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
volume.is_outside = outside_count > 0;
|
||||||
|
if (volume.printable) {
|
||||||
|
if (state == ModelInstancePVS_Inside && volume.is_outside)
|
||||||
|
state = ModelInstancePVS_Fully_Outside;
|
||||||
|
if (state == ModelInstancePVS_Fully_Outside && volume.is_outside && outside_count < volume_hull_2d.size())
|
||||||
|
state = ModelInstancePVS_Partly_Outside;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto check_against_convex_bed = [&bed_poly, bed_height](GLVolume& volume, ModelInstanceEPrintVolumeState& state) {
|
||||||
|
const TriangleMesh* mesh = volume.is_sinking() ? &GUI::wxGetApp().plater()->model().objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : volume.convex_hull();
|
||||||
|
const Polygon volume_hull_2d = its_convex_hull_2d_above(mesh->its, volume.world_matrix().cast<float>(), 0.0f);
|
||||||
|
const BoundingBoxf3* const bb = volume.is_sinking() ? &volume.transformed_non_sinking_bounding_box() : &volume.transformed_convex_hull_bounding_box();
|
||||||
|
ModelInstanceEPrintVolumeState volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb->min.z(), bb->max.z());
|
||||||
|
bool contained = (volume_state == ModelInstancePVS_Inside);
|
||||||
|
bool intersects = (volume_state == ModelInstancePVS_Partly_Outside);
|
||||||
|
|
||||||
|
volume.is_outside = !contained;
|
||||||
|
if (volume.printable) {
|
||||||
|
if (state == ModelInstancePVS_Inside && volume.is_outside)
|
||||||
|
state = ModelInstancePVS_Fully_Outside;
|
||||||
|
|
||||||
|
if (state == ModelInstancePVS_Fully_Outside && volume.is_outside && intersects)
|
||||||
|
state = ModelInstancePVS_Partly_Outside;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
|
const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
|
||||||
BoundingBoxf3 print_volume({ unscale<double>(bed_box_2D.min.x()), unscale<double>(bed_box_2D.min.y()), 0.0 },
|
BoundingBoxf3 print_volume({ unscale<double>(bed_box_2D.min.x()), unscale<double>(bed_box_2D.min.y()), 0.0 },
|
||||||
{ unscale<double>(bed_box_2D.max.x()), unscale<double>(bed_box_2D.max.y()),
|
{ unscale<double>(bed_box_2D.max.x()), unscale<double>(bed_box_2D.max.y()), config->opt_float("max_print_height") });
|
||||||
config->opt_float("max_print_height") });
|
|
||||||
// Allow the objects to protrude below the print bed
|
// Allow the objects to protrude below the print bed
|
||||||
print_volume.min(2) = -1e10;
|
print_volume.min.z() = -1e10;
|
||||||
print_volume.min(0) -= BedEpsilon;
|
print_volume.min.x() -= BedEpsilon;
|
||||||
print_volume.min(1) -= BedEpsilon;
|
print_volume.min.y() -= BedEpsilon;
|
||||||
print_volume.max(0) += BedEpsilon;
|
print_volume.max.x() += BedEpsilon;
|
||||||
print_volume.max(1) += BedEpsilon;
|
print_volume.max.y() += BedEpsilon;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside;
|
|
||||||
|
|
||||||
|
ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside;
|
||||||
bool contained_min_one = false;
|
bool contained_min_one = false;
|
||||||
|
|
||||||
for (GLVolume* volume : this->volumes) {
|
for (GLVolume* volume : this->volumes) {
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (as_toolpaths && !volume->is_extrusion_path)
|
||||||
|
continue;
|
||||||
|
else if (!as_toolpaths && (volume->is_modifier || (!volume->shader_outside_printer_detection_enabled && (volume->is_wipe_tower || volume->composite_id.volume_id < 0))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (GUI::Bed3D::is_rectangle(opt->values))
|
||||||
|
check_against_rectangular_bed(*volume, overall_state);
|
||||||
|
else {
|
||||||
|
Vec2d center;
|
||||||
|
double radius;
|
||||||
|
if (GUI::Bed3D::is_circle(opt->values, ¢er, &radius))
|
||||||
|
check_against_circular_bed(*volume, overall_state, center, radius);
|
||||||
|
else if (GUI::Bed3D::is_convex(opt->values))
|
||||||
|
check_against_convex_bed(*volume, overall_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
contained_min_one |= !volume->is_outside;
|
||||||
|
#else
|
||||||
if (volume->is_modifier || (!volume->shader_outside_printer_detection_enabled && (volume->is_wipe_tower || volume->composite_id.volume_id < 0)))
|
if (volume->is_modifier || (!volume->shader_outside_printer_detection_enabled && (volume->is_wipe_tower || volume->composite_id.volume_id < 0)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -956,15 +1163,16 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||||||
|
|
||||||
contained_min_one |= contained;
|
contained_min_one |= contained;
|
||||||
|
|
||||||
if (state == ModelInstancePVS_Inside && volume->is_outside)
|
if (overall_state == ModelInstancePVS_Inside && volume->is_outside)
|
||||||
state = ModelInstancePVS_Fully_Outside;
|
overall_state = ModelInstancePVS_Fully_Outside;
|
||||||
|
|
||||||
if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb))
|
if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb))
|
||||||
state = ModelInstancePVS_Partly_Outside;
|
overall_state = ModelInstancePVS_Partly_Outside;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_state != nullptr)
|
if (out_state != nullptr)
|
||||||
*out_state = state;
|
*out_state = overall_state;
|
||||||
|
|
||||||
return contained_min_one;
|
return contained_min_one;
|
||||||
}
|
}
|
||||||
@ -1020,35 +1228,28 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
|
|||||||
std::vector<Color> colors(colors_count);
|
std::vector<Color> colors(colors_count);
|
||||||
|
|
||||||
unsigned char rgb[3];
|
unsigned char rgb[3];
|
||||||
for (unsigned int i = 0; i < colors_count; ++i)
|
for (unsigned int i = 0; i < colors_count; ++i) {
|
||||||
{
|
|
||||||
const std::string& txt_color = config->opt_string("extruder_colour", i);
|
const std::string& txt_color = config->opt_string("extruder_colour", i);
|
||||||
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
|
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
|
||||||
{
|
|
||||||
colors[i].set(txt_color, rgb);
|
colors[i].set(txt_color, rgb);
|
||||||
}
|
else {
|
||||||
else
|
|
||||||
{
|
|
||||||
const std::string& txt_color = config->opt_string("filament_colour", i);
|
const std::string& txt_color = config->opt_string("filament_colour", i);
|
||||||
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
|
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
|
||||||
colors[i].set(txt_color, rgb);
|
colors[i].set(txt_color, rgb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GLVolume* volume : volumes)
|
for (GLVolume* volume : volumes) {
|
||||||
{
|
if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0))
|
||||||
if ((volume == nullptr) || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int extruder_id = volume->extruder_id - 1;
|
int extruder_id = volume->extruder_id - 1;
|
||||||
if ((extruder_id < 0) || ((int)colors.size() <= extruder_id))
|
if (extruder_id < 0 || (int)colors.size() <= extruder_id)
|
||||||
extruder_id = 0;
|
extruder_id = 0;
|
||||||
|
|
||||||
const Color& color = colors[extruder_id];
|
const Color& color = colors[extruder_id];
|
||||||
if (!color.text.empty())
|
if (!color.text.empty()) {
|
||||||
{
|
for (int i = 0; i < 3; ++i) {
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
volume->color[i] = (float)color.rgb[i] * inv_255;
|
volume->color[i] = (float)color.rgb[i] * inv_255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@ enum ModelInstanceEPrintVolumeState : unsigned char;
|
|||||||
// Return appropriate color based on the ModelVolume.
|
// Return appropriate color based on the ModelVolume.
|
||||||
std::array<float, 4> color_from_model_volume(const ModelVolume& model_volume);
|
std::array<float, 4> color_from_model_volume(const ModelVolume& model_volume);
|
||||||
|
|
||||||
|
|
||||||
// A container for interleaved arrays of 3D vertices and normals,
|
// A container for interleaved arrays of 3D vertices and normals,
|
||||||
// possibly indexed by triangles and / or quads.
|
// possibly indexed by triangles and / or quads.
|
||||||
class GLIndexedVertexArray {
|
class GLIndexedVertexArray {
|
||||||
@ -279,6 +278,10 @@ private:
|
|||||||
std::shared_ptr<const TriangleMesh> m_convex_hull;
|
std::shared_ptr<const TriangleMesh> m_convex_hull;
|
||||||
// Bounding box of this volume, in unscaled coordinates.
|
// Bounding box of this volume, in unscaled coordinates.
|
||||||
std::optional<BoundingBoxf3> m_transformed_convex_hull_bounding_box;
|
std::optional<BoundingBoxf3> m_transformed_convex_hull_bounding_box;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// Bounding box of the non sinking part of this volume, in unscaled coordinates.
|
||||||
|
std::optional<BoundingBoxf3> m_transformed_non_sinking_bounding_box;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
class SinkingContours
|
class SinkingContours
|
||||||
{
|
{
|
||||||
@ -469,6 +472,12 @@ public:
|
|||||||
BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const;
|
BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const;
|
||||||
// caching variant
|
// caching variant
|
||||||
const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
|
const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// non-caching variant
|
||||||
|
BoundingBoxf3 transformed_non_sinking_bounding_box(const Transform3d& trafo) const;
|
||||||
|
// caching variant
|
||||||
|
const BoundingBoxf3& transformed_non_sinking_bounding_box() const;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
// convex hull
|
// convex hull
|
||||||
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
|
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
|
||||||
|
|
||||||
@ -481,7 +490,15 @@ public:
|
|||||||
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
|
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
|
||||||
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
void set_bounding_boxes_as_dirty() {
|
||||||
|
m_transformed_bounding_box.reset();
|
||||||
|
m_transformed_convex_hull_bounding_box.reset();
|
||||||
|
m_transformed_non_sinking_bounding_box.reset();
|
||||||
|
}
|
||||||
|
#else
|
||||||
void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); m_transformed_convex_hull_bounding_box.reset(); }
|
void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); m_transformed_convex_hull_bounding_box.reset(); }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
bool is_sla_support() const;
|
bool is_sla_support() const;
|
||||||
bool is_sla_pad() const;
|
bool is_sla_pad() const;
|
||||||
@ -498,6 +515,12 @@ public:
|
|||||||
// Return an estimate of the memory held by GPU vertex buffers.
|
// Return an estimate of the memory held by GPU vertex buffers.
|
||||||
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
|
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
|
||||||
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// calculates the 3D convex hull from indexed_vertex_array.vertices_and_normals_interleaved
|
||||||
|
// must be called before calling indexed_vertex_array.finalize_geometry();
|
||||||
|
void calc_convex_hull_3d();
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<GLVolume*> GLVolumePtrs;
|
typedef std::vector<GLVolume*> GLVolumePtrs;
|
||||||
@ -514,10 +537,30 @@ public:
|
|||||||
All
|
All
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
struct PrintVolume
|
||||||
|
{
|
||||||
|
// see: Bed3D::EShapeType
|
||||||
|
int type{ 0 };
|
||||||
|
// data contains:
|
||||||
|
// Rectangle:
|
||||||
|
// [0] = min.x, [1] = min.y, [2] = max.x, [3] = max.y
|
||||||
|
// Circle:
|
||||||
|
// [0] = center.x, [1] = center.y, [3] = radius
|
||||||
|
std::array<float, 4> data;
|
||||||
|
// [0] = min z, [1] = max z
|
||||||
|
std::array<float, 2> zs;
|
||||||
|
};
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
PrintVolume m_print_volume;
|
||||||
|
#else
|
||||||
// min and max vertex of the print box volume
|
// min and max vertex of the print box volume
|
||||||
float m_print_box_min[3];
|
float m_print_box_min[3];
|
||||||
float m_print_box_max[3];
|
float m_print_box_max[3];
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
// z range for clipping in shaders
|
// z range for clipping in shaders
|
||||||
float m_z_range[2];
|
float m_z_range[2];
|
||||||
@ -589,10 +632,14 @@ public:
|
|||||||
bool empty() const { return volumes.empty(); }
|
bool empty() const { return volumes.empty(); }
|
||||||
void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); }
|
void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); }
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; }
|
||||||
|
#else
|
||||||
void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) {
|
void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) {
|
||||||
m_print_box_min[0] = min_x; m_print_box_min[1] = min_y; m_print_box_min[2] = min_z;
|
m_print_box_min[0] = min_x; m_print_box_min[1] = min_y; m_print_box_min[2] = min_z;
|
||||||
m_print_box_max[0] = max_x; m_print_box_max[1] = max_y; m_print_box_max[2] = max_z;
|
m_print_box_max[0] = max_x; m_print_box_max[1] = max_y; m_print_box_max[2] = max_z;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; }
|
void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; }
|
||||||
void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; }
|
void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; }
|
||||||
@ -607,7 +654,11 @@ public:
|
|||||||
|
|
||||||
// returns true if all the volumes are completely contained in the print volume
|
// returns true if all the volumes are completely contained in the print volume
|
||||||
// returns the containment state in the given out_state, if non-null
|
// returns the containment state in the given out_state, if non-null
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state, bool as_toolpaths = false) const;
|
||||||
|
#else
|
||||||
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const;
|
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
void reset_outside_state();
|
void reset_outside_state();
|
||||||
|
|
||||||
void update_colors_by_extruder(const DynamicPrintConfig* config);
|
void update_colors_by_extruder(const DynamicPrintConfig* config);
|
||||||
|
@ -22,9 +22,25 @@ namespace GUI {
|
|||||||
|
|
||||||
BedShape::BedShape(const ConfigOptionPoints& points)
|
BedShape::BedShape(const ConfigOptionPoints& points)
|
||||||
{
|
{
|
||||||
auto polygon = Polygon::new_scale(points.values);
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (points.size() < 3) {
|
||||||
|
m_type = Bed3D::EShapeType::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
// is this a rectangle ?
|
// is this a rectangle ?
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
Vec2d min;
|
||||||
|
Vec2d max;
|
||||||
|
if (Bed3D::is_rectangle(points.values, &min, &max)) {
|
||||||
|
m_type = Bed3D::EShapeType::Rectangle;
|
||||||
|
m_rectSize = max - min;
|
||||||
|
m_rectOrigin = -min;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Polygon polygon = Polygon::new_scale(points.values);
|
||||||
if (points.size() == 4) {
|
if (points.size() == 4) {
|
||||||
auto lines = polygon.lines();
|
auto lines = polygon.lines();
|
||||||
if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) {
|
if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) {
|
||||||
@ -48,8 +64,21 @@ BedShape::BedShape(const ConfigOptionPoints& points)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
// is this a circle ?
|
// is this a circle ?
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
Vec2d center;
|
||||||
|
double radius;
|
||||||
|
if (Bed3D::is_circle(points.values, ¢er, &radius)) {
|
||||||
|
m_type = Bed3D::EShapeType::Circle;
|
||||||
|
m_diameter = 2.0 * radius;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a custom bed shape, use the polygon provided.
|
||||||
|
m_type = Bed3D::EShapeType::Custom;
|
||||||
|
#else
|
||||||
{
|
{
|
||||||
// Analyze the array of points.Do they reside on a circle ?
|
// Analyze the array of points.Do they reside on a circle ?
|
||||||
auto center = polygon.bounding_box().center();
|
auto center = polygon.bounding_box().center();
|
||||||
@ -84,6 +113,7 @@ BedShape::BedShape(const ConfigOptionPoints& points)
|
|||||||
|
|
||||||
// This is a custom bed shape, use the polygon provided.
|
// This is a custom bed shape, use the polygon provided.
|
||||||
m_type = Type::Custom;
|
m_type = Type::Custom;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_option_label(BedShape::Parameter param)
|
static std::string get_option_label(BedShape::Parameter param)
|
||||||
@ -134,6 +164,18 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
wxString BedShape::get_name(Bed3D::EShapeType type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case Bed3D::EShapeType::Rectangle: { return _L("Rectangular"); }
|
||||||
|
case Bed3D::EShapeType::Circle: { return _L("Circular"); }
|
||||||
|
case Bed3D::EShapeType::Custom: { return _L("Custom"); }
|
||||||
|
case Bed3D::EShapeType::Invalid:
|
||||||
|
default: return _L("Invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
wxString BedShape::get_name(Type type)
|
wxString BedShape::get_name(Type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -144,21 +186,34 @@ wxString BedShape::get_name(Type type)
|
|||||||
default: return _L("Invalid");
|
default: return _L("Invalid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
size_t BedShape::get_type()
|
size_t BedShape::get_type()
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
return static_cast<size_t>(m_type == Bed3D::EShapeType::Invalid ? Bed3D::EShapeType::Rectangle : m_type);
|
||||||
|
#else
|
||||||
return static_cast<size_t>(m_type == Type::Invalid ? Type::Rectangular : m_type);
|
return static_cast<size_t>(m_type == Type::Invalid ? Type::Rectangular : m_type);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString BedShape::get_full_name_with_params()
|
wxString BedShape::get_full_name_with_params()
|
||||||
{
|
{
|
||||||
wxString out = _L("Shape") + ": " + get_name(m_type);
|
wxString out = _L("Shape") + ": " + get_name(m_type);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (m_type == Bed3D::EShapeType::Rectangle) {
|
||||||
|
#else
|
||||||
if (m_type == Type::Rectangular) {
|
if (m_type == Type::Rectangular) {
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
out += "\n" + _(get_option_label(Parameter::RectSize)) + ": [" + ConfigOptionPoint(m_rectSize).serialize() + "]";
|
out += "\n" + _(get_option_label(Parameter::RectSize)) + ": [" + ConfigOptionPoint(m_rectSize).serialize() + "]";
|
||||||
out += "\n" + _(get_option_label(Parameter::RectOrigin))+ ": [" + ConfigOptionPoint(m_rectOrigin).serialize() + "]";
|
out += "\n" + _(get_option_label(Parameter::RectOrigin))+ ": [" + ConfigOptionPoint(m_rectOrigin).serialize() + "]";
|
||||||
}
|
}
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
else if (m_type == Bed3D::EShapeType::Circle)
|
||||||
|
#else
|
||||||
else if (m_type == Type::Circular)
|
else if (m_type == Type::Circular)
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
out += "\n" + _L(get_option_label(Parameter::Diameter)) + ": [" + double_to_string(m_diameter) + "]";
|
out += "\n" + _L(get_option_label(Parameter::Diameter)) + ": [" + double_to_string(m_diameter) + "]";
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
@ -166,11 +221,19 @@ wxString BedShape::get_full_name_with_params()
|
|||||||
|
|
||||||
void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup)
|
void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (m_type == Bed3D::EShapeType::Rectangle || m_type == Bed3D::EShapeType::Invalid) {
|
||||||
|
#else
|
||||||
if (m_type == Type::Rectangular || m_type == Type::Invalid) {
|
if (m_type == Type::Rectangular || m_type == Type::Invalid) {
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
optgroup->set_value("rect_size" , new ConfigOptionPoints{ m_rectSize });
|
optgroup->set_value("rect_size" , new ConfigOptionPoints{ m_rectSize });
|
||||||
optgroup->set_value("rect_origin" , new ConfigOptionPoints{ m_rectOrigin });
|
optgroup->set_value("rect_origin" , new ConfigOptionPoints{ m_rectOrigin });
|
||||||
}
|
}
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
else if (m_type == Bed3D::EShapeType::Circle)
|
||||||
|
#else
|
||||||
else if (m_type == Type::Circular)
|
else if (m_type == Type::Circular)
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
optgroup->set_value("diameter", double_to_string(m_diameter));
|
optgroup->set_value("diameter", double_to_string(m_diameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +285,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf
|
|||||||
m_custom_texture = custom_texture.value.empty() ? NONE : custom_texture.value;
|
m_custom_texture = custom_texture.value.empty() ? NONE : custom_texture.value;
|
||||||
m_custom_model = custom_model.value.empty() ? NONE : custom_model.value;
|
m_custom_model = custom_model.value.empty() ? NONE : custom_model.value;
|
||||||
|
|
||||||
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
|
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _L("Shape"));
|
||||||
sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font());
|
sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font());
|
||||||
wxGetApp().UpdateDarkUI(sbsizer->GetStaticBox());
|
wxGetApp().UpdateDarkUI(sbsizer->GetStaticBox());
|
||||||
|
|
||||||
@ -232,16 +295,28 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf
|
|||||||
|
|
||||||
sbsizer->Add(m_shape_options_book);
|
sbsizer->Add(m_shape_options_book);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
auto optgroup = init_shape_options_page(BedShape::get_name(Bed3D::EShapeType::Rectangle));
|
||||||
|
#else
|
||||||
auto optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Rectangular));
|
auto optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Rectangular));
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
BedShape::append_option_line(optgroup, BedShape::Parameter::RectSize);
|
BedShape::append_option_line(optgroup, BedShape::Parameter::RectSize);
|
||||||
BedShape::append_option_line(optgroup, BedShape::Parameter::RectOrigin);
|
BedShape::append_option_line(optgroup, BedShape::Parameter::RectOrigin);
|
||||||
activate_options_page(optgroup);
|
activate_options_page(optgroup);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
optgroup = init_shape_options_page(BedShape::get_name(Bed3D::EShapeType::Circle));
|
||||||
|
#else
|
||||||
optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Circular));
|
optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Circular));
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
BedShape::append_option_line(optgroup, BedShape::Parameter::Diameter);
|
BedShape::append_option_line(optgroup, BedShape::Parameter::Diameter);
|
||||||
activate_options_page(optgroup);
|
activate_options_page(optgroup);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
optgroup = init_shape_options_page(BedShape::get_name(Bed3D::EShapeType::Custom));
|
||||||
|
#else
|
||||||
optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Custom));
|
optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Custom));
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
Line line{ "", "" };
|
Line line{ "", "" };
|
||||||
line.full_width = 1;
|
line.full_width = 1;
|
||||||
@ -265,10 +340,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf
|
|||||||
wxPanel* texture_panel = init_texture_panel();
|
wxPanel* texture_panel = init_texture_panel();
|
||||||
wxPanel* model_panel = init_model_panel();
|
wxPanel* model_panel = init_model_panel();
|
||||||
|
|
||||||
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
|
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e) { update_shape(); }));
|
||||||
{
|
|
||||||
update_shape();
|
|
||||||
}));
|
|
||||||
|
|
||||||
// right pane with preview canvas
|
// right pane with preview canvas
|
||||||
m_canvas = new Bed_2D(this);
|
m_canvas = new Bed_2D(this);
|
||||||
@ -295,7 +367,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf
|
|||||||
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
|
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
|
||||||
{
|
{
|
||||||
wxPanel* panel = new wxPanel(m_shape_options_book);
|
wxPanel* panel = new wxPanel(m_shape_options_book);
|
||||||
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
|
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _L("Settings"));
|
||||||
|
|
||||||
optgroup->label_width = 10;
|
optgroup->label_width = 10;
|
||||||
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
@ -319,7 +391,7 @@ wxPanel* BedShapePanel::init_texture_panel()
|
|||||||
{
|
{
|
||||||
wxPanel* panel = new wxPanel(this);
|
wxPanel* panel = new wxPanel(this);
|
||||||
wxGetApp().UpdateDarkUI(panel, true);
|
wxGetApp().UpdateDarkUI(panel, true);
|
||||||
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Texture")));
|
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _L("Texture"));
|
||||||
|
|
||||||
optgroup->label_width = 10;
|
optgroup->label_width = 10;
|
||||||
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
@ -329,7 +401,7 @@ wxPanel* BedShapePanel::init_texture_panel()
|
|||||||
Line line{ "", "" };
|
Line line{ "", "" };
|
||||||
line.full_width = 1;
|
line.full_width = 1;
|
||||||
line.widget = [this](wxWindow* parent) {
|
line.widget = [this](wxWindow* parent) {
|
||||||
wxButton* load_btn = new wxButton(parent, wxID_ANY, _(L("Load...")));
|
wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load..."));
|
||||||
wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
load_sizer->Add(load_btn, 1, wxEXPAND);
|
load_sizer->Add(load_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
@ -338,7 +410,7 @@ wxPanel* BedShapePanel::init_texture_panel()
|
|||||||
wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
filename_sizer->Add(filename_lbl, 1, wxEXPAND);
|
filename_sizer->Add(filename_lbl, 1, wxEXPAND);
|
||||||
|
|
||||||
wxButton* remove_btn = new wxButton(parent, wxID_ANY, _(L("Remove")));
|
wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove"));
|
||||||
wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
remove_sizer->Add(remove_btn, 1, wxEXPAND);
|
remove_sizer->Add(remove_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
@ -347,31 +419,23 @@ wxPanel* BedShapePanel::init_texture_panel()
|
|||||||
sizer->Add(load_sizer, 1, wxEXPAND);
|
sizer->Add(load_sizer, 1, wxEXPAND);
|
||||||
sizer->Add(remove_sizer, 1, wxEXPAND | wxTOP, 2);
|
sizer->Add(remove_sizer, 1, wxEXPAND | wxTOP, 2);
|
||||||
|
|
||||||
load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { load_texture(); }));
|
||||||
{
|
remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) {
|
||||||
load_texture();
|
|
||||||
}));
|
|
||||||
|
|
||||||
remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
|
||||||
{
|
|
||||||
m_custom_texture = NONE;
|
m_custom_texture = NONE;
|
||||||
update_shape();
|
update_shape();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) {
|
||||||
{
|
|
||||||
e.SetText(_(boost::filesystem::path(m_custom_texture).filename().string()));
|
e.SetText(_(boost::filesystem::path(m_custom_texture).filename().string()));
|
||||||
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
||||||
if (lbl != nullptr)
|
if (lbl != nullptr) {
|
||||||
{
|
|
||||||
bool exists = (m_custom_texture == NONE) || boost::filesystem::exists(m_custom_texture);
|
bool exists = (m_custom_texture == NONE) || boost::filesystem::exists(m_custom_texture);
|
||||||
lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED));
|
lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED));
|
||||||
|
|
||||||
wxString tooltip_text = "";
|
wxString tooltip_text = "";
|
||||||
if (m_custom_texture != NONE)
|
if (m_custom_texture != NONE) {
|
||||||
{
|
|
||||||
if (!exists)
|
if (!exists)
|
||||||
tooltip_text += _(L("Not found:")) + " ";
|
tooltip_text += _L("Not found:") + " ";
|
||||||
|
|
||||||
tooltip_text += _(m_custom_texture);
|
tooltip_text += _(m_custom_texture);
|
||||||
}
|
}
|
||||||
@ -382,10 +446,7 @@ wxPanel* BedShapePanel::init_texture_panel()
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) { e.Enable(m_custom_texture != NONE); }));
|
||||||
{
|
|
||||||
e.Enable(m_custom_texture != NONE);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return sizer;
|
return sizer;
|
||||||
};
|
};
|
||||||
@ -401,7 +462,7 @@ wxPanel* BedShapePanel::init_model_panel()
|
|||||||
{
|
{
|
||||||
wxPanel* panel = new wxPanel(this);
|
wxPanel* panel = new wxPanel(this);
|
||||||
wxGetApp().UpdateDarkUI(panel, true);
|
wxGetApp().UpdateDarkUI(panel, true);
|
||||||
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Model")));
|
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(panel, _L("Model"));
|
||||||
|
|
||||||
optgroup->label_width = 10;
|
optgroup->label_width = 10;
|
||||||
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
@ -411,7 +472,7 @@ wxPanel* BedShapePanel::init_model_panel()
|
|||||||
Line line{ "", "" };
|
Line line{ "", "" };
|
||||||
line.full_width = 1;
|
line.full_width = 1;
|
||||||
line.widget = [this](wxWindow* parent) {
|
line.widget = [this](wxWindow* parent) {
|
||||||
wxButton* load_btn = new wxButton(parent, wxID_ANY, _(L("Load...")));
|
wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load..."));
|
||||||
wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
load_sizer->Add(load_btn, 1, wxEXPAND);
|
load_sizer->Add(load_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
@ -419,7 +480,7 @@ wxPanel* BedShapePanel::init_model_panel()
|
|||||||
wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
filename_sizer->Add(filename_lbl, 1, wxEXPAND);
|
filename_sizer->Add(filename_lbl, 1, wxEXPAND);
|
||||||
|
|
||||||
wxButton* remove_btn = new wxButton(parent, wxID_ANY, _(L("Remove")));
|
wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove"));
|
||||||
wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
remove_sizer->Add(remove_btn, 1, wxEXPAND);
|
remove_sizer->Add(remove_btn, 1, wxEXPAND);
|
||||||
|
|
||||||
@ -428,31 +489,24 @@ wxPanel* BedShapePanel::init_model_panel()
|
|||||||
sizer->Add(load_sizer, 1, wxEXPAND);
|
sizer->Add(load_sizer, 1, wxEXPAND);
|
||||||
sizer->Add(remove_sizer, 1, wxEXPAND | wxTOP, 2);
|
sizer->Add(remove_sizer, 1, wxEXPAND | wxTOP, 2);
|
||||||
|
|
||||||
load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { load_model(); }));
|
||||||
{
|
|
||||||
load_model();
|
|
||||||
}));
|
|
||||||
|
|
||||||
remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) {
|
||||||
{
|
|
||||||
m_custom_model = NONE;
|
m_custom_model = NONE;
|
||||||
update_shape();
|
update_shape();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) {
|
||||||
{
|
|
||||||
e.SetText(_(boost::filesystem::path(m_custom_model).filename().string()));
|
e.SetText(_(boost::filesystem::path(m_custom_model).filename().string()));
|
||||||
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
||||||
if (lbl != nullptr)
|
if (lbl != nullptr) {
|
||||||
{
|
|
||||||
bool exists = (m_custom_model == NONE) || boost::filesystem::exists(m_custom_model);
|
bool exists = (m_custom_model == NONE) || boost::filesystem::exists(m_custom_model);
|
||||||
lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED));
|
lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED));
|
||||||
|
|
||||||
wxString tooltip_text = "";
|
wxString tooltip_text = "";
|
||||||
if (m_custom_model != NONE)
|
if (m_custom_model != NONE) {
|
||||||
{
|
|
||||||
if (!exists)
|
if (!exists)
|
||||||
tooltip_text += _(L("Not found:")) + " ";
|
tooltip_text += _L("Not found:") + " ";
|
||||||
|
|
||||||
tooltip_text += _(m_custom_model);
|
tooltip_text += _(m_custom_model);
|
||||||
}
|
}
|
||||||
@ -463,10 +517,7 @@ wxPanel* BedShapePanel::init_model_panel()
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e)
|
remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) { e.Enable(m_custom_model != NONE); }));
|
||||||
{
|
|
||||||
e.Enable(m_custom_model != NONE);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return sizer;
|
return sizer;
|
||||||
};
|
};
|
||||||
@ -511,9 +562,17 @@ void BedShapePanel::update_shape()
|
|||||||
auto page_idx = m_shape_options_book->GetSelection();
|
auto page_idx = m_shape_options_book->GetSelection();
|
||||||
auto opt_group = m_optgroups[page_idx];
|
auto opt_group = m_optgroups[page_idx];
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
Bed3D::EShapeType page_type = static_cast<Bed3D::EShapeType>(page_idx);
|
||||||
|
#else
|
||||||
BedShape::Type page_type = static_cast<BedShape::Type>(page_idx);
|
BedShape::Type page_type = static_cast<BedShape::Type>(page_idx);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (page_type == Bed3D::EShapeType::Rectangle) {
|
||||||
|
#else
|
||||||
if (page_type == BedShape::Type::Rectangular) {
|
if (page_type == BedShape::Type::Rectangular) {
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
Vec2d rect_size(Vec2d::Zero());
|
Vec2d rect_size(Vec2d::Zero());
|
||||||
Vec2d rect_origin(Vec2d::Zero());
|
Vec2d rect_origin(Vec2d::Zero());
|
||||||
|
|
||||||
@ -544,7 +603,11 @@ void BedShapePanel::update_shape()
|
|||||||
Vec2d(x1, y1),
|
Vec2d(x1, y1),
|
||||||
Vec2d(x0, y1) };
|
Vec2d(x0, y1) };
|
||||||
}
|
}
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
else if (page_type == Bed3D::EShapeType::Circle) {
|
||||||
|
#else
|
||||||
else if (page_type == BedShape::Type::Circular) {
|
else if (page_type == BedShape::Type::Circular) {
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
double diameter;
|
double diameter;
|
||||||
try { diameter = boost::any_cast<double>(opt_group->get_value("diameter")); }
|
try { diameter = boost::any_cast<double>(opt_group->get_value("diameter")); }
|
||||||
catch (const std::exception & /* e */) { return; }
|
catch (const std::exception & /* e */) { return; }
|
||||||
@ -560,7 +623,11 @@ void BedShapePanel::update_shape()
|
|||||||
}
|
}
|
||||||
m_shape = points;
|
m_shape = points;
|
||||||
}
|
}
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
else if (page_type == Bed3D::EShapeType::Custom)
|
||||||
|
#else
|
||||||
else if (page_type == BedShape::Type::Custom)
|
else if (page_type == BedShape::Type::Custom)
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
m_shape = m_loaded_shape;
|
m_shape = m_loaded_shape;
|
||||||
|
|
||||||
update_preview();
|
update_preview();
|
||||||
@ -569,14 +636,13 @@ void BedShapePanel::update_shape()
|
|||||||
// Loads an stl file, projects it to the XY plane and calculates a polygon.
|
// Loads an stl file, projects it to the XY plane and calculates a polygon.
|
||||||
void BedShapePanel::load_stl()
|
void BedShapePanel::load_stl()
|
||||||
{
|
{
|
||||||
wxFileDialog dialog(this, _(L("Choose an STL file to import bed shape from:")), "", "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
wxFileDialog dialog(this, _L("Choose an STL file to import bed shape from:"), "", "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||||
if (dialog.ShowModal() != wxID_OK)
|
if (dialog.ShowModal() != wxID_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string file_name = dialog.GetPath().ToUTF8().data();
|
std::string file_name = dialog.GetPath().ToUTF8().data();
|
||||||
if (!boost::algorithm::iends_with(file_name, ".stl"))
|
if (!boost::algorithm::iends_with(file_name, ".stl")) {
|
||||||
{
|
show_error(this, _L("Invalid file format."));
|
||||||
show_error(this, _(L("Invalid file format.")));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,7 +653,7 @@ void BedShapePanel::load_stl()
|
|||||||
model = Model::read_from_file(file_name);
|
model = Model::read_from_file(file_name);
|
||||||
}
|
}
|
||||||
catch (std::exception &) {
|
catch (std::exception &) {
|
||||||
show_error(this, _(L("Error! Invalid model")));
|
show_error(this, _L("Error! Invalid model"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,11 +661,11 @@ void BedShapePanel::load_stl()
|
|||||||
auto expolygons = mesh.horizontal_projection();
|
auto expolygons = mesh.horizontal_projection();
|
||||||
|
|
||||||
if (expolygons.size() == 0) {
|
if (expolygons.size() == 0) {
|
||||||
show_error(this, _(L("The selected file contains no geometry.")));
|
show_error(this, _L("The selected file contains no geometry."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (expolygons.size() > 1) {
|
if (expolygons.size() > 1) {
|
||||||
show_error(this, _(L("The selected file contains several disjoint areas. This is not supported.")));
|
show_error(this, _L("The selected file contains several disjoint areas. This is not supported."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,7 +680,7 @@ void BedShapePanel::load_stl()
|
|||||||
|
|
||||||
void BedShapePanel::load_texture()
|
void BedShapePanel::load_texture()
|
||||||
{
|
{
|
||||||
wxFileDialog dialog(this, _(L("Choose a file to import bed texture from (PNG/SVG):")), "", "",
|
wxFileDialog dialog(this, _L("Choose a file to import bed texture from (PNG/SVG):"), "", "",
|
||||||
file_wildcards(FT_TEX), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
file_wildcards(FT_TEX), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||||
|
|
||||||
if (dialog.ShowModal() != wxID_OK)
|
if (dialog.ShowModal() != wxID_OK)
|
||||||
@ -623,9 +689,8 @@ void BedShapePanel::load_texture()
|
|||||||
m_custom_texture = NONE;
|
m_custom_texture = NONE;
|
||||||
|
|
||||||
std::string file_name = dialog.GetPath().ToUTF8().data();
|
std::string file_name = dialog.GetPath().ToUTF8().data();
|
||||||
if (!boost::algorithm::iends_with(file_name, ".png") && !boost::algorithm::iends_with(file_name, ".svg"))
|
if (!boost::algorithm::iends_with(file_name, ".png") && !boost::algorithm::iends_with(file_name, ".svg")) {
|
||||||
{
|
show_error(this, _L("Invalid file format."));
|
||||||
show_error(this, _(L("Invalid file format.")));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,7 +702,7 @@ void BedShapePanel::load_texture()
|
|||||||
|
|
||||||
void BedShapePanel::load_model()
|
void BedShapePanel::load_model()
|
||||||
{
|
{
|
||||||
wxFileDialog dialog(this, _(L("Choose an STL file to import bed model from:")), "", "",
|
wxFileDialog dialog(this, _L("Choose an STL file to import bed model from:"), "", "",
|
||||||
file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||||
|
|
||||||
if (dialog.ShowModal() != wxID_OK)
|
if (dialog.ShowModal() != wxID_OK)
|
||||||
@ -646,9 +711,8 @@ void BedShapePanel::load_model()
|
|||||||
m_custom_model = NONE;
|
m_custom_model = NONE;
|
||||||
|
|
||||||
std::string file_name = dialog.GetPath().ToUTF8().data();
|
std::string file_name = dialog.GetPath().ToUTF8().data();
|
||||||
if (!boost::algorithm::iends_with(file_name, ".stl"))
|
if (!boost::algorithm::iends_with(file_name, ".stl")) {
|
||||||
{
|
show_error(this, _L("Invalid file format."));
|
||||||
show_error(this, _(L("Invalid file format.")));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#include "GUI_Utils.hpp"
|
#include "GUI_Utils.hpp"
|
||||||
#include "2DBed.hpp"
|
#include "2DBed.hpp"
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
#include "3DBed.hpp"
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
|
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
@ -19,12 +22,14 @@ using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
|
|||||||
|
|
||||||
struct BedShape
|
struct BedShape
|
||||||
{
|
{
|
||||||
|
#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Rectangular = 0,
|
Rectangular = 0,
|
||||||
Circular,
|
Circular,
|
||||||
Custom,
|
Custom,
|
||||||
Invalid
|
Invalid
|
||||||
};
|
};
|
||||||
|
#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
enum class Parameter {
|
enum class Parameter {
|
||||||
RectSize,
|
RectSize,
|
||||||
@ -34,10 +39,18 @@ struct BedShape
|
|||||||
|
|
||||||
BedShape(const ConfigOptionPoints& points);
|
BedShape(const ConfigOptionPoints& points);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool is_custom() { return m_type == Bed3D::EShapeType::Custom; }
|
||||||
|
#else
|
||||||
bool is_custom() { return m_type == Type::Custom; }
|
bool is_custom() { return m_type == Type::Custom; }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
static void append_option_line(ConfigOptionsGroupShp optgroup, Parameter param);
|
static void append_option_line(ConfigOptionsGroupShp optgroup, Parameter param);
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
static wxString get_name(Bed3D::EShapeType type);
|
||||||
|
#else
|
||||||
static wxString get_name(Type type);
|
static wxString get_name(Type type);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
// convert Type to size_t
|
// convert Type to size_t
|
||||||
size_t get_type();
|
size_t get_type();
|
||||||
@ -46,7 +59,11 @@ struct BedShape
|
|||||||
void apply_optgroup_values(ConfigOptionsGroupShp optgroup);
|
void apply_optgroup_values(ConfigOptionsGroupShp optgroup);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
Bed3D::EShapeType m_type{ Bed3D::EShapeType::Invalid };
|
||||||
|
#else
|
||||||
Type m_type {Type::Invalid};
|
Type m_type {Type::Invalid};
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
Vec2d m_rectSize {200, 200};
|
Vec2d m_rectSize {200, 200};
|
||||||
Vec2d m_rectOrigin {0, 0};
|
Vec2d m_rectOrigin {0, 0};
|
||||||
double m_diameter {0};
|
double m_diameter {0};
|
||||||
|
@ -6,10 +6,11 @@
|
|||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/LocalesUtils.hpp"
|
#include "libslic3r/LocalesUtils.hpp"
|
||||||
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
|
||||||
#include "Camera.hpp"
|
#include "Camera.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "GUI_Utils.hpp"
|
#include "GUI_Utils.hpp"
|
||||||
@ -19,6 +20,10 @@
|
|||||||
#include "GLToolbar.hpp"
|
#include "GLToolbar.hpp"
|
||||||
#include "GUI_Preview.hpp"
|
#include "GUI_Preview.hpp"
|
||||||
#include "GUI_ObjectManipulation.hpp"
|
#include "GUI_ObjectManipulation.hpp"
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
#include "3DBed.hpp"
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
#include <imgui/imgui_internal.h>
|
#include <imgui/imgui_internal.h>
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
@ -674,6 +679,10 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print&
|
|||||||
if (wxGetApp().is_gcode_viewer())
|
if (wxGetApp().is_gcode_viewer())
|
||||||
m_custom_gcode_per_print_z = gcode_result.custom_gcode_per_print_z;
|
m_custom_gcode_per_print_z = gcode_result.custom_gcode_per_print_z;
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
m_max_print_height = gcode_result.max_print_height;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
load_toolpaths(gcode_result);
|
load_toolpaths(gcode_result);
|
||||||
|
|
||||||
if (m_layers.empty())
|
if (m_layers.empty())
|
||||||
@ -819,6 +828,9 @@ void GCodeViewer::reset()
|
|||||||
|
|
||||||
m_paths_bounding_box = BoundingBoxf3();
|
m_paths_bounding_box = BoundingBoxf3();
|
||||||
m_max_bounding_box = BoundingBoxf3();
|
m_max_bounding_box = BoundingBoxf3();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
m_max_print_height = 0.0f;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
m_tool_colors = std::vector<Color>();
|
m_tool_colors = std::vector<Color>();
|
||||||
m_extruders_count = 0;
|
m_extruders_count = 0;
|
||||||
m_extruder_ids = std::vector<unsigned char>();
|
m_extruder_ids = std::vector<unsigned char>();
|
||||||
@ -835,6 +847,9 @@ void GCodeViewer::reset()
|
|||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
m_statistics.reset_all();
|
m_statistics.reset_all();
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
m_contained_in_bed = true;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeViewer::render()
|
void GCodeViewer::render()
|
||||||
@ -1554,7 +1569,49 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||||||
|
|
||||||
// set approximate max bounding box (take in account also the tool marker)
|
// set approximate max bounding box (take in account also the tool marker)
|
||||||
m_max_bounding_box = m_paths_bounding_box;
|
m_max_bounding_box = m_paths_bounding_box;
|
||||||
m_max_bounding_box.merge(m_paths_bounding_box.max + m_sequential_view.marker.get_bounding_box().size()[2] * Vec3d::UnitZ());
|
m_max_bounding_box.merge(m_paths_bounding_box.max + m_sequential_view.marker.get_bounding_box().size().z() * Vec3d::UnitZ());
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (wxGetApp().is_editor()) {
|
||||||
|
const Bed3D::EShapeType bed_type = wxGetApp().plater()->get_bed().get_shape_type();
|
||||||
|
if (bed_type == Bed3D::EShapeType::Rectangle) {
|
||||||
|
BoundingBoxf3 print_volume = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
||||||
|
print_volume.min.z() = -1e10;
|
||||||
|
print_volume.max.z() = m_max_print_height;
|
||||||
|
print_volume.min -= Vec3f(BedEpsilon, BedEpsilon, 0.0f).cast<double>();
|
||||||
|
print_volume.max += Vec3f(BedEpsilon, BedEpsilon, 0.0f).cast<double>();
|
||||||
|
m_contained_in_bed = print_volume.contains(m_paths_bounding_box);
|
||||||
|
}
|
||||||
|
else if (bed_type == Bed3D::EShapeType::Circle) {
|
||||||
|
Vec2d center;
|
||||||
|
double radius;
|
||||||
|
Bed3D::is_circle(wxGetApp().plater()->get_bed().get_shape(), ¢er, &radius);
|
||||||
|
const double sq_radius = sqr(radius);
|
||||||
|
for (const GCodeProcessor::MoveVertex& move : gcode_result.moves) {
|
||||||
|
if (move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.0f && move.height != 0.0f) {
|
||||||
|
if (sq_radius < (Vec2d(move.position.x(), move.position.y()) - center).squaredNorm()) {
|
||||||
|
m_contained_in_bed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bed_type == Bed3D::EShapeType::Custom) {
|
||||||
|
const Pointfs& shape = wxGetApp().plater()->get_bed().get_shape();
|
||||||
|
if (Bed3D::is_convex(shape)) {
|
||||||
|
const Polygon poly = Polygon::new_scale(shape);
|
||||||
|
for (const GCodeProcessor::MoveVertex& move : gcode_result.moves) {
|
||||||
|
if (move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.0f && move.height != 0.0f) {
|
||||||
|
if (!poly.contains(Point::new_scale(Vec2d(move.position.x(), move.position.y())))) {
|
||||||
|
m_contained_in_bed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
#if ENABLE_FIX_SEAMS_SYNCH
|
#if ENABLE_FIX_SEAMS_SYNCH
|
||||||
m_sequential_view.gcode_ids.clear();
|
m_sequential_view.gcode_ids.clear();
|
||||||
|
@ -780,6 +780,9 @@ private:
|
|||||||
BoundingBoxf3 m_paths_bounding_box;
|
BoundingBoxf3 m_paths_bounding_box;
|
||||||
// bounding box of toolpaths + marker tools
|
// bounding box of toolpaths + marker tools
|
||||||
BoundingBoxf3 m_max_bounding_box;
|
BoundingBoxf3 m_max_bounding_box;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
float m_max_print_height{ 0.0f };
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
std::vector<Color> m_tool_colors;
|
std::vector<Color> m_tool_colors;
|
||||||
Layers m_layers;
|
Layers m_layers;
|
||||||
std::array<unsigned int, 2> m_layers_z_range;
|
std::array<unsigned int, 2> m_layers_z_range;
|
||||||
@ -804,6 +807,10 @@ private:
|
|||||||
|
|
||||||
std::vector<CustomGCode::Item> m_custom_gcode_per_print_z;
|
std::vector<CustomGCode::Item> m_custom_gcode_per_print_z;
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool m_contained_in_bed{ true };
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GCodeViewer();
|
GCodeViewer();
|
||||||
~GCodeViewer() { reset(); }
|
~GCodeViewer() { reset(); }
|
||||||
@ -832,6 +839,10 @@ public:
|
|||||||
const SequentialView& get_sequential_view() const { return m_sequential_view; }
|
const SequentialView& get_sequential_view() const { return m_sequential_view; }
|
||||||
void update_sequential_view_current(unsigned int first, unsigned int last);
|
void update_sequential_view_current(unsigned int first, unsigned int last);
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool is_contained_in_bed() const { return m_contained_in_bed; }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
EViewType get_view_type() const { return m_view_type; }
|
EViewType get_view_type() const { return m_view_type; }
|
||||||
void set_view_type(EViewType type) {
|
void set_view_type(EViewType type) {
|
||||||
if (type == EViewType::Count)
|
if (type == EViewType::Count)
|
||||||
|
@ -1108,10 +1108,18 @@ void GLCanvas3D::reset_volumes()
|
|||||||
_set_warning_notification(EWarning::ObjectOutside, false);
|
_set_warning_notification(EWarning::ObjectOutside, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state(bool as_toolpaths) const
|
||||||
|
#else
|
||||||
ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state() const
|
ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state() const
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
{
|
{
|
||||||
ModelInstanceEPrintVolumeState state;
|
ModelInstanceEPrintVolumeState state;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
m_volumes.check_outside_state(m_config, &state, as_toolpaths);
|
||||||
|
#else
|
||||||
m_volumes.check_outside_state(m_config, &state);
|
m_volumes.check_outside_state(m_config, &state);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1828,8 +1836,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
assert(volume_idx_wipe_tower_old == -1);
|
assert(volume_idx_wipe_tower_old == -1);
|
||||||
volume_idx_wipe_tower_old = (int)volume_id;
|
volume_idx_wipe_tower_old = (int)volume_id;
|
||||||
}
|
}
|
||||||
if (!m_reload_delayed)
|
if (!m_reload_delayed) {
|
||||||
{
|
|
||||||
deleted_volumes.emplace_back(volume, volume_id);
|
deleted_volumes.emplace_back(volume, volume_id);
|
||||||
delete volume;
|
delete volume;
|
||||||
}
|
}
|
||||||
@ -2123,8 +2130,10 @@ void GLCanvas3D::load_sla_preview()
|
|||||||
// Release OpenGL data before generating new data.
|
// Release OpenGL data before generating new data.
|
||||||
reset_volumes();
|
reset_volumes();
|
||||||
_load_sla_shells();
|
_load_sla_shells();
|
||||||
|
#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
||||||
m_volumes.set_print_box(float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, 0.0f, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
m_volumes.set_print_box(float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, 0.0f, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
||||||
|
#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
_update_sla_shells_outside_state();
|
_update_sla_shells_outside_state();
|
||||||
_set_warning_notification_if_needed(EWarning::SlaSupportsOutside);
|
_set_warning_notification_if_needed(EWarning::SlaSupportsOutside);
|
||||||
}
|
}
|
||||||
@ -3216,6 +3225,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) {
|
else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) {
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (evt.LeftUp())
|
||||||
|
m_selection.stop_dragging();
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
if (m_layers_editing.state != LayersEditing::Unknown) {
|
if (m_layers_editing.state != LayersEditing::Unknown) {
|
||||||
m_layers_editing.state = LayersEditing::Unknown;
|
m_layers_editing.state = LayersEditing::Unknown;
|
||||||
_stop_timer();
|
_stop_timer();
|
||||||
@ -4984,6 +4998,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
|
|||||||
_update_volumes_hover_state();
|
_update_volumes_hover_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
static BoundingBoxf3 print_volume(const DynamicPrintConfig& config)
|
static BoundingBoxf3 print_volume(const DynamicPrintConfig& config)
|
||||||
{
|
{
|
||||||
// tolerance to avoid false detection at bed edges
|
// tolerance to avoid false detection at bed edges
|
||||||
@ -5000,6 +5015,7 @@ static BoundingBoxf3 print_volume(const DynamicPrintConfig& config)
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
void GLCanvas3D::_render_background() const
|
void GLCanvas3D::_render_background() const
|
||||||
{
|
{
|
||||||
@ -5010,11 +5026,16 @@ void GLCanvas3D::_render_background() const
|
|||||||
|
|
||||||
if (!m_volumes.empty())
|
if (!m_volumes.empty())
|
||||||
use_error_color &= _is_any_volume_outside();
|
use_error_color &= _is_any_volume_outside();
|
||||||
else {
|
else
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
use_error_color &= m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed();
|
||||||
|
#else
|
||||||
|
{
|
||||||
const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
||||||
const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box();
|
const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box();
|
||||||
use_error_color &= (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0) ? !test_volume.contains(paths_volume) : false;
|
use_error_color &= (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0) ? !test_volume.contains(paths_volume) : false;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glPushMatrix());
|
glsafe(::glPushMatrix());
|
||||||
@ -5090,13 +5111,55 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
|
|||||||
if (m_picking_enabled) {
|
if (m_picking_enabled) {
|
||||||
// Update the layer editing selection to the first object selected, update the current object maximum Z.
|
// Update the layer editing selection to the first object selected, update the current object maximum Z.
|
||||||
m_layers_editing.select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1);
|
m_layers_editing.select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1);
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
if (m_config != nullptr) {
|
if (m_config != nullptr) {
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
Bed3D::EShapeType type = wxGetApp().plater()->get_bed().get_shape_type();
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Bed3D::EShapeType::Circle: {
|
||||||
|
Vec2d center;
|
||||||
|
double radius;
|
||||||
|
if (Bed3D::is_circle(wxGetApp().plater()->get_bed().get_shape(), ¢er, &radius)) {
|
||||||
|
m_volumes.set_print_volume({ static_cast<int>(type),
|
||||||
|
{ float(center.x()), float(center.y()), float(radius) + BedEpsilon, 0.0f },
|
||||||
|
{ 0.0f, float(m_config->opt_float("max_print_height")) } });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Bed3D::EShapeType::Rectangle: {
|
||||||
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
||||||
m_volumes.set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
m_volumes.set_print_volume({ static_cast<int>(type),
|
||||||
|
{ float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon },
|
||||||
|
{ 0.0f, float(m_config->opt_float("max_print_height")) } });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
case Bed3D::EShapeType::Custom: {
|
||||||
|
m_volumes.set_print_volume({ static_cast<int>(type),
|
||||||
|
{ 0.0f, 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
||||||
|
m_volumes.set_print_box((float)bed_bb.min.x() - BedEpsilon, (float)bed_bb.min.y() - BedEpsilon, 0.0f, (float)bed_bb.max.x() + BedEpsilon, (float)bed_bb.max.y() + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (m_requires_check_outside_state) {
|
||||||
m_volumes.check_outside_state(m_config, nullptr);
|
m_volumes.check_outside_state(m_config, nullptr);
|
||||||
|
m_requires_check_outside_state = false;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
m_volumes.check_outside_state(m_config, nullptr);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
}
|
||||||
|
#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
if (m_use_clipping_planes)
|
if (m_use_clipping_planes)
|
||||||
m_volumes.set_z_range(-m_clipping_planes[0].get_data()[3], m_clipping_planes[1].get_data()[3]);
|
m_volumes.set_z_range(-m_clipping_planes[0].get_data()[3], m_clipping_planes[1].get_data()[3]);
|
||||||
@ -5106,7 +5169,11 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
|
|||||||
m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
|
m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
|
||||||
m_volumes.set_show_sinking_contours(! m_gizmos.is_hiding_instances());
|
m_volumes.set_show_sinking_contours(! m_gizmos.is_hiding_instances());
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_mod");
|
||||||
|
#else
|
||||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
|
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
if (shader != nullptr) {
|
if (shader != nullptr) {
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
|
|
||||||
@ -5751,7 +5818,7 @@ void GLCanvas3D::_load_print_toolpaths()
|
|||||||
total_layer_count = std::max(total_layer_count, print_object->total_layer_count());
|
total_layer_count = std::max(total_layer_count, print_object->total_layer_count());
|
||||||
}
|
}
|
||||||
size_t skirt_height = print->has_infinite_skirt() ? total_layer_count : std::min<size_t>(print->config().skirt_height.value, total_layer_count);
|
size_t skirt_height = print->has_infinite_skirt() ? total_layer_count : std::min<size_t>(print->config().skirt_height.value, total_layer_count);
|
||||||
if ((skirt_height == 0) && print->has_brim())
|
if (skirt_height == 0 && print->has_brim())
|
||||||
skirt_height = 1;
|
skirt_height = 1;
|
||||||
|
|
||||||
// Get first skirt_height layers.
|
// Get first skirt_height layers.
|
||||||
@ -5784,6 +5851,9 @@ void GLCanvas3D::_load_print_toolpaths()
|
|||||||
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
|
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
volume->calc_convex_hull_3d();
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6074,8 +6144,16 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
|
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
|
||||||
[](const GLVolume *volume) { return volume->empty(); }),
|
[](const GLVolume *volume) { return volume->empty(); }),
|
||||||
m_volumes.volumes.end());
|
m_volumes.volumes.end());
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
||||||
|
GLVolume* v = m_volumes.volumes[i];
|
||||||
|
v->calc_convex_hull_3d();
|
||||||
|
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
|
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
|
||||||
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||||
}
|
}
|
||||||
@ -6083,7 +6161,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||||||
void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors)
|
void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors)
|
||||||
{
|
{
|
||||||
const Print *print = this->fff_print();
|
const Print *print = this->fff_print();
|
||||||
if ((print == nullptr) || print->wipe_tower_data().tool_changes.empty())
|
if (print == nullptr || print->wipe_tower_data().tool_changes.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!print->is_step_done(psWipeTower))
|
if (!print->is_step_done(psWipeTower))
|
||||||
@ -6231,8 +6309,16 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||||||
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
|
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
|
||||||
[](const GLVolume *volume) { return volume->empty(); }),
|
[](const GLVolume *volume) { return volume->empty(); }),
|
||||||
m_volumes.volumes.end());
|
m_volumes.volumes.end());
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
|
||||||
|
GLVolume* v = m_volumes.volumes[i];
|
||||||
|
v->calc_convex_hull_3d();
|
||||||
|
v->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
|
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
|
||||||
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||||
}
|
}
|
||||||
@ -6294,18 +6380,26 @@ void GLCanvas3D::_load_sla_shells()
|
|||||||
|
|
||||||
void GLCanvas3D::_update_toolpath_volumes_outside_state()
|
void GLCanvas3D::_update_toolpath_volumes_outside_state()
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
check_volumes_outside_state(true);
|
||||||
|
#else
|
||||||
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
||||||
for (GLVolume* volume : m_volumes.volumes) {
|
for (GLVolume* volume : m_volumes.volumes) {
|
||||||
volume->is_outside = (test_volume.radius() > 0.0 && volume->is_extrusion_path) ? !test_volume.contains(volume->bounding_box()) : false;
|
volume->is_outside = (test_volume.radius() > 0.0 && volume->is_extrusion_path) ? !test_volume.contains(volume->bounding_box()) : false;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::_update_sla_shells_outside_state()
|
void GLCanvas3D::_update_sla_shells_outside_state()
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
check_volumes_outside_state();
|
||||||
|
#else
|
||||||
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
||||||
for (GLVolume* volume : m_volumes.volumes) {
|
for (GLVolume* volume : m_volumes.volumes) {
|
||||||
volume->is_outside = (test_volume.radius() > 0.0 && volume->shader_outside_printer_detection_enabled) ? !test_volume.contains(volume->transformed_convex_hull_bounding_box()) : false;
|
volume->is_outside = (test_volume.radius() > 0.0 && volume->shader_outside_printer_detection_enabled) ? !test_volume.contains(volume->transformed_convex_hull_bounding_box()) : false;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
|
void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
|
||||||
@ -6316,12 +6410,18 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
|
|||||||
show = _is_any_volume_outside();
|
show = _is_any_volume_outside();
|
||||||
else {
|
else {
|
||||||
if (wxGetApp().is_editor()) {
|
if (wxGetApp().is_editor()) {
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (current_printer_technology() != ptSLA)
|
||||||
|
show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed();
|
||||||
|
#else
|
||||||
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
|
||||||
const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box();
|
const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box();
|
||||||
if (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0)
|
if (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0)
|
||||||
show = !test_volume.contains(paths_volume);
|
show = !test_volume.contains(paths_volume);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_set_warning_notification(warning, show);
|
_set_warning_notification(warning, show);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6396,7 +6496,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
|||||||
bool GLCanvas3D::_is_any_volume_outside() const
|
bool GLCanvas3D::_is_any_volume_outside() const
|
||||||
{
|
{
|
||||||
for (const GLVolume* volume : m_volumes.volumes) {
|
for (const GLVolume* volume : m_volumes.volumes) {
|
||||||
if ((volume != nullptr) && volume->is_outside)
|
if (volume != nullptr && volume->is_outside)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,6 +475,9 @@ private:
|
|||||||
const DynamicPrintConfig* m_config;
|
const DynamicPrintConfig* m_config;
|
||||||
Model* m_model;
|
Model* m_model;
|
||||||
BackgroundSlicingProcess *m_process;
|
BackgroundSlicingProcess *m_process;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool m_requires_check_outside_state{ false };
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
std::array<unsigned int, 2> m_old_size{ 0, 0 };
|
std::array<unsigned int, 2> m_old_size{ 0, 0 };
|
||||||
|
|
||||||
@ -611,11 +614,18 @@ public:
|
|||||||
void post_event(wxEvent &&event);
|
void post_event(wxEvent &&event);
|
||||||
|
|
||||||
void set_as_dirty();
|
void set_as_dirty();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
void requires_check_outside_state() { m_requires_check_outside_state = true; }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
unsigned int get_volumes_count() const;
|
unsigned int get_volumes_count() const;
|
||||||
const GLVolumeCollection& get_volumes() const { return m_volumes; }
|
const GLVolumeCollection& get_volumes() const { return m_volumes; }
|
||||||
void reset_volumes();
|
void reset_volumes();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
ModelInstanceEPrintVolumeState check_volumes_outside_state(bool as_toolpaths = false) const;
|
||||||
|
#else
|
||||||
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
|
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
#if ENABLE_SEAMS_USING_MODELS
|
#if ENABLE_SEAMS_USING_MODELS
|
||||||
void init_gcode_viewer() { m_gcode_viewer.init(); }
|
void init_gcode_viewer() { m_gcode_viewer.init(); }
|
||||||
|
@ -61,10 +61,15 @@ std::pair<bool, std::string> GLShadersManager::init()
|
|||||||
// used to render extrusion and travel paths as lines in gcode preview
|
// used to render extrusion and travel paths as lines in gcode preview
|
||||||
valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" });
|
valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" });
|
||||||
// used to render objects in 3d editor
|
// used to render objects in 3d editor
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
// When setting this technology to default rename the following from "gouraud_mod" to "gouraud"
|
||||||
|
valid &= append_shader("gouraud_mod", { "gouraud_mod.vs", "gouraud_mod.fs" }
|
||||||
|
#else
|
||||||
valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" }
|
valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
#if ENABLE_ENVIRONMENT_MAP
|
#if ENABLE_ENVIRONMENT_MAP
|
||||||
, { "ENABLE_ENVIRONMENT_MAP"sv }
|
, { "ENABLE_ENVIRONMENT_MAP"sv }
|
||||||
#endif
|
#endif // ENABLE_ENVIRONMENT_MAP
|
||||||
);
|
);
|
||||||
// used to render variable layers heights in 3d editor
|
// used to render variable layers heights in 3d editor
|
||||||
valid &= append_shader("variable_layer_height", { "variable_layer_height.vs", "variable_layer_height.fs" });
|
valid &= append_shader("variable_layer_height", { "variable_layer_height.vs", "variable_layer_height.fs" });
|
||||||
|
@ -635,7 +635,6 @@ void ObjectManipulation::update_if_dirty()
|
|||||||
update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
|
update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (selection.requires_uniform_scale()) {
|
if (selection.requires_uniform_scale()) {
|
||||||
m_lock_bnt->SetLock(true);
|
m_lock_bnt->SetLock(true);
|
||||||
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
|
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
|
||||||
@ -658,8 +657,14 @@ void ObjectManipulation::update_if_dirty()
|
|||||||
else
|
else
|
||||||
m_og->disable();
|
m_og->disable();
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
if (!selection.is_dragging()) {
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
update_reset_buttons_visibility();
|
update_reset_buttons_visibility();
|
||||||
update_mirror_buttons_visibility();
|
update_mirror_buttons_visibility();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
}
|
}
|
||||||
|
@ -508,20 +508,23 @@ RENDER_AGAIN:
|
|||||||
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||||
|
|
||||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||||
|
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x,
|
||||||
|
m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(0.5f);
|
||||||
|
|
||||||
const float settings_sliders_left =
|
const float settings_sliders_left =
|
||||||
std::max({m_imgui->calc_text_size(m_desc.at("offset")).x,
|
std::max(std::max({m_imgui->calc_text_size(m_desc.at("offset")).x,
|
||||||
m_imgui->calc_text_size(m_desc.at("quality")).x,
|
m_imgui->calc_text_size(m_desc.at("quality")).x,
|
||||||
m_imgui->calc_text_size(m_desc.at("closing_distance")).x,
|
m_imgui->calc_text_size(m_desc.at("closing_distance")).x,
|
||||||
m_imgui->calc_text_size(m_desc.at("hole_diameter")).x,
|
m_imgui->calc_text_size(m_desc.at("hole_diameter")).x,
|
||||||
m_imgui->calc_text_size(m_desc.at("hole_depth")).x})
|
m_imgui->calc_text_size(m_desc.at("hole_depth")).x}) + m_imgui->scaled(0.5f), clipping_slider_left);
|
||||||
+ m_imgui->scaled(1.f);
|
|
||||||
|
|
||||||
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
|
|
||||||
const float diameter_slider_left = settings_sliders_left; //m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f);
|
const float diameter_slider_left = settings_sliders_left; //m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f);
|
||||||
const float minimal_slider_width = m_imgui->scaled(4.f);
|
const float minimal_slider_width = m_imgui->scaled(4.f);
|
||||||
|
|
||||||
|
const float button_preview_width = m_imgui->calc_button_size(m_desc.at("preview")).x;
|
||||||
|
|
||||||
float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left});
|
float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left});
|
||||||
window_width = std::max(window_width, m_imgui->calc_text_size(m_desc.at("preview")).x);
|
window_width = std::max(window_width, button_preview_width);
|
||||||
|
|
||||||
if (m_imgui->button(m_desc["preview"]))
|
if (m_imgui->button(m_desc["preview"]))
|
||||||
hollow_mesh();
|
hollow_mesh();
|
||||||
@ -544,9 +547,9 @@ RENDER_AGAIN:
|
|||||||
float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc.at("offset"));
|
m_imgui->text(m_desc.at("offset"));
|
||||||
ImGui::SameLine(settings_sliders_left);
|
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
||||||
ImGui::PushItemWidth(window_width - settings_sliders_left);
|
ImGui::PushItemWidth(window_width - settings_sliders_left);
|
||||||
m_imgui->slider_float(" ", &offset, offset_min, offset_max, "%.1f mm");
|
m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm");
|
||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width);
|
m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width);
|
||||||
|
|
||||||
@ -557,8 +560,8 @@ RENDER_AGAIN:
|
|||||||
if (current_mode >= quality_mode) {
|
if (current_mode >= quality_mode) {
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc.at("quality"));
|
m_imgui->text(m_desc.at("quality"));
|
||||||
ImGui::SameLine(settings_sliders_left);
|
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
||||||
m_imgui->slider_float(" ", &quality, quality_min, quality_max, "%.1f");
|
m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f");
|
||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width);
|
m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width);
|
||||||
|
|
||||||
@ -570,8 +573,8 @@ RENDER_AGAIN:
|
|||||||
if (current_mode >= closing_d_mode) {
|
if (current_mode >= closing_d_mode) {
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc.at("closing_distance"));
|
m_imgui->text(m_desc.at("closing_distance"));
|
||||||
ImGui::SameLine(settings_sliders_left);
|
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
||||||
m_imgui->slider_float(" ", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
|
m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
|
||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width);
|
m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width);
|
||||||
|
|
||||||
@ -614,11 +617,11 @@ RENDER_AGAIN:
|
|||||||
m_new_hole_radius = diameter_upper_cap / 2.f;
|
m_new_hole_radius = diameter_upper_cap / 2.f;
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc.at("hole_diameter"));
|
m_imgui->text(m_desc.at("hole_diameter"));
|
||||||
ImGui::SameLine(diameter_slider_left);
|
ImGui::SameLine(diameter_slider_left, m_imgui->get_item_spacing().x);
|
||||||
ImGui::PushItemWidth(window_width - diameter_slider_left);
|
ImGui::PushItemWidth(window_width - diameter_slider_left);
|
||||||
|
|
||||||
float diam = 2.f * m_new_hole_radius;
|
float diam = 2.f * m_new_hole_radius;
|
||||||
m_imgui->slider_float("", &diam, 1.f, 15.f, "%.1f mm", 1.f, false);
|
m_imgui->slider_float("##hole_diameter", &diam, 1.f, 15.f, "%.1f mm", 1.f, false);
|
||||||
// Let's clamp the value (which could have been entered by keyboard) to a larger range
|
// Let's clamp the value (which could have been entered by keyboard) to a larger range
|
||||||
// than the slider. This allows entering off-scale values and still protects against
|
// than the slider. This allows entering off-scale values and still protects against
|
||||||
//complete non-sense.
|
//complete non-sense.
|
||||||
@ -630,8 +633,8 @@ RENDER_AGAIN:
|
|||||||
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc["hole_depth"]);
|
m_imgui->text(m_desc["hole_depth"]);
|
||||||
ImGui::SameLine(diameter_slider_left);
|
ImGui::SameLine(diameter_slider_left, m_imgui->get_item_spacing().x);
|
||||||
m_imgui->slider_float(" ", &m_new_hole_height, 0.f, 10.f, "%.1f mm", 1.f, false);
|
m_imgui->slider_float("##hole_depth", &m_new_hole_height, 0.f, 10.f, "%.1f mm", 1.f, false);
|
||||||
// Same as above:
|
// Same as above:
|
||||||
m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f);
|
m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f);
|
||||||
|
|
||||||
@ -697,10 +700,10 @@ RENDER_AGAIN:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine(clipping_slider_left);
|
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
||||||
ImGui::PushItemWidth(window_width - clipping_slider_left);
|
ImGui::PushItemWidth(window_width - settings_sliders_left);
|
||||||
float clp_dist = m_c->object_clipper()->get_position();
|
float clp_dist = m_c->object_clipper()->get_position();
|
||||||
if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f"))
|
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
|
||||||
m_c->object_clipper()->set_position(clp_dist, true);
|
m_c->object_clipper()->set_position(clp_dist, true);
|
||||||
|
|
||||||
// make sure supports are shown/hidden as appropriate
|
// make sure supports are shown/hidden as appropriate
|
||||||
|
@ -66,12 +66,20 @@ GLGizmoPainterBase::ClippingPlaneDataWrapper GLGizmoPainterBase::get_clipping_pl
|
|||||||
|
|
||||||
void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
auto* shader = wxGetApp().get_shader("gouraud_mod");
|
||||||
|
#else
|
||||||
auto* shader = wxGetApp().get_shader("gouraud");
|
auto* shader = wxGetApp().get_shader("gouraud");
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
if (! shader)
|
if (! shader)
|
||||||
return;
|
return;
|
||||||
shader->start_using();
|
shader->start_using();
|
||||||
shader->set_uniform("slope.actived", false);
|
shader->set_uniform("slope.actived", false);
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
shader->set_uniform("print_volume.type", 0);
|
||||||
|
#else
|
||||||
shader->set_uniform("print_box.actived", false);
|
shader->set_uniform("print_box.actived", false);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
shader->set_uniform("clipping_plane", this->get_clipping_plane_data().clp_dataf);
|
shader->set_uniform("clipping_plane", this->get_clipping_plane_data().clp_dataf);
|
||||||
ScopeGuard guard([shader]() { if (shader) shader->stop_using(); });
|
ScopeGuard guard([shader]() { if (shader) shader->stop_using(); });
|
||||||
|
|
||||||
@ -98,7 +106,11 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
|||||||
// to the shader input variable print_box.volume_world_matrix before
|
// to the shader input variable print_box.volume_world_matrix before
|
||||||
// rendering the painted triangles. When this matrix is not set, the
|
// rendering the painted triangles. When this matrix is not set, the
|
||||||
// wrong transformation matrix is used for "Clipping of view".
|
// wrong transformation matrix is used for "Clipping of view".
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
shader->set_uniform("volume_world_matrix", trafo_matrix);
|
||||||
|
#else
|
||||||
shader->set_uniform("print_box.volume_world_matrix", trafo_matrix);
|
shader->set_uniform("print_box.volume_world_matrix", trafo_matrix);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
m_triangle_selectors[mesh_id]->render(m_imgui);
|
m_triangle_selectors[mesh_id]->render(m_imgui);
|
||||||
|
|
||||||
@ -575,7 +587,11 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
|
|||||||
auto* shader = wxGetApp().get_current_shader();
|
auto* shader = wxGetApp().get_current_shader();
|
||||||
if (! shader)
|
if (! shader)
|
||||||
return;
|
return;
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
assert(shader->get_name() == "gouraud_mod");
|
||||||
|
#else
|
||||||
assert(shader->get_name() == "gouraud");
|
assert(shader->get_name() == "gouraud");
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
ScopeGuard guard([shader]() { if (shader) shader->set_uniform("offset_depth_buffer", false);});
|
ScopeGuard guard([shader]() { if (shader) shader->set_uniform("offset_depth_buffer", false);});
|
||||||
shader->set_uniform("offset_depth_buffer", true);
|
shader->set_uniform("offset_depth_buffer", true);
|
||||||
for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color),
|
for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color),
|
||||||
|
@ -673,7 +673,7 @@ RENDER_AGAIN:
|
|||||||
// - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene
|
// - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene
|
||||||
// - take correct undo/redo snapshot after the user is done with moving the slider
|
// - take correct undo/redo snapshot after the user is done with moving the slider
|
||||||
float initial_value = m_new_point_head_diameter;
|
float initial_value = m_new_point_head_diameter;
|
||||||
m_imgui->slider_float("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f");
|
m_imgui->slider_float("##head_diameter", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f");
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
if (m_old_point_head_diameter == 0.f)
|
if (m_old_point_head_diameter == 0.f)
|
||||||
m_old_point_head_diameter = initial_value;
|
m_old_point_head_diameter = initial_value;
|
||||||
@ -733,7 +733,7 @@ RENDER_AGAIN:
|
|||||||
float density = static_cast<const ConfigOptionInt*>(opts[0])->value;
|
float density = static_cast<const ConfigOptionInt*>(opts[0])->value;
|
||||||
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
|
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
|
||||||
|
|
||||||
m_imgui->slider_float("", &minimal_point_distance, 0.f, 20.f, "%.f mm");
|
m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm");
|
||||||
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
|
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
|
||||||
bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
|
bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
|
||||||
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
|
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
|
||||||
@ -742,7 +742,7 @@ RENDER_AGAIN:
|
|||||||
m_imgui->text(m_desc.at("points_density"));
|
m_imgui->text(m_desc.at("points_density"));
|
||||||
ImGui::SameLine(settings_sliders_left);
|
ImGui::SameLine(settings_sliders_left);
|
||||||
|
|
||||||
m_imgui->slider_float(" ", &density, 0.f, 200.f, "%.f %%");
|
m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%");
|
||||||
slider_clicked |= ImGui::IsItemClicked();
|
slider_clicked |= ImGui::IsItemClicked();
|
||||||
slider_edited |= ImGui::IsItemEdited();
|
slider_edited |= ImGui::IsItemEdited();
|
||||||
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
|
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
|
||||||
@ -802,7 +802,7 @@ RENDER_AGAIN:
|
|||||||
ImGui::SameLine(clipping_slider_left);
|
ImGui::SameLine(clipping_slider_left);
|
||||||
ImGui::PushItemWidth(window_width - clipping_slider_left);
|
ImGui::PushItemWidth(window_width - clipping_slider_left);
|
||||||
float clp_dist = m_c->object_clipper()->get_position();
|
float clp_dist = m_c->object_clipper()->get_position();
|
||||||
if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f"))
|
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
|
||||||
m_c->object_clipper()->set_position(clp_dist, true);
|
m_c->object_clipper()->set_position(clp_dist, true);
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ void ImGuiWrapper::render()
|
|||||||
m_new_frame_open = false;
|
m_new_frame_open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, float wrap_width)
|
ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, float wrap_width) const
|
||||||
{
|
{
|
||||||
auto text_utf8 = into_u8(text);
|
auto text_utf8 = into_u8(text);
|
||||||
ImVec2 size = ImGui::CalcTextSize(text_utf8.c_str(), NULL, false, wrap_width);
|
ImVec2 size = ImGui::CalcTextSize(text_utf8.c_str(), NULL, false, wrap_width);
|
||||||
@ -293,6 +293,22 @@ ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, float wrap_width)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiWrapper::calc_button_size(const wxString &text, const ImVec2 &button_size) const
|
||||||
|
{
|
||||||
|
const ImVec2 text_size = this->calc_text_size(text);
|
||||||
|
const ImGuiContext &g = *GImGui;
|
||||||
|
const ImGuiStyle &style = g.Style;
|
||||||
|
|
||||||
|
return ImGui::CalcItemSize(button_size, text_size.x + style.FramePadding.x * 2.0f, text_size.y + style.FramePadding.y * 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 ImGuiWrapper::get_item_spacing() const
|
||||||
|
{
|
||||||
|
const ImGuiContext &g = *GImGui;
|
||||||
|
const ImGuiStyle &style = g.Style;
|
||||||
|
return g.Style.ItemSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
float ImGuiWrapper::get_slider_float_height() const
|
float ImGuiWrapper::get_slider_float_height() const
|
||||||
{
|
{
|
||||||
const ImGuiContext& g = *GImGui;
|
const ImGuiContext& g = *GImGui;
|
||||||
|
@ -53,8 +53,10 @@ public:
|
|||||||
|
|
||||||
float scaled(float x) const { return x * m_font_size; }
|
float scaled(float x) const { return x * m_font_size; }
|
||||||
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); }
|
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); }
|
||||||
ImVec2 calc_text_size(const wxString &text, float wrap_width = -1.0f);
|
ImVec2 calc_text_size(const wxString &text, float wrap_width = -1.0f) const;
|
||||||
|
ImVec2 calc_button_size(const wxString &text, const ImVec2 &button_size = ImVec2(0, 0)) const;
|
||||||
|
|
||||||
|
ImVec2 get_item_spacing() const;
|
||||||
float get_slider_float_height() const;
|
float get_slider_float_height() const;
|
||||||
|
|
||||||
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
|
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "libslic3r/SLAPrint.hpp"
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
|
||||||
#include "GUI.hpp"
|
#include "GUI.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
@ -3007,12 +3008,19 @@ void Plater::priv::schedule_background_process()
|
|||||||
|
|
||||||
void Plater::priv::update_print_volume_state()
|
void Plater::priv::update_print_volume_state()
|
||||||
{
|
{
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(this->config->option("bed_shape"));
|
||||||
|
const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast<float>(scale_(BedEpsilon))).front();
|
||||||
|
const float bed_height = this->config->opt_float("max_print_height");
|
||||||
|
this->q->model().update_print_volume_state(bed_poly, bed_height);
|
||||||
|
#else
|
||||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(this->config->opt<ConfigOptionPoints>("bed_shape")->values));
|
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(this->config->opt<ConfigOptionPoints>("bed_shape")->values));
|
||||||
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(this->config->opt_float("max_print_height"))));
|
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(this->config->opt_float("max_print_height"))));
|
||||||
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
||||||
print_volume.offset(BedEpsilon);
|
print_volume.offset(BedEpsilon);
|
||||||
print_volume.min(2) = -1e10;
|
print_volume.min(2) = -1e10;
|
||||||
this->q->model().update_print_volume_state(print_volume);
|
this->q->model().update_print_volume_state(print_volume);
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,6 +112,9 @@ Selection::Selection()
|
|||||||
, m_type(Empty)
|
, m_type(Empty)
|
||||||
, m_valid(false)
|
, m_valid(false)
|
||||||
, m_scale_factor(1.0f)
|
, m_scale_factor(1.0f)
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
, m_dragging(false)
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
{
|
{
|
||||||
this->set_bounding_boxes_dirty();
|
this->set_bounding_boxes_dirty();
|
||||||
}
|
}
|
||||||
@ -690,6 +693,10 @@ void Selection::start_dragging()
|
|||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
m_dragging = true;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
set_caches();
|
set_caches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,6 +737,9 @@ void Selection::translate(const Vec3d& displacement, bool local)
|
|||||||
|
|
||||||
ensure_not_below_bed();
|
ensure_not_below_bed();
|
||||||
set_bounding_boxes_dirty();
|
set_bounding_boxes_dirty();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
|
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
|
||||||
@ -842,7 +852,10 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
|||||||
volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new);
|
volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->set_bounding_boxes_dirty();
|
set_bounding_boxes_dirty();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection::flattening_rotate(const Vec3d& normal)
|
void Selection::flattening_rotate(const Vec3d& normal)
|
||||||
@ -941,6 +954,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
|
|||||||
|
|
||||||
ensure_on_bed();
|
ensure_on_bed();
|
||||||
set_bounding_boxes_dirty();
|
set_bounding_boxes_dirty();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
|
void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
|
||||||
@ -2140,10 +2156,10 @@ void Selection::ensure_not_below_bed()
|
|||||||
GLVolume* volume = (*m_volumes)[i];
|
GLVolume* volume = (*m_volumes)[i];
|
||||||
if (!volume->is_wipe_tower && !volume->is_modifier) {
|
if (!volume->is_wipe_tower && !volume->is_modifier) {
|
||||||
const double max_z = volume->transformed_convex_hull_bounding_box().max.z();
|
const double max_z = volume->transformed_convex_hull_bounding_box().max.z();
|
||||||
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
const std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
||||||
InstancesToZMap::iterator it = instances_max_z.find(instance);
|
InstancesToZMap::iterator it = instances_max_z.find(instance);
|
||||||
if (it == instances_max_z.end())
|
if (it == instances_max_z.end())
|
||||||
it = instances_max_z.insert(InstancesToZMap::value_type(instance, -DBL_MAX)).first;
|
it = instances_max_z.insert({ instance, -DBL_MAX }).first;
|
||||||
|
|
||||||
it->second = std::max(it->second, max_z);
|
it->second = std::max(it->second, max_z);
|
||||||
}
|
}
|
||||||
@ -2152,17 +2168,17 @@ void Selection::ensure_not_below_bed()
|
|||||||
if (is_any_volume()) {
|
if (is_any_volume()) {
|
||||||
for (unsigned int i : m_list) {
|
for (unsigned int i : m_list) {
|
||||||
GLVolume& volume = *(*m_volumes)[i];
|
GLVolume& volume = *(*m_volumes)[i];
|
||||||
std::pair<int, int> instance = std::make_pair(volume.object_idx(), volume.instance_idx());
|
const std::pair<int, int> instance = std::make_pair(volume.object_idx(), volume.instance_idx());
|
||||||
InstancesToZMap::iterator it = instances_max_z.find(instance);
|
InstancesToZMap::const_iterator it = instances_max_z.find(instance);
|
||||||
double z_shift = SINKING_MIN_Z_THRESHOLD - it->second;
|
const double z_shift = SINKING_MIN_Z_THRESHOLD - it->second;
|
||||||
if (it != instances_max_z.end() && z_shift > 0.0)
|
if (it != instances_max_z.end() && z_shift > 0.0)
|
||||||
volume.set_volume_offset(Z, volume.get_volume_offset(Z) + z_shift);
|
volume.set_volume_offset(Z, volume.get_volume_offset(Z) + z_shift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (GLVolume* volume : *m_volumes) {
|
for (GLVolume* volume : *m_volumes) {
|
||||||
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
const std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
||||||
InstancesToZMap::iterator it = instances_max_z.find(instance);
|
InstancesToZMap::const_iterator it = instances_max_z.find(instance);
|
||||||
if (it != instances_max_z.end() && it->second < SINKING_MIN_Z_THRESHOLD)
|
if (it != instances_max_z.end() && it->second < SINKING_MIN_Z_THRESHOLD)
|
||||||
volume->set_instance_offset(Z, volume->get_instance_offset(Z) + SINKING_MIN_Z_THRESHOLD - it->second);
|
volume->set_instance_offset(Z, volume->get_instance_offset(Z) + SINKING_MIN_Z_THRESHOLD - it->second);
|
||||||
}
|
}
|
||||||
|
@ -220,6 +220,10 @@ private:
|
|||||||
|
|
||||||
float m_scale_factor;
|
float m_scale_factor;
|
||||||
|
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
bool m_dragging;
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Selection();
|
Selection();
|
||||||
|
|
||||||
@ -312,6 +316,10 @@ public:
|
|||||||
const BoundingBoxf3& get_scaled_instance_bounding_box() const;
|
const BoundingBoxf3& get_scaled_instance_bounding_box() const;
|
||||||
|
|
||||||
void start_dragging();
|
void start_dragging();
|
||||||
|
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
void stop_dragging() { m_dragging = false; }
|
||||||
|
bool is_dragging() const { return m_dragging; }
|
||||||
|
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
|
||||||
|
|
||||||
void translate(const Vec3d& displacement, bool local = false);
|
void translate(const Vec3d& displacement, bool local = false);
|
||||||
void rotate(const Vec3d& rotation, TransformationType transformation_type);
|
void rotate(const Vec3d& rotation, TransformationType transformation_type);
|
||||||
|
Loading…
Reference in New Issue
Block a user