mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-03 10:50:36 +08:00
Merge branch 'master' into fs_dir_per_glyph_SPE-1597
This commit is contained in:
commit
006c1e6f56
1219
cmake/modules/FindwxWidgets.cmake
Normal file
1219
cmake/modules/FindwxWidgets.cmake
Normal file
File diff suppressed because it is too large
Load Diff
@ -49,26 +49,12 @@ if (SLIC3R_GUI)
|
|||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
||||||
find_package(wxWidgets 3.2 QUIET COMPONENTS base core adv html gl)
|
|
||||||
if (NOT wxWidgets_FOUND)
|
|
||||||
message(FATAL_ERROR "Could not find wxWidgets >= 3.2")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (NOT "${wxWidgets_USE_FILE}" STREQUAL "")
|
|
||||||
include(${wxWidgets_USE_FILE})
|
|
||||||
endif ()
|
|
||||||
else ()
|
|
||||||
find_package(wxWidgets 3.2 COMPONENTS html adv gl core base)
|
|
||||||
if (NOT wxWidgets_FOUND)
|
|
||||||
message(STATUS "Trying to find wxWidgets in CONFIG mode...")
|
|
||||||
find_package(wxWidgets 3.2 CONFIG REQUIRED COMPONENTS html adv gl core base)
|
|
||||||
slic3r_remap_configs(wx::wxhtml wx::wxadv wx::wxgl wx::wxcore wx::wxbase RelWithDebInfo Release)
|
|
||||||
else ()
|
|
||||||
if (NOT "${wxWidgets_USE_FILE}" STREQUAL "")
|
|
||||||
include(${wxWidgets_USE_FILE})
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
find_package(wxWidgets 3.2 MODULE REQUIRED COMPONENTS base core adv html gl)
|
||||||
|
|
||||||
|
include(${wxWidgets_USE_FILE})
|
||||||
|
|
||||||
|
slic3r_remap_configs(wx::wxhtml wx::wxadv wx::wxgl wx::wxcore wx::wxbase RelWithDebInfo Release)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#ifndef CSGMESH_HPP
|
#ifndef CSGMESH_HPP
|
||||||
#define CSGMESH_HPP
|
#define CSGMESH_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/Point.hpp"
|
||||||
|
|
||||||
#include <libslic3r/AnyPtr.hpp>
|
#include <libslic3r/AnyPtr.hpp>
|
||||||
#include <admesh/stl.h>
|
#include <libslic3r/TriangleMesh.hpp>
|
||||||
|
|
||||||
namespace Slic3r { namespace csg {
|
namespace Slic3r { namespace csg {
|
||||||
|
|
||||||
@ -81,6 +83,35 @@ struct CSGPart {
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class Cont> bool is_all_positive(const Cont &csgmesh)
|
||||||
|
{
|
||||||
|
bool is_all_pos =
|
||||||
|
std::all_of(csgmesh.begin(),
|
||||||
|
csgmesh.end(),
|
||||||
|
[](auto &part) {
|
||||||
|
return csg::get_operation(part) == csg::CSGType::Union;
|
||||||
|
});
|
||||||
|
|
||||||
|
return is_all_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Cont>
|
||||||
|
indexed_triangle_set csgmesh_merge_positive_parts(const Cont &csgmesh)
|
||||||
|
{
|
||||||
|
indexed_triangle_set m;
|
||||||
|
for (auto &csgpart : csgmesh) {
|
||||||
|
auto op = csg::get_operation(csgpart);
|
||||||
|
const indexed_triangle_set * pmesh = csg::get_mesh(csgpart);
|
||||||
|
if (pmesh && op == csg::CSGType::Union) {
|
||||||
|
indexed_triangle_set mcpy = *pmesh;
|
||||||
|
its_transform(mcpy, csg::get_transform(csgpart), true);
|
||||||
|
its_merge(m, mcpy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace Slic3r::csg
|
}} // namespace Slic3r::csg
|
||||||
|
|
||||||
#endif // CSGMESH_HPP
|
#endif // CSGMESH_HPP
|
||||||
|
@ -516,7 +516,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
|
WipeTower::WipeTower(const PrintConfig& config, const PrintRegionConfig& default_region_config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
|
||||||
m_semm(config.single_extruder_multi_material.value),
|
m_semm(config.single_extruder_multi_material.value),
|
||||||
m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y),
|
m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y),
|
||||||
m_wipe_tower_width(float(config.wipe_tower_width)),
|
m_wipe_tower_width(float(config.wipe_tower_width)),
|
||||||
@ -530,6 +530,8 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
|
|||||||
m_no_sparse_layers(config.wipe_tower_no_sparse_layers),
|
m_no_sparse_layers(config.wipe_tower_no_sparse_layers),
|
||||||
m_gcode_flavor(config.gcode_flavor),
|
m_gcode_flavor(config.gcode_flavor),
|
||||||
m_travel_speed(config.travel_speed),
|
m_travel_speed(config.travel_speed),
|
||||||
|
m_infill_speed(default_region_config.infill_speed),
|
||||||
|
m_perimeter_speed(default_region_config.perimeter_speed),
|
||||||
m_current_tool(initial_tool),
|
m_current_tool(initial_tool),
|
||||||
wipe_volumes(wiping_matrix)
|
wipe_volumes(wiping_matrix)
|
||||||
{
|
{
|
||||||
@ -541,6 +543,13 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
|
|||||||
if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it.
|
if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it.
|
||||||
m_first_layer_speed = default_speed / 2.f;
|
m_first_layer_speed = default_speed / 2.f;
|
||||||
|
|
||||||
|
// Autospeed may be used...
|
||||||
|
if (m_infill_speed == 0.f)
|
||||||
|
m_infill_speed = 80.f;
|
||||||
|
if (m_perimeter_speed == 0.f)
|
||||||
|
m_perimeter_speed = 80.f;
|
||||||
|
|
||||||
|
|
||||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||||
if (m_semm) {
|
if (m_semm) {
|
||||||
@ -1034,7 +1043,7 @@ void WipeTower::toolchange_Wipe(
|
|||||||
float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height);
|
float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height);
|
||||||
float dy = m_extra_spacing*m_perimeter_width;
|
float dy = m_extra_spacing*m_perimeter_width;
|
||||||
|
|
||||||
const float target_speed = is_first_layer() ? m_first_layer_speed * 60.f : 4800.f;
|
const float target_speed = is_first_layer() ? m_first_layer_speed * 60.f : m_infill_speed * 60.f;
|
||||||
float wipe_speed = 0.33f * target_speed;
|
float wipe_speed = 0.33f * target_speed;
|
||||||
|
|
||||||
// if there is less than 2.5*m_perimeter_width to the edge, advance straightaway (there is likely a blob anyway)
|
// if there is less than 2.5*m_perimeter_width to the edge, advance straightaway (there is likely a blob anyway)
|
||||||
@ -1103,7 +1112,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
|||||||
|
|
||||||
// Slow down on the 1st layer.
|
// Slow down on the 1st layer.
|
||||||
bool first_layer = is_first_layer();
|
bool first_layer = is_first_layer();
|
||||||
float feedrate = first_layer ? m_first_layer_speed * 60.f : 2900.f;
|
float feedrate = first_layer ? m_first_layer_speed * 60.f : m_infill_speed * 60.f;
|
||||||
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
|
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
|
||||||
box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
|
box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
|
||||||
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
||||||
@ -1203,7 +1212,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
|||||||
// First generate vector of annotated point which form the boundary.
|
// First generate vector of annotated point which form the boundary.
|
||||||
std::vector<std::pair<Vec2f, Type>> pts = {{wt_box.ru, Corner}};
|
std::vector<std::pair<Vec2f, Type>> pts = {{wt_box.ru, Corner}};
|
||||||
if (double alpha_start = std::asin((0.5*w)/r); ! std::isnan(alpha_start) && r > 0.5*w+0.01) {
|
if (double alpha_start = std::asin((0.5*w)/r); ! std::isnan(alpha_start) && r > 0.5*w+0.01) {
|
||||||
for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 20.)
|
for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 40.)
|
||||||
pts.emplace_back(Vec2f(center.x() + r*std::cos(alpha)/support_scale, center.y() + r*std::sin(alpha)), alpha == alpha_start ? ArcStart : Arc);
|
pts.emplace_back(Vec2f(center.x() + r*std::cos(alpha)/support_scale, center.y() + r*std::sin(alpha)), alpha == alpha_start ? ArcStart : Arc);
|
||||||
pts.back().second = ArcEnd;
|
pts.back().second = ArcEnd;
|
||||||
}
|
}
|
||||||
@ -1285,6 +1294,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
|||||||
return poly;
|
return poly;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
feedrate = first_layer ? m_first_layer_speed * 60.f : m_perimeter_speed * 60.f;
|
||||||
|
|
||||||
// outer contour (always)
|
// outer contour (always)
|
||||||
bool infill_cone = first_layer && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing;
|
bool infill_cone = first_layer && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing;
|
||||||
Polygon poly = supported_rectangle(wt_box, feedrate, infill_cone);
|
Polygon poly = supported_rectangle(wt_box, feedrate, infill_cone);
|
||||||
|
@ -14,6 +14,7 @@ namespace Slic3r
|
|||||||
|
|
||||||
class WipeTowerWriter;
|
class WipeTowerWriter;
|
||||||
class PrintConfig;
|
class PrintConfig;
|
||||||
|
class PrintRegionConfig;
|
||||||
enum GCodeFlavor : unsigned char;
|
enum GCodeFlavor : unsigned char;
|
||||||
|
|
||||||
|
|
||||||
@ -129,7 +130,10 @@ public:
|
|||||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||||
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
||||||
// wipe_area -- space available for one toolchange in mm
|
// wipe_area -- space available for one toolchange in mm
|
||||||
WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool);
|
WipeTower(const PrintConfig& config,
|
||||||
|
const PrintRegionConfig& default_region_config,
|
||||||
|
const std::vector<std::vector<float>>& wiping_matrix,
|
||||||
|
size_t initial_tool);
|
||||||
|
|
||||||
|
|
||||||
// Set the extruder properties.
|
// Set the extruder properties.
|
||||||
@ -269,6 +273,8 @@ private:
|
|||||||
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
|
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
|
||||||
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
|
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
|
||||||
float m_travel_speed = 0.f;
|
float m_travel_speed = 0.f;
|
||||||
|
float m_infill_speed = 0.f;
|
||||||
|
float m_perimeter_speed = 0.f;
|
||||||
float m_first_layer_speed = 0.f;
|
float m_first_layer_speed = 0.f;
|
||||||
size_t m_first_layer_idx = size_t(-1);
|
size_t m_first_layer_idx = size_t(-1);
|
||||||
|
|
||||||
|
@ -675,7 +675,9 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
|||||||
void PresetBundle::export_selections(AppConfig &config)
|
void PresetBundle::export_selections(AppConfig &config)
|
||||||
{
|
{
|
||||||
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() >= 1);
|
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() >= 1);
|
||||||
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() > 1 || filaments.get_selected_preset().alias == extruders_filaments.front().get_selected_preset()->alias);
|
// #ysFIXME_delete_after_test !All filament selections are always saved in extruder_filaments (for MM and SM printers),
|
||||||
|
// so there is no need to control a correspondence between filaments and extruders_filaments
|
||||||
|
//assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() > 1 || filaments.get_selected_preset().alias == extruders_filaments.front().get_selected_preset()->alias);
|
||||||
config.clear_section("presets");
|
config.clear_section("presets");
|
||||||
config.set("presets", "print", prints.get_selected_preset_name());
|
config.set("presets", "print", prints.get_selected_preset_name());
|
||||||
config.set("presets", "filament", extruders_filaments.front().get_selected_preset_name());
|
config.set("presets", "filament", extruders_filaments.front().get_selected_preset_name());
|
||||||
|
@ -1453,7 +1453,7 @@ void Print::_make_wipe_tower()
|
|||||||
this->throw_if_canceled();
|
this->throw_if_canceled();
|
||||||
|
|
||||||
// Initialize the wipe tower.
|
// Initialize the wipe tower.
|
||||||
WipeTower wipe_tower(m_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder());
|
WipeTower wipe_tower(m_config, m_default_region_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder());
|
||||||
|
|
||||||
//wipe_tower.set_retract();
|
//wipe_tower.set_retract();
|
||||||
//wipe_tower.set_zhop();
|
//wipe_tower.set_zhop();
|
||||||
|
@ -814,15 +814,15 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||||||
|| opt_key == "overhang_speed_2"
|
|| opt_key == "overhang_speed_2"
|
||||||
|| opt_key == "overhang_speed_3"
|
|| opt_key == "overhang_speed_3"
|
||||||
|| opt_key == "external_perimeter_speed"
|
|| opt_key == "external_perimeter_speed"
|
||||||
|| opt_key == "infill_speed"
|
|
||||||
|| opt_key == "perimeter_speed"
|
|
||||||
|| opt_key == "small_perimeter_speed"
|
|| opt_key == "small_perimeter_speed"
|
||||||
|| opt_key == "solid_infill_speed"
|
|| opt_key == "solid_infill_speed"
|
||||||
|| opt_key == "top_solid_infill_speed") {
|
|| opt_key == "top_solid_infill_speed") {
|
||||||
invalidated |= m_print->invalidate_step(psGCodeExport);
|
invalidated |= m_print->invalidate_step(psGCodeExport);
|
||||||
} else if (
|
} else if (
|
||||||
opt_key == "wipe_into_infill"
|
opt_key == "wipe_into_infill"
|
||||||
|| opt_key == "wipe_into_objects") {
|
|| opt_key == "wipe_into_objects"
|
||||||
|
|| opt_key == "infill_speed"
|
||||||
|
|| opt_key == "perimeter_speed") {
|
||||||
invalidated |= m_print->invalidate_step(psWipeTower);
|
invalidated |= m_print->invalidate_step(psWipeTower);
|
||||||
invalidated |= m_print->invalidate_step(psGCodeExport);
|
invalidated |= m_print->invalidate_step(psGCodeExport);
|
||||||
} else {
|
} else {
|
||||||
@ -1539,21 +1539,33 @@ void PrintObject::discover_vertical_shells()
|
|||||||
// Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions.
|
// Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions.
|
||||||
narrow_sparse_infill_region_radius - tiny_overlap_radius, ClipperLib::jtSquare);
|
narrow_sparse_infill_region_radius - tiny_overlap_radius, ClipperLib::jtSquare);
|
||||||
|
|
||||||
|
Polygons object_volume;
|
||||||
Polygons internal_volume;
|
Polygons internal_volume;
|
||||||
{
|
{
|
||||||
Polygons shrinked_bottom_slice = idx_layer > 0 ? to_polygons(m_layers[idx_layer - 1]->lslices) : Polygons{};
|
Polygons shrinked_bottom_slice = idx_layer > 0 ? to_polygons(m_layers[idx_layer - 1]->lslices) : Polygons{};
|
||||||
Polygons shrinked_upper_slice = (idx_layer + 1) < m_layers.size() ?
|
Polygons shrinked_upper_slice = (idx_layer + 1) < m_layers.size() ?
|
||||||
to_polygons(m_layers[idx_layer + 1]->lslices) :
|
to_polygons(m_layers[idx_layer + 1]->lslices) :
|
||||||
Polygons{};
|
Polygons{};
|
||||||
internal_volume = intersection(shrinked_bottom_slice, shrinked_upper_slice);
|
object_volume = intersection(shrinked_bottom_slice, shrinked_upper_slice);
|
||||||
|
internal_volume = closing(polygonsInternal, SCALED_EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The opening operation may cause scattered tiny drops on the smooth parts of the model, filter them out
|
// The regularization operation may cause scattered tiny drops on the smooth parts of the model, filter them out
|
||||||
|
// If the region checks both following conditions, it is removed:
|
||||||
|
// 1. the area is very small,
|
||||||
|
// OR the area is quite small and it is fully wrapped in model (not visible)
|
||||||
|
// the in-model condition is there due to small sloping surfaces, e.g. top of the hull of the benchy
|
||||||
|
// 2. the area does not fully cover an internal polygon
|
||||||
|
// This is there mainly for a very thin parts, where the solid layers would be missing if the part area is quite small
|
||||||
regularized_shell.erase(std::remove_if(regularized_shell.begin(), regularized_shell.end(),
|
regularized_shell.erase(std::remove_if(regularized_shell.begin(), regularized_shell.end(),
|
||||||
[&min_perimeter_infill_spacing, &internal_volume](const ExPolygon &p) {
|
[&internal_volume, &min_perimeter_infill_spacing,
|
||||||
return p.area() < min_perimeter_infill_spacing * scaled(1.5) ||
|
&object_volume](const ExPolygon &p) {
|
||||||
(p.area() < min_perimeter_infill_spacing * scaled(8.0) &&
|
return (p.area() < min_perimeter_infill_spacing * scaled(1.5) ||
|
||||||
diff(to_polygons(p), internal_volume).empty());
|
(p.area() < min_perimeter_infill_spacing * scaled(8.0) &&
|
||||||
|
diff(to_polygons(p), object_volume).empty())) &&
|
||||||
|
diff(internal_volume,
|
||||||
|
expand(to_polygons(p), min_perimeter_infill_spacing))
|
||||||
|
.size() >= internal_volume.size();
|
||||||
}),
|
}),
|
||||||
regularized_shell.end());
|
regularized_shell.end());
|
||||||
}
|
}
|
||||||
|
@ -127,35 +127,6 @@ void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Cont> bool is_all_positive(const Cont &csgmesh)
|
|
||||||
{
|
|
||||||
bool is_all_pos =
|
|
||||||
std::all_of(csgmesh.begin(),
|
|
||||||
csgmesh.end(),
|
|
||||||
[](auto &part) {
|
|
||||||
return csg::get_operation(part) == csg::CSGType::Union;
|
|
||||||
});
|
|
||||||
|
|
||||||
return is_all_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Cont>
|
|
||||||
static indexed_triangle_set csgmesh_merge_positive_parts(const Cont &csgmesh)
|
|
||||||
{
|
|
||||||
indexed_triangle_set m;
|
|
||||||
for (auto &csgpart : csgmesh) {
|
|
||||||
auto op = csg::get_operation(csgpart);
|
|
||||||
const indexed_triangle_set * pmesh = csg::get_mesh(csgpart);
|
|
||||||
if (pmesh && op == csg::CSGType::Union) {
|
|
||||||
indexed_triangle_set mcpy = *pmesh;
|
|
||||||
its_transform(mcpy, csg::get_transform(csgpart), true);
|
|
||||||
its_merge(m, mcpy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
indexed_triangle_set SLAPrint::Steps::generate_preview_vdb(
|
indexed_triangle_set SLAPrint::Steps::generate_preview_vdb(
|
||||||
SLAPrintObject &po, SLAPrintObjectStep step)
|
SLAPrintObject &po, SLAPrintObjectStep step)
|
||||||
{
|
{
|
||||||
|
@ -2757,6 +2757,11 @@ bool TickCodeInfo::add_tick(const int tick, Type type, const int extruder, doubl
|
|||||||
|
|
||||||
bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z)
|
bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z)
|
||||||
{
|
{
|
||||||
|
// Save previously value of the tick before the call a Dialog from get_... functions,
|
||||||
|
// otherwise a background process can change ticks values and current iterator wouldn't be valid for the moment of a Dialog close
|
||||||
|
// and PS will crash (see https://github.com/prusa3d/PrusaSlicer/issues/10941)
|
||||||
|
TickCode changed_tick = *it;
|
||||||
|
|
||||||
std::string edited_value;
|
std::string edited_value;
|
||||||
if (it->type == ColorChange)
|
if (it->type == ColorChange)
|
||||||
edited_value = get_new_color(it->color);
|
edited_value = get_new_color(it->color);
|
||||||
@ -2768,7 +2773,10 @@ bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z)
|
|||||||
if (edited_value.empty())
|
if (edited_value.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TickCode changed_tick = *it;
|
// Update iterator. For this moment its value can be invalid
|
||||||
|
if (it = ticks.find(changed_tick); it == ticks.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (it->type == ColorChange) {
|
if (it->type == ColorChange) {
|
||||||
if (it->color == edited_value)
|
if (it->color == edited_value)
|
||||||
return false;
|
return false;
|
||||||
|
@ -4067,7 +4067,7 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
|||||||
model_object->invalidate_bounding_box();
|
model_object->invalidate_bounding_box();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (v->is_wipe_tower)
|
else if (m_selection.is_wipe_tower() && v->is_wipe_tower)
|
||||||
// Move a wipe tower proxy.
|
// Move a wipe tower proxy.
|
||||||
wipe_tower_origin = v->get_volume_offset();
|
wipe_tower_origin = v->get_volume_offset();
|
||||||
}
|
}
|
||||||
|
@ -503,6 +503,11 @@ void ObjectManipulation::Show(const bool show)
|
|||||||
}
|
}
|
||||||
m_word_local_combo->Show(show_world_local_combo);
|
m_word_local_combo->Show(show_world_local_combo);
|
||||||
m_empty_str->Show(!show_world_local_combo);
|
m_empty_str->Show(!show_world_local_combo);
|
||||||
|
|
||||||
|
m_skew_label->Show(m_show_skew);
|
||||||
|
m_reset_skew_button->Show(m_show_skew);
|
||||||
|
|
||||||
|
m_parent->Layout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,15 +800,22 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
|||||||
m_mirror_warning_bitmap->SetBitmap(show_mirror ? m_manifold_warning_bmp.bmp() : wxNullBitmap);
|
m_mirror_warning_bitmap->SetBitmap(show_mirror ? m_manifold_warning_bmp.bmp() : wxNullBitmap);
|
||||||
m_mirror_warning_bitmap->SetMinSize(show_mirror ? m_manifold_warning_bmp.GetSize() : wxSize(0, 0));
|
m_mirror_warning_bitmap->SetMinSize(show_mirror ? m_manifold_warning_bmp.GetSize() : wxSize(0, 0));
|
||||||
m_mirror_warning_bitmap->SetToolTip(show_mirror ? _L("Left handed") : "");
|
m_mirror_warning_bitmap->SetToolTip(show_mirror ? _L("Left handed") : "");
|
||||||
m_reset_skew_button->Show(show_skew);
|
|
||||||
m_skew_label->Show(show_skew);
|
|
||||||
|
|
||||||
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
|
if (m_show_skew == show_skew)
|
||||||
Sidebar& panel = wxGetApp().sidebar();
|
get_sizer()->Layout();
|
||||||
if (!panel.IsFrozen()) {
|
else {
|
||||||
panel.Freeze();
|
// Call sidebar layout only if it's really needed,
|
||||||
panel.Layout();
|
// it means, when we show/hide additional line for skew information
|
||||||
panel.Thaw();
|
m_show_skew = show_skew;
|
||||||
|
m_reset_skew_button->Show(m_show_skew);
|
||||||
|
m_skew_label->Show(m_show_skew);
|
||||||
|
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
|
||||||
|
Sidebar& panel = wxGetApp().sidebar();
|
||||||
|
if (!panel.IsFrozen()) {
|
||||||
|
panel.Freeze();
|
||||||
|
panel.Layout();
|
||||||
|
panel.Thaw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,7 @@ private:
|
|||||||
bool m_is_enabled { true };
|
bool m_is_enabled { true };
|
||||||
bool m_is_enabled_size_and_scale { true };
|
bool m_is_enabled_size_and_scale { true };
|
||||||
|
|
||||||
|
bool m_show_skew { false };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ObjectManipulation(wxWindow* parent);
|
ObjectManipulation(wxWindow* parent);
|
||||||
|
@ -465,14 +465,17 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const
|
bool MeshRaycaster::intersects_line(Vec3d point, Vec3d direction, const Transform3d& trafo) const
|
||||||
{
|
{
|
||||||
point = trafo.inverse() * point;
|
Transform3d trafo_inv = trafo.inverse();
|
||||||
|
Vec3d to = trafo_inv * (point + direction);
|
||||||
|
point = trafo_inv * point;
|
||||||
|
direction = (to-point).normalized();
|
||||||
|
|
||||||
std::vector<AABBMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
std::vector<AABBMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
||||||
std::vector<AABBMesh::hit_result> neg_hits = m_emesh.query_ray_hits(point, -direction);
|
std::vector<AABBMesh::hit_result> neg_hits = m_emesh.query_ray_hits(point, -direction);
|
||||||
|
|
||||||
return !hits.empty() && !neg_hits.empty();
|
return !hits.empty() || !neg_hits.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,7 +187,9 @@ public:
|
|||||||
|
|
||||||
const AABBMesh &get_aabb_mesh() const { return m_emesh; }
|
const AABBMesh &get_aabb_mesh() const { return m_emesh; }
|
||||||
|
|
||||||
bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
|
// Given a point and direction in world coords, returns whether the respective line
|
||||||
|
// intersects the mesh if it is transformed into world by trafo.
|
||||||
|
bool intersects_line(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
|
||||||
|
|
||||||
// Given a vector of points in woorld coordinates, this returns vector
|
// Given a vector of points in woorld coordinates, this returns vector
|
||||||
// of indices of points that are visible (i.e. not cut by clipping plane
|
// of indices of points that are visible (i.e. not cut by clipping plane
|
||||||
|
@ -1276,9 +1276,11 @@ void Sidebar::show_info_sizer()
|
|||||||
{
|
{
|
||||||
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||||
ModelObjectPtrs objects = p->plater->model().objects;
|
ModelObjectPtrs objects = p->plater->model().objects;
|
||||||
int obj_idx = selection.get_object_idx();
|
const int obj_idx = selection.get_object_idx();
|
||||||
|
const int inst_idx = selection.get_instance_idx();
|
||||||
|
|
||||||
if (m_mode < comExpert || objects.empty() || obj_idx < 0 || int(objects.size()) <= obj_idx ||
|
if (m_mode < comExpert || objects.empty() || obj_idx < 0 || int(objects.size()) <= obj_idx ||
|
||||||
|
inst_idx < 0 || int(objects[obj_idx]->instances.size()) <= inst_idx ||
|
||||||
objects[obj_idx]->volumes.empty() || // hack to avoid crash when deleting the last object on the bed
|
objects[obj_idx]->volumes.empty() || // hack to avoid crash when deleting the last object on the bed
|
||||||
(selection.is_single_full_object() && objects[obj_idx]->instances.size()> 1) ||
|
(selection.is_single_full_object() && objects[obj_idx]->instances.size()> 1) ||
|
||||||
!(selection.is_single_full_instance() || selection.is_single_volume())) {
|
!(selection.is_single_full_instance() || selection.is_single_volume())) {
|
||||||
@ -1288,9 +1290,6 @@ void Sidebar::show_info_sizer()
|
|||||||
|
|
||||||
const ModelObject* model_object = objects[obj_idx];
|
const ModelObject* model_object = objects[obj_idx];
|
||||||
|
|
||||||
int inst_idx = selection.get_instance_idx();
|
|
||||||
assert(inst_idx >= 0);
|
|
||||||
|
|
||||||
bool imperial_units = wxGetApp().app_config->get_bool("use_inches");
|
bool imperial_units = wxGetApp().app_config->get_bool("use_inches");
|
||||||
double koef = imperial_units ? ObjectManipulation::mm_to_in : 1.0f;
|
double koef = imperial_units ? ObjectManipulation::mm_to_in : 1.0f;
|
||||||
|
|
||||||
@ -6471,9 +6470,12 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
|
|||||||
csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh),
|
csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh),
|
||||||
csg::mpartsPositive | csg::mpartsNegative | csg::mpartsDoSplits);
|
csg::mpartsPositive | csg::mpartsNegative | csg::mpartsDoSplits);
|
||||||
|
|
||||||
if (csg::check_csgmesh_booleans(range(csgmesh)) == csgmesh.end()) {
|
auto csgrange = range(csgmesh);
|
||||||
|
if (csg::is_all_positive(csgrange)) {
|
||||||
|
mesh = TriangleMesh{csg::csgmesh_merge_positive_parts(csgrange)};
|
||||||
|
} else if (csg::check_csgmesh_booleans(csgrange) == csgrange.end()) {
|
||||||
try {
|
try {
|
||||||
auto cgalm = csg::perform_csgmesh_booleans(range(csgmesh));
|
auto cgalm = csg::perform_csgmesh_booleans(csgrange);
|
||||||
mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*cgalm);
|
mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*cgalm);
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
}
|
}
|
||||||
@ -7130,7 +7132,9 @@ void Plater::force_filament_cb_update()
|
|||||||
|
|
||||||
// Update preset comboboxes on sidebar and filaments tab
|
// Update preset comboboxes on sidebar and filaments tab
|
||||||
p->sidebar->update_presets(Preset::TYPE_FILAMENT);
|
p->sidebar->update_presets(Preset::TYPE_FILAMENT);
|
||||||
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filaments.get_selected_preset_name());
|
|
||||||
|
TabFilament* tab = dynamic_cast<TabFilament*>(wxGetApp().get_tab(Preset::TYPE_FILAMENT));
|
||||||
|
tab->select_preset(wxGetApp().preset_bundle->extruders_filaments[tab->get_active_extruder()].get_selected_preset_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::force_print_bed_update()
|
void Plater::force_print_bed_update()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user