mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 18:21:18 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_3dconnexion
This commit is contained in:
commit
599403ba94
18 changed files with 628 additions and 295 deletions
|
|
@ -184,10 +184,21 @@ extern void stl_mirror_xz(stl_file *stl);
|
|||
|
||||
extern void stl_get_size(stl_file *stl);
|
||||
|
||||
// the following function is not used
|
||||
/*
|
||||
template<typename T>
|
||||
extern void stl_transform(stl_file *stl, T *trafo3x4)
|
||||
{
|
||||
for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
|
||||
Eigen::Matrix<T, 3, 3, Eigen::DontAlign> trafo3x3;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
trafo3x3(i, j) = (i * 4) + j;
|
||||
}
|
||||
}
|
||||
Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = trafo3x3.inverse().transpose();
|
||||
for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
|
||||
stl_facet &face = stl->facet_start[i_face];
|
||||
for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
|
||||
stl_vertex &v_dst = face.vertex[i_vertex];
|
||||
|
|
@ -196,21 +207,18 @@ extern void stl_transform(stl_file *stl, T *trafo3x4)
|
|||
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
|
||||
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
|
||||
}
|
||||
stl_vertex &v_dst = face.normal;
|
||||
stl_vertex v_src = v_dst;
|
||||
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2));
|
||||
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2));
|
||||
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2));
|
||||
}
|
||||
face.normal = (r * face.normal.template cast<T>()).template cast<float>().eval();
|
||||
}
|
||||
|
||||
stl_get_size(stl);
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
|
||||
{
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
const Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0).inverse().transpose();
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
stl_facet &f = stl->facet_start[i];
|
||||
for (size_t j = 0; j < 3; ++j)
|
||||
f.vertex[j] = (t * f.vertex[j].template cast<T>()).template cast<float>().eval();
|
||||
|
|
@ -223,12 +231,13 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Aff
|
|||
template<typename T>
|
||||
inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
|
||||
{
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
const Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = m.inverse().transpose();
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
stl_facet &f = stl->facet_start[i];
|
||||
for (size_t j = 0; j < 3; ++j)
|
||||
f.vertex[j] = (m * f.vertex[j].template cast<T>()).template cast<float>().eval();
|
||||
f.normal = (m * f.normal.template cast<T>()).template cast<float>().eval();
|
||||
}
|
||||
f.normal = (r * f.normal.template cast<T>()).template cast<float>().eval();
|
||||
}
|
||||
|
||||
stl_get_size(stl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@
|
|||
#include "Geometry.hpp"
|
||||
#include "GCode/PrintExtents.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "ShortestPath.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
|
|
@ -695,7 +692,7 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
|||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, const std::vector<ThumbnailData>* thumbnail_data)
|
||||
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -725,7 +722,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||
try {
|
||||
m_placeholder_parser_failed_templates.clear();
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
this->_do_export(*print, file, thumbnail_data);
|
||||
this->_do_export(*print, file, thumbnail_cb);
|
||||
#else
|
||||
this->_do_export(*print, file);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -793,9 +790,9 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void GCode::_do_export(Print& print, FILE* file, const std::vector<ThumbnailData>* thumbnail_data)
|
||||
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
void GCode::_do_export(Print &print, FILE *file)
|
||||
void GCode::_do_export(Print& print, FILE* file)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
|
@ -812,46 +809,46 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
// shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
|
||||
if (print.config().gcode_flavor.value == gcfMarlin) {
|
||||
m_normal_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[0]);
|
||||
m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]);
|
||||
m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]);
|
||||
m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]);
|
||||
m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]);
|
||||
m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]);
|
||||
m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]);
|
||||
|
||||
if (m_silent_time_estimator_enabled)
|
||||
{
|
||||
m_silent_time_estimator.reset();
|
||||
m_silent_time_estimator.set_dialect(print.config().gcode_flavor);
|
||||
/* "Stealth mode" values can be just a copy of "normal mode" values
|
||||
/* "Stealth mode" values can be just a copy of "normal mode" values
|
||||
* (when they aren't input for a printer preset).
|
||||
* Thus, use back value from values, instead of second one, which could be absent
|
||||
*/
|
||||
m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back());
|
||||
m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back());
|
||||
m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back());
|
||||
m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back());
|
||||
m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back());
|
||||
m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back());
|
||||
m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back());
|
||||
m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back());
|
||||
if (print.config().single_extruder_multi_material) {
|
||||
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
|
||||
// are considered to be active for the single extruder multi-material printers only.
|
||||
|
|
@ -909,7 +906,8 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
std::sort(zs.begin(), zs.end());
|
||||
m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin()));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Print all objects with the same print_z together.
|
||||
std::vector<coordf_t> zs;
|
||||
for (auto object : print.objects()) {
|
||||
|
|
@ -927,7 +925,7 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
m_enable_cooling_markers = true;
|
||||
this->apply_print_config(print.config());
|
||||
this->set_extruders(print.extruders());
|
||||
|
||||
|
||||
// Initialize colorprint.
|
||||
m_colorprint_heights = cast<float>(print.config().colorprint_heights.values);
|
||||
|
||||
|
|
@ -936,31 +934,31 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
// get the minimum cross-section used in the print
|
||||
std::vector<double> mm3_per_mm;
|
||||
for (auto object : print.objects()) {
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++region_id) {
|
||||
const PrintRegion* region = print.regions()[region_id];
|
||||
for (auto layer : object->layers()) {
|
||||
const LayerRegion* layerm = layer->regions()[region_id];
|
||||
if (region->config().get_abs_value("perimeter_speed" ) == 0 ||
|
||||
region->config().get_abs_value("small_perimeter_speed" ) == 0 ||
|
||||
region->config().get_abs_value("external_perimeter_speed" ) == 0 ||
|
||||
region->config().get_abs_value("bridge_speed" ) == 0)
|
||||
if (region->config().get_abs_value("perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("small_perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("external_perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("bridge_speed") == 0)
|
||||
mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
|
||||
if (region->config().get_abs_value("infill_speed" ) == 0 ||
|
||||
region->config().get_abs_value("solid_infill_speed" ) == 0 ||
|
||||
region->config().get_abs_value("top_solid_infill_speed" ) == 0 ||
|
||||
region->config().get_abs_value("bridge_speed" ) == 0)
|
||||
if (region->config().get_abs_value("infill_speed") == 0 ||
|
||||
region->config().get_abs_value("solid_infill_speed") == 0 ||
|
||||
region->config().get_abs_value("top_solid_infill_speed") == 0 ||
|
||||
region->config().get_abs_value("bridge_speed") == 0)
|
||||
mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm());
|
||||
}
|
||||
}
|
||||
if (object->config().get_abs_value("support_material_speed" ) == 0 ||
|
||||
object->config().get_abs_value("support_material_interface_speed" ) == 0)
|
||||
if (object->config().get_abs_value("support_material_speed") == 0 ||
|
||||
object->config().get_abs_value("support_material_interface_speed") == 0)
|
||||
for (auto layer : object->support_layers())
|
||||
mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
// filter out 0-width segments
|
||||
mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end());
|
||||
if (! mm3_per_mm.empty()) {
|
||||
if (!mm3_per_mm.empty()) {
|
||||
// In order to honor max_print_speed we need to find a target volumetric
|
||||
// speed that we can use throughout the print. So we define this target
|
||||
// volumetric speed as the volumetric speed produced by printing the
|
||||
|
|
@ -973,7 +971,7 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
}
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
|
||||
|
||||
m_cooling_buffer = make_unique<CoolingBuffer>(*this);
|
||||
if (print.config().spiral_vase.value)
|
||||
m_spiral_vase = make_unique<SpiralVase>(print.config());
|
||||
|
|
@ -991,11 +989,12 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
// Write thumbnails using base64 encoding
|
||||
if (thumbnail_data != nullptr)
|
||||
if (thumbnail_cb != nullptr)
|
||||
{
|
||||
const size_t max_row_length = 78;
|
||||
|
||||
for (const ThumbnailData& data : *thumbnail_data)
|
||||
ThumbnailsList thumbnails;
|
||||
thumbnail_cb(thumbnails, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, false);
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
{
|
||||
if (data.is_valid())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
#include "GCodeTimeEstimator.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "GCode/Analyzer.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
@ -30,9 +33,6 @@ namespace Slic3r {
|
|||
// Forward declarations.
|
||||
class GCode;
|
||||
class GCodePreviewData;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
struct ThumbnailData;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
class AvoidCrossingPerimeters {
|
||||
public:
|
||||
|
|
@ -167,7 +167,7 @@ public:
|
|||
// throws std::runtime_exception on error,
|
||||
// throws CanceledException through print->throw_if_canceled().
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, const std::vector<ThumbnailData>* thumbnail_data = nullptr);
|
||||
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -199,7 +199,7 @@ public:
|
|||
|
||||
protected:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void _do_export(Print& print, FILE* file, const std::vector<ThumbnailData>* thumbnail_data);
|
||||
void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
#else
|
||||
void _do_export(Print &print, FILE *file);
|
||||
#endif //ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <vector>
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
@ -20,6 +21,9 @@ struct ThumbnailData
|
|||
bool is_valid() const;
|
||||
};
|
||||
|
||||
typedef std::vector<ThumbnailData> ThumbnailsList;
|
||||
typedef std::function<void(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background)> ThumbnailsGeneratorCallback;
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
|
|||
|
|
@ -1538,7 +1538,7 @@ void Print::process()
|
|||
// write error into the G-code, cannot execute post-processing scripts).
|
||||
// It is up to the caller to show an error message.
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector<ThumbnailData>* thumbnail_data)
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -1559,7 +1559,7 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa
|
|||
// The following line may die for multiple reasons.
|
||||
GCode gcode;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
gcode.do_export(this, path.c_str(), preview_data, thumbnail_data);
|
||||
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
|
||||
#else
|
||||
gcode.do_export(this, path.c_str(), preview_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
#include "Slicing.hpp"
|
||||
#include "GCode/ToolOrdering.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
@ -19,9 +22,6 @@ class PrintObject;
|
|||
class ModelObject;
|
||||
class GCode;
|
||||
class GCodePreviewData;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
struct ThumbnailData;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Print step IDs for keeping track of the print state.
|
||||
enum PrintStep {
|
||||
|
|
@ -311,7 +311,7 @@ public:
|
|||
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
|
||||
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector<ThumbnailData>* thumbnail_data = nullptr);
|
||||
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
|
|||
|
|
@ -1522,9 +1522,9 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
|
|||
layer_height_profile.clear();
|
||||
|
||||
if (layer_height_profile.empty()) {
|
||||
//layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);
|
||||
updated = true;
|
||||
//layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);
|
||||
updated = true;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,40 +224,59 @@ std::vector<coordf_t> layer_height_profile_from_ranges(
|
|||
|
||||
// Based on the work of @platsch
|
||||
// Fill layer_height_profile by heights ensuring a prescribed maximum cusp height.
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slicing_params,
|
||||
const ModelObject& object, float cusp_value)
|
||||
#else
|
||||
std::vector<coordf_t> layer_height_profile_adaptive(
|
||||
const SlicingParameters &slicing_params,
|
||||
const t_layer_config_ranges & /* layer_config_ranges */,
|
||||
const ModelVolumePtrs &volumes)
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
{
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// 1) Initialize the SlicingAdaptive class with the object meshes.
|
||||
SlicingAdaptive as;
|
||||
as.set_slicing_parameters(slicing_params);
|
||||
for (const ModelVolume *volume : volumes)
|
||||
as.set_object(object);
|
||||
#else
|
||||
// 1) Initialize the SlicingAdaptive class with the object meshes.
|
||||
SlicingAdaptive as;
|
||||
as.set_slicing_parameters(slicing_params);
|
||||
for (const ModelVolume* volume : volumes)
|
||||
if (volume->is_model_part())
|
||||
as.add_mesh(&volume->mesh());
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
as.prepare();
|
||||
|
||||
// 2) Generate layers using the algorithm of @platsch
|
||||
// loop until we have at least one layer and the max slice_z reaches the object height
|
||||
//FIXME make it configurable
|
||||
// Cusp value: A maximum allowed distance from a corner of a rectangular extrusion to a chrodal line, in mm.
|
||||
const coordf_t cusp_value = 0.2; // $self->config->get_value('cusp_value');
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
double cusp_value = 0.2;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
layer_height_profile.push_back(0.);
|
||||
std::vector<double> layer_height_profile;
|
||||
layer_height_profile.push_back(0.0);
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
if (slicing_params.first_object_layer_height_fixed()) {
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
}
|
||||
coordf_t slice_z = slicing_params.first_object_layer_height;
|
||||
coordf_t height = slicing_params.first_object_layer_height;
|
||||
double slice_z = slicing_params.first_object_layer_height;
|
||||
int current_facet = 0;
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
while (slice_z <= slicing_params.object_print_z_height()) {
|
||||
double height = 999.0;
|
||||
#else
|
||||
double height = slicing_params.first_object_layer_height;
|
||||
while ((slice_z - height) <= slicing_params.object_print_z_height()) {
|
||||
height = 999;
|
||||
height = 999.0;
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// Slic3r::debugf "\n Slice layer: %d\n", $id;
|
||||
// determine next layer height
|
||||
coordf_t cusp_height = as.cusp_height(slice_z, cusp_value, current_facet);
|
||||
double cusp_height = as.cusp_height((float)slice_z, cusp_value, current_facet);
|
||||
|
||||
// check for horizontal features and object size
|
||||
/*
|
||||
if($self->config->get_value('match_horizontal_surfaces')) {
|
||||
|
|
@ -303,19 +322,113 @@ std::vector<coordf_t> layer_height_profile_adaptive(
|
|||
layer_height_profile.push_back(slice_z);
|
||||
layer_height_profile.push_back(height);
|
||||
slice_z += height;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
layer_height_profile.push_back(slice_z);
|
||||
layer_height_profile.push_back(height);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
}
|
||||
|
||||
coordf_t last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
double z_gap = slicing_params.object_print_z_height() - layer_height_profile[layer_height_profile.size() - 2];
|
||||
if (z_gap > 0.0)
|
||||
{
|
||||
layer_height_profile.push_back(slicing_params.object_print_z_height());
|
||||
layer_height_profile.push_back(clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, z_gap));
|
||||
}
|
||||
#else
|
||||
double last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]);
|
||||
layer_height_profile.push_back(last);
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
layer_height_profile.push_back(slicing_params.object_print_z_height());
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
return layer_height_profile;
|
||||
}
|
||||
|
||||
std::vector<double> smooth_height_profile(const std::vector<double>& profile, const SlicingParameters& slicing_params, const HeightProfileSmoothingParams& smoothing_params)
|
||||
{
|
||||
auto gauss_blur = [&slicing_params](const std::vector<double>& profile, const HeightProfileSmoothingParams& smoothing_params) -> std::vector<double> {
|
||||
auto gauss_kernel = [] (unsigned int radius) -> std::vector<double> {
|
||||
unsigned int size = 2 * radius + 1;
|
||||
std::vector<double> ret;
|
||||
ret.reserve(size);
|
||||
|
||||
// Reworked from static inline int getGaussianKernelSize(float sigma) taken from opencv-4.1.2\modules\features2d\src\kaze\AKAZEFeatures.cpp
|
||||
double sigma = 0.3 * (double)(radius - 1) + 0.8;
|
||||
double two_sq_sigma = 2.0 * sigma * sigma;
|
||||
double inv_root_two_pi_sq_sigma = 1.0 / ::sqrt(M_PI * two_sq_sigma);
|
||||
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
{
|
||||
double x = (double)i - (double)radius;
|
||||
ret.push_back(inv_root_two_pi_sq_sigma * ::exp(-x * x / two_sq_sigma));
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
// skip first layer ?
|
||||
size_t skip_count = slicing_params.first_object_layer_height_fixed() ? 4 : 0;
|
||||
|
||||
// not enough data to smmoth
|
||||
if ((int)profile.size() - (int)skip_count < 6)
|
||||
return profile;
|
||||
|
||||
unsigned int radius = std::max(smoothing_params.radius, (unsigned int)1);
|
||||
std::vector<double> kernel = gauss_kernel(radius);
|
||||
int two_radius = 2 * (int)radius;
|
||||
|
||||
std::vector<double> ret;
|
||||
size_t size = profile.size();
|
||||
ret.reserve(size);
|
||||
|
||||
// leave first layer untouched
|
||||
for (size_t i = 0; i < skip_count; ++i)
|
||||
{
|
||||
ret.push_back(profile[i]);
|
||||
}
|
||||
|
||||
// smooth the rest of the profile by biasing a gaussian blur
|
||||
// the bias moves the smoothed profile closer to the min_layer_height
|
||||
double delta_h = slicing_params.max_layer_height - slicing_params.min_layer_height;
|
||||
double inv_delta_h = (delta_h != 0.0) ? 1.0 / delta_h : 1.0;
|
||||
|
||||
double max_dz_band = (double)radius * slicing_params.layer_height;
|
||||
for (size_t i = skip_count; i < size; i += 2)
|
||||
{
|
||||
double zi = profile[i];
|
||||
double hi = profile[i + 1];
|
||||
ret.push_back(zi);
|
||||
ret.push_back(0.0);
|
||||
double& height = ret.back();
|
||||
int begin = std::max((int)i - two_radius, (int)skip_count);
|
||||
int end = std::min((int)i + two_radius, (int)size - 2);
|
||||
double weight_total = 0.0;
|
||||
for (int j = begin; j <= end; j += 2)
|
||||
{
|
||||
int kernel_id = radius + (j - (int)i) / 2;
|
||||
double dz = std::abs(zi - profile[j]);
|
||||
if (dz * slicing_params.layer_height <= max_dz_band)
|
||||
{
|
||||
double dh = std::abs(slicing_params.max_layer_height - profile[j + 1]);
|
||||
double weight = kernel[kernel_id] * sqrt(dh * inv_delta_h);
|
||||
height += weight * profile[j + 1];
|
||||
weight_total += weight;
|
||||
}
|
||||
}
|
||||
|
||||
height = clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, (weight_total != 0.0) ? height /= weight_total : hi);
|
||||
if (smoothing_params.keep_min)
|
||||
height = std::min(height, hi);
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
return gauss_blur(profile, smoothing_params);
|
||||
}
|
||||
|
||||
void adjust_layer_height_profile(
|
||||
const SlicingParameters &slicing_params,
|
||||
std::vector<coordf_t> &layer_height_profile,
|
||||
|
|
@ -609,7 +722,11 @@ int generate_layer_height_texture(
|
|||
const Vec3crd &color1 = palette_raw[idx1];
|
||||
const Vec3crd &color2 = palette_raw[idx2];
|
||||
coordf_t z = cell_to_z * coordf_t(cell);
|
||||
assert(z >= lo && z <= hi);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
assert((lo - EPSILON <= z) && (z <= hi + EPSILON));
|
||||
#else
|
||||
assert(z >= lo && z <= hi);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// Intensity profile to visualize the layers.
|
||||
coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h);
|
||||
// Color mapping from layer height to RGB.
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@ namespace Slic3r
|
|||
|
||||
class PrintConfig;
|
||||
class PrintObjectConfig;
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
class ModelObject;
|
||||
#else
|
||||
class ModelVolume;
|
||||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
// Parameters to guide object slicing and support generation.
|
||||
// The slicing parameters account for a raft and whether the 1st object layer is printed with a normal or a bridging flow
|
||||
|
|
@ -138,11 +142,29 @@ extern std::vector<coordf_t> layer_height_profile_from_ranges(
|
|||
const SlicingParameters &slicing_params,
|
||||
const t_layer_config_ranges &layer_config_ranges);
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
extern std::vector<double> layer_height_profile_adaptive(
|
||||
const SlicingParameters& slicing_params,
|
||||
const ModelObject& object, float cusp_value);
|
||||
|
||||
struct HeightProfileSmoothingParams
|
||||
{
|
||||
unsigned int radius;
|
||||
bool keep_min;
|
||||
|
||||
HeightProfileSmoothingParams() : radius(5), keep_min(false) {}
|
||||
HeightProfileSmoothingParams(unsigned int radius, bool keep_min) : radius(radius), keep_min(keep_min) {}
|
||||
};
|
||||
|
||||
extern std::vector<double> smooth_height_profile(
|
||||
const std::vector<double>& profile, const SlicingParameters& slicing_params,
|
||||
const HeightProfileSmoothingParams& smoothing_params);
|
||||
#else
|
||||
extern std::vector<coordf_t> layer_height_profile_adaptive(
|
||||
const SlicingParameters &slicing_params,
|
||||
const t_layer_config_ranges &layer_config_ranges,
|
||||
const ModelVolumePtrs &volumes);
|
||||
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
enum LayerHeightEditActionType : unsigned int {
|
||||
LAYER_HEIGHT_EDIT_ACTION_INCREASE = 0,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
#include "libslic3r.h"
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
#include "Model.hpp"
|
||||
#else
|
||||
#include "TriangleMesh.hpp"
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
#include "SlicingAdaptive.hpp"
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void SlicingAdaptive::clear()
|
||||
{
|
||||
m_meshes.clear();
|
||||
m_meshes.clear();
|
||||
m_faces.clear();
|
||||
m_face_normal_z.clear();
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
std::pair<float, float> face_z_span(const stl_facet *f)
|
||||
{
|
||||
|
|
@ -21,21 +27,42 @@ std::pair<float, float> face_z_span(const stl_facet *f)
|
|||
|
||||
void SlicingAdaptive::prepare()
|
||||
{
|
||||
// 1) Collect faces of all meshes.
|
||||
int nfaces_total = 0;
|
||||
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
if (m_object == nullptr)
|
||||
return;
|
||||
|
||||
m_faces.clear();
|
||||
m_face_normal_z.clear();
|
||||
|
||||
m_mesh = m_object->raw_mesh();
|
||||
const ModelInstance* first_instance = m_object->instances.front();
|
||||
m_mesh.transform(first_instance->get_matrix(), first_instance->is_left_handed());
|
||||
for (stl_facet& facet : m_mesh.stl.facet_start)
|
||||
{
|
||||
facet.normal.normalize();
|
||||
}
|
||||
|
||||
// 1) Collect faces from mesh.
|
||||
m_faces.reserve(m_mesh.stl.stats.number_of_facets);
|
||||
for (const stl_facet& face : m_mesh.stl.facet_start)
|
||||
m_faces.emplace_back(&face);
|
||||
#else
|
||||
// 1) Collect faces of all meshes.
|
||||
int nfaces_total = 0;
|
||||
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
||||
nfaces_total += (*it_mesh)->stl.stats.number_of_facets;
|
||||
m_faces.reserve(nfaces_total);
|
||||
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
||||
for (const stl_facet &face : (*it_mesh)->stl.facet_start)
|
||||
m_faces.emplace_back(&face);
|
||||
m_faces.reserve(nfaces_total);
|
||||
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
||||
for (const stl_facet& face : (*it_mesh)->stl.facet_start)
|
||||
m_faces.emplace_back(&face);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
// 2) Sort faces lexicographically by their Z span.
|
||||
std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) {
|
||||
std::pair<float, float> span1 = face_z_span(f1);
|
||||
std::pair<float, float> span1 = face_z_span(f1);
|
||||
std::pair<float, float> span2 = face_z_span(f2);
|
||||
return span1 < span2;
|
||||
});
|
||||
return span1 < span2;
|
||||
});
|
||||
|
||||
// 3) Generate Z components of the facet normals.
|
||||
m_face_normal_z.assign(m_faces.size(), 0.f);
|
||||
|
|
@ -45,14 +72,14 @@ void SlicingAdaptive::prepare()
|
|||
|
||||
float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet)
|
||||
{
|
||||
float height = m_slicing_params.max_layer_height;
|
||||
float height = (float)m_slicing_params.max_layer_height;
|
||||
bool first_hit = false;
|
||||
|
||||
// find all facets intersecting the slice-layer
|
||||
int ordered_id = current_facet;
|
||||
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
|
||||
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
||||
// facet's minimum is higher than slice_z -> end loop
|
||||
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
||||
// facet's minimum is higher than slice_z -> end loop
|
||||
if (zspan.first >= z)
|
||||
break;
|
||||
// facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point
|
||||
|
|
@ -77,8 +104,8 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet
|
|||
// check for sloped facets inside the determined layer and correct height if necessary
|
||||
if (height > m_slicing_params.min_layer_height) {
|
||||
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
|
||||
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
||||
// facet's minimum is higher than slice_z + height -> end loop
|
||||
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
||||
// facet's minimum is higher than slice_z + height -> end loop
|
||||
if (zspan.first >= z + height)
|
||||
break;
|
||||
|
||||
|
|
@ -117,24 +144,25 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet
|
|||
return height;
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// Returns the distance to the next horizontal facet in Z-dir
|
||||
// to consider horizontal object features in slice thickness
|
||||
float SlicingAdaptive::horizontal_facet_distance(float z)
|
||||
{
|
||||
for (size_t i = 0; i < m_faces.size(); ++ i) {
|
||||
std::pair<float, float> zspan = face_z_span(m_faces[i]);
|
||||
// facet's minimum is higher than max forward distance -> end loop
|
||||
std::pair<float, float> zspan = face_z_span(m_faces[i]);
|
||||
// facet's minimum is higher than max forward distance -> end loop
|
||||
if (zspan.first > z + m_slicing_params.max_layer_height)
|
||||
break;
|
||||
// min_z == max_z -> horizontal facet
|
||||
if (zspan.first > z && zspan.first == zspan.second)
|
||||
if ((zspan.first > z) && (zspan.first == zspan.second))
|
||||
return zspan.first - z;
|
||||
}
|
||||
|
||||
// objects maximum?
|
||||
return (z + m_slicing_params.max_layer_height > m_slicing_params.object_print_z_height()) ?
|
||||
std::max<float>(m_slicing_params.object_print_z_height() - z, 0.f) :
|
||||
m_slicing_params.max_layer_height;
|
||||
return (z + (float)m_slicing_params.max_layer_height > (float)m_slicing_params.object_print_z_height()) ?
|
||||
std::max((float)m_slicing_params.object_print_z_height() - z, 0.f) : (float)m_slicing_params.max_layer_height;
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -5,29 +5,49 @@
|
|||
|
||||
#include "Slicing.hpp"
|
||||
#include "admesh/stl.h"
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
#include "TriangleMesh.hpp"
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
class ModelVolume;
|
||||
#else
|
||||
class TriangleMesh;
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
class SlicingAdaptive
|
||||
{
|
||||
public:
|
||||
void clear();
|
||||
void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; }
|
||||
void add_mesh(const TriangleMesh *mesh) { m_meshes.push_back(mesh); }
|
||||
void prepare();
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void clear();
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; }
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void set_object(const ModelObject& object) { m_object = &object; }
|
||||
#else
|
||||
void add_mesh(const TriangleMesh* mesh) { m_meshes.push_back(mesh); }
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void prepare();
|
||||
float cusp_height(float z, float cusp_value, int ¤t_facet);
|
||||
float horizontal_facet_distance(float z);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
float horizontal_facet_distance(float z);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
protected:
|
||||
SlicingParameters m_slicing_params;
|
||||
|
||||
std::vector<const TriangleMesh*> m_meshes;
|
||||
// Collected faces of all meshes, sorted by raising Z of the bottom most face.
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
const ModelObject* m_object;
|
||||
TriangleMesh m_mesh;
|
||||
#else
|
||||
std::vector<const TriangleMesh*> m_meshes;
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// Collected faces of all meshes, sorted by raising Z of the bottom most face.
|
||||
std::vector<const stl_facet*> m_faces;
|
||||
// Z component of face normals, normalized.
|
||||
// Z component of face normals, normalized.
|
||||
std::vector<float> m_face_normal_z;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -42,4 +42,7 @@
|
|||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE (1 && ENABLE_THUMBNAIL_GENERATOR)
|
||||
|
||||
// Enable adaptive layer height profile
|
||||
#define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
#endif // _technologies_h_
|
||||
|
|
|
|||
|
|
@ -20,9 +20,6 @@
|
|||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/GCode/PostProcessor.hpp"
|
||||
#include "libslic3r/GCode/PreviewData.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include <cassert>
|
||||
|
|
@ -91,7 +88,7 @@ void BackgroundSlicingProcess::process_fff()
|
|||
m_print->process();
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id));
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_data);
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb);
|
||||
#else
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -139,9 +136,12 @@ void BackgroundSlicingProcess::process_sla()
|
|||
m_sla_print->export_raster(zipper);
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
if (m_thumbnail_data != nullptr)
|
||||
if (m_thumbnail_cb != nullptr)
|
||||
{
|
||||
for (const ThumbnailData& data : *m_thumbnail_data)
|
||||
ThumbnailsList thumbnails;
|
||||
m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, false);
|
||||
// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, false); // renders also supports and pad
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
{
|
||||
if (data.is_valid())
|
||||
write_thumbnail(zipper, data);
|
||||
|
|
@ -461,9 +461,12 @@ void BackgroundSlicingProcess::prepare_upload()
|
|||
Zipper zipper{source_path.string()};
|
||||
m_sla_print->export_raster(zipper, m_upload_job.upload_data.upload_path.string());
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
if (m_thumbnail_data != nullptr)
|
||||
if (m_thumbnail_cb != nullptr)
|
||||
{
|
||||
for (const ThumbnailData& data : *m_thumbnail_data)
|
||||
ThumbnailsList thumbnails;
|
||||
m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, false);
|
||||
// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, false, false); // renders also supports and pad
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
{
|
||||
if (data.is_valid())
|
||||
write_thumbnail(zipper, data);
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ namespace Slic3r {
|
|||
|
||||
class DynamicPrintConfig;
|
||||
class GCodePreviewData;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
struct ThumbnailData;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
class Model;
|
||||
class SLAPrint;
|
||||
|
||||
|
|
@ -53,7 +50,7 @@ public:
|
|||
void set_sla_print(SLAPrint *print) { m_sla_print = print; }
|
||||
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; }
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void set_thumbnail_data(const std::vector<ThumbnailData>* data) { m_thumbnail_data = data; }
|
||||
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished
|
||||
|
|
@ -159,8 +156,8 @@ private:
|
|||
// Data structure, to which the G-code export writes its annotations.
|
||||
GCodePreviewData *m_gcode_preview_data = nullptr;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
// Data structures, used to write thumbnails into gcode.
|
||||
const std::vector<ThumbnailData>* m_thumbnail_data = nullptr;
|
||||
// Callback function, used to write thumbnails into gcode.
|
||||
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
||||
std::string m_temp_output_path;
|
||||
|
|
|
|||
|
|
@ -131,6 +131,9 @@ GLCanvas3D::LayersEditing::LayersEditing()
|
|||
, m_object_max_z(0.f)
|
||||
, m_slicing_parameters(nullptr)
|
||||
, m_layer_height_profile_modified(false)
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
, m_adaptive_cusp(0.2f)
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
, state(Unknown)
|
||||
, band_width(2.0f)
|
||||
, strength(0.005f)
|
||||
|
|
@ -151,7 +154,9 @@ GLCanvas3D::LayersEditing::~LayersEditing()
|
|||
}
|
||||
|
||||
const float GLCanvas3D::LayersEditing::THICKNESS_BAR_WIDTH = 70.0f;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
const float GLCanvas3D::LayersEditing::THICKNESS_RESET_BUTTON_HEIGHT = 22.0f;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
|
||||
{
|
||||
|
|
@ -218,13 +223,103 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
|||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static const ImVec4 orange(0.757f, 0.404f, 0.216f, 1.0f);
|
||||
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float canvas_w = (float)cnv_size.get_width();
|
||||
float canvas_h = (float)cnv_size.get_height();
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
imgui.set_next_window_pos(canvas_w - imgui.get_style_scaling() * THICKNESS_BAR_WIDTH, canvas_h, ImGuiCond_Always, 1.0f, 1.0f);
|
||||
imgui.set_next_window_bg_alpha(0.5f);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
|
||||
imgui.begin(_(L("Layer height profile")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, orange);
|
||||
imgui.text(_(L("Left mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Add detail")));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, orange);
|
||||
imgui.text(_(L("Right mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Remove detail")));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, orange);
|
||||
imgui.text(_(L("Shift + Left mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Reset to base")));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, orange);
|
||||
imgui.text(_(L("Shift + Right mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Smoothing")));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, orange);
|
||||
imgui.text(_(L("Mouse wheel:")));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Increase/decrease edit area")));
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Adaptive"))))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event<float>(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_cusp));
|
||||
|
||||
ImGui::SameLine();
|
||||
float text_align = ImGui::GetCursorPosX();
|
||||
imgui.text(_(L("Cusp (mm)")));
|
||||
ImGui::SameLine();
|
||||
float widget_align = ImGui::GetCursorPosX();
|
||||
ImGui::PushItemWidth(120.0f);
|
||||
m_adaptive_cusp = std::min(m_adaptive_cusp, (float)m_slicing_parameters->max_layer_height);
|
||||
ImGui::SliderFloat("", &m_adaptive_cusp, 0.0f, (float)m_slicing_parameters->max_layer_height, "%.2f");
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Smooth"))))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), HeightProfileSmoothEvent(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, m_smooth_params ));
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(text_align);
|
||||
imgui.text(_(L("Radius")));
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(120.0f);
|
||||
ImGui::SetCursorPosX(widget_align);
|
||||
int radius = (int)m_smooth_params.radius;
|
||||
if (ImGui::SliderInt("##1", &radius, 1, 10))
|
||||
m_smooth_params.radius = (unsigned int)radius;
|
||||
|
||||
ImGui::SetCursorPosX(text_align);
|
||||
imgui.text(_(L("Keep min")));
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(120.0f);
|
||||
ImGui::SetCursorPosX(widget_align);
|
||||
imgui.checkbox("##2", m_smooth_params.keep_min);
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Reset"))))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE));
|
||||
|
||||
imgui.end();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
const Rect& bar_rect = get_bar_rect_viewport(canvas);
|
||||
#else
|
||||
const Rect& bar_rect = get_bar_rect_viewport(canvas);
|
||||
const Rect& reset_rect = get_reset_rect_viewport(canvas);
|
||||
|
||||
_render_tooltip_texture(canvas, bar_rect, reset_rect);
|
||||
_render_reset_texture(reset_rect);
|
||||
_render_active_object_annotations(canvas, bar_rect);
|
||||
_render_profile(bar_rect);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
render_active_object_annotations(canvas, bar_rect);
|
||||
render_profile(bar_rect);
|
||||
}
|
||||
|
||||
float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas)
|
||||
|
|
@ -249,11 +344,13 @@ bool GLCanvas3D::LayersEditing::bar_rect_contains(const GLCanvas3D& canvas, floa
|
|||
return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom());
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
bool GLCanvas3D::LayersEditing::reset_rect_contains(const GLCanvas3D& canvas, float x, float y)
|
||||
{
|
||||
const Rect& rect = get_reset_rect_screen(canvas);
|
||||
return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom());
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
|
||||
{
|
||||
|
|
@ -261,9 +358,14 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
|
|||
float w = (float)cnv_size.get_width();
|
||||
float h = (float)cnv_size.get_height();
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
return Rect(w - thickness_bar_width(canvas), 0.0f, w, h);
|
||||
#else
|
||||
return Rect(w - thickness_bar_width(canvas), 0.0f, w, h - reset_button_height(canvas));
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas)
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
|
|
@ -272,6 +374,7 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas)
|
|||
|
||||
return Rect(w - thickness_bar_width(canvas), h - reset_button_height(canvas), w, h);
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
|
||||
{
|
||||
|
|
@ -282,9 +385,14 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
|
|||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
|
||||
#else
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas)
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
|
|
@ -296,13 +404,14 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas
|
|||
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
|
||||
bool GLCanvas3D::LayersEditing::_is_initialized() const
|
||||
bool GLCanvas3D::LayersEditing::is_initialized() const
|
||||
{
|
||||
return m_shader.is_initialized();
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const
|
||||
{
|
||||
// TODO: do this with ImGui
|
||||
|
|
@ -348,8 +457,9 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co
|
|||
|
||||
GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top());
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const
|
||||
void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const
|
||||
{
|
||||
m_shader.start_using();
|
||||
|
||||
|
|
@ -380,7 +490,7 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
|
|||
m_shader.stop_using();
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const
|
||||
void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) const
|
||||
{
|
||||
//FIXME show some kind of legend.
|
||||
|
||||
|
|
@ -497,6 +607,24 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
|
|||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp)
|
||||
{
|
||||
m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, cusp);
|
||||
const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile;
|
||||
m_layers_texture.valid = false;
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params)
|
||||
{
|
||||
m_layer_height_profile = smooth_height_profile(m_layer_height_profile, *m_slicing_parameters, smoothing_params);
|
||||
const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile;
|
||||
m_layers_texture.valid = false;
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
void GLCanvas3D::LayersEditing::generate_layer_height_texture()
|
||||
{
|
||||
this->update_slicing_parameters();
|
||||
|
|
@ -558,6 +686,7 @@ float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas)
|
|||
* THICKNESS_BAR_WIDTH;
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas)
|
||||
{
|
||||
return
|
||||
|
|
@ -568,6 +697,7 @@ float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas)
|
|||
#endif
|
||||
* THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
|
||||
const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX);
|
||||
|
|
@ -1119,6 +1249,11 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
|
|||
wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
|
||||
|
|
@ -1421,6 +1556,29 @@ bool GLCanvas3D::is_layers_editing_allowed() const
|
|||
return m_layers_editing.is_allowed();
|
||||
}
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void GLCanvas3D::reset_layer_height_profile()
|
||||
{
|
||||
m_layers_editing.reset_layer_height_profile(*this);
|
||||
m_layers_editing.state = LayersEditing::Completed;
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::adaptive_layer_height_profile(float cusp)
|
||||
{
|
||||
m_layers_editing.adaptive_layer_height_profile(*this, cusp);
|
||||
m_layers_editing.state = LayersEditing::Completed;
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params)
|
||||
{
|
||||
m_layers_editing.smooth_layer_height_profile(*this, smoothing_params);
|
||||
m_layers_editing.state = LayersEditing::Completed;
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool GLCanvas3D::is_reload_delayed() const
|
||||
{
|
||||
return m_reload_delayed;
|
||||
|
|
@ -2830,6 +2988,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
m_layers_editing.state = LayersEditing::Editing;
|
||||
_perform_layer_editing_action(&evt);
|
||||
}
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
else if ((layer_editing_object_idx != -1) && m_layers_editing.reset_rect_contains(*this, pos(0), pos(1)))
|
||||
{
|
||||
if (evt.LeftDown())
|
||||
|
|
@ -2842,6 +3001,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled)
|
||||
{
|
||||
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;
|
|||
using Vec3dEvent = Event<Vec3d>;
|
||||
template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
|
||||
|
||||
using HeightProfileSmoothEvent = Event<HeightProfileSmoothingParams>;
|
||||
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
||||
|
|
@ -104,6 +106,11 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
|
|||
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
class GLCanvas3D
|
||||
{
|
||||
|
|
@ -153,13 +160,17 @@ private:
|
|||
|
||||
private:
|
||||
static const float THICKNESS_BAR_WIDTH;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static const float THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool m_enabled;
|
||||
Shader m_shader;
|
||||
unsigned int m_z_texture_id;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
mutable GLTexture m_tooltip_texture;
|
||||
mutable GLTexture m_reset_texture;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// Not owned by LayersEditing.
|
||||
const DynamicPrintConfig *m_config;
|
||||
// ModelObject for the currently selected object (Model::objects[last_object_id]).
|
||||
|
|
@ -171,6 +182,11 @@ private:
|
|||
std::vector<coordf_t> m_layer_height_profile;
|
||||
bool m_layer_height_profile_modified;
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
mutable float m_adaptive_cusp;
|
||||
mutable HeightProfileSmoothingParams m_smooth_params;
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
class LayersTexture
|
||||
{
|
||||
public:
|
||||
|
|
@ -217,28 +233,42 @@ private:
|
|||
void adjust_layer_height_profile();
|
||||
void accept_changes(GLCanvas3D& canvas);
|
||||
void reset_layer_height_profile(GLCanvas3D& canvas);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp);
|
||||
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_paramsn);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
static float get_cursor_z_relative(const GLCanvas3D& canvas);
|
||||
static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static bool reset_rect_contains(const GLCanvas3D& canvas, float x, float y);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_bar_rect_screen(const GLCanvas3D& canvas);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_reset_rect_screen(const GLCanvas3D& canvas);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_bar_rect_viewport(const GLCanvas3D& canvas);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_reset_rect_viewport(const GLCanvas3D& canvas);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
float object_max_z() const { return m_object_max_z; }
|
||||
|
||||
private:
|
||||
bool _is_initialized() const;
|
||||
bool is_initialized() const;
|
||||
void generate_layer_height_texture();
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const;
|
||||
void _render_reset_texture(const Rect& reset_rect) const;
|
||||
void _render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const;
|
||||
void _render_profile(const Rect& bar_rect) const;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const;
|
||||
void render_profile(const Rect& bar_rect) const;
|
||||
void update_slicing_parameters();
|
||||
|
||||
static float thickness_bar_width(const GLCanvas3D &canvas);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static float reset_button_height(const GLCanvas3D &canvas);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
};
|
||||
|
||||
struct Mouse
|
||||
|
|
@ -501,6 +531,12 @@ public:
|
|||
bool is_layers_editing_enabled() const;
|
||||
bool is_layers_editing_allowed() const;
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void reset_layer_height_profile();
|
||||
void adaptive_layer_height_profile(float cusp);
|
||||
void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool is_reload_delayed() const;
|
||||
|
||||
void enable_layers_editing(bool enable);
|
||||
|
|
|
|||
|
|
@ -1388,9 +1388,6 @@ struct Plater::priv
|
|||
Slic3r::Model model;
|
||||
PrinterTechnology printer_technology = ptFFF;
|
||||
Slic3r::GCodePreviewData gcode_preview_data;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
std::vector<Slic3r::ThumbnailData> thumbnail_data;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// GUI elements
|
||||
wxSizer* panel_sizer{ nullptr };
|
||||
|
|
@ -1948,6 +1945,7 @@ struct Plater::priv
|
|||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background);
|
||||
void generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
void msw_rescale_object_menu();
|
||||
|
|
@ -2018,7 +2016,15 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
background_process.set_sla_print(&sla_print);
|
||||
background_process.set_gcode_preview_data(&gcode_preview_data);
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
background_process.set_thumbnail_data(&thumbnail_data);
|
||||
background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background)
|
||||
{
|
||||
std::packaged_task<void(ThumbnailsList&, const Vec2ds&, bool, bool, bool)> task([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background) {
|
||||
generate_thumbnails(thumbnails, sizes, printable_only, parts_only, transparent_background);
|
||||
});
|
||||
std::future<void> result = task.get_future();
|
||||
wxTheApp->CallAfter([&]() { task(thumbnails, sizes, printable_only, parts_only, transparent_background); });
|
||||
result.wait();
|
||||
});
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED);
|
||||
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
||||
|
|
@ -2089,6 +2095,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); });
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event<float>& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); });
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
// 3DScene/Toolbar:
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
|
||||
|
|
@ -3068,37 +3079,6 @@ bool Plater::priv::restart_background_process(unsigned int state)
|
|||
( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) ||
|
||||
(state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) != 0 ||
|
||||
(state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 ) ) {
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
if (((state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) == 0) &&
|
||||
(this->background_process.state() != BackgroundSlicingProcess::STATE_RUNNING))
|
||||
{
|
||||
// update thumbnail data
|
||||
const std::vector<Vec2d> &thumbnail_sizes = this->background_process.current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values;
|
||||
if (this->printer_technology == ptFFF)
|
||||
{
|
||||
// for ptFFF we need to generate the thumbnails before the export of gcode starts
|
||||
this->thumbnail_data.clear();
|
||||
for (const Vec2d &sized : thumbnail_sizes)
|
||||
{
|
||||
this->thumbnail_data.push_back(ThumbnailData());
|
||||
Point size(sized); // round to ints
|
||||
generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, true, false);
|
||||
}
|
||||
}
|
||||
else if (this->printer_technology == ptSLA)
|
||||
{
|
||||
// for ptSLA generate thumbnails without supports and pad (not yet calculated)
|
||||
// to render also supports and pad see on_slicing_update()
|
||||
this->thumbnail_data.clear();
|
||||
for (const Vec2d &sized : thumbnail_sizes)
|
||||
{
|
||||
this->thumbnail_data.push_back(ThumbnailData());
|
||||
Point size(sized); // round to ints
|
||||
generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
// The print is valid and it can be started.
|
||||
if (this->background_process.start()) {
|
||||
this->statusbar()->set_cancel_callback([this]() {
|
||||
|
|
@ -3438,25 +3418,6 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
|||
} else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) {
|
||||
// Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways.
|
||||
this->preview->reload_print();
|
||||
|
||||
// uncomment the following lines if you want to render into the thumbnail also supports and pad for SLA printer
|
||||
/*
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
// update thumbnail data
|
||||
// for ptSLA generate the thumbnail after supports and pad have been calculated to have them rendered
|
||||
if ((this->printer_technology == ptSLA) && (evt.status.percent == -3))
|
||||
{
|
||||
const std::vector<Vec2d>& thumbnail_sizes = this->background_process.current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values;
|
||||
this->thumbnail_data.clear();
|
||||
for (const Vec2d &sized : thumbnail_sizes)
|
||||
{
|
||||
this->thumbnail_data.push_back(ThumbnailData());
|
||||
Point size(sized); // round to ints
|
||||
generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, false, false);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3687,6 +3648,19 @@ void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsig
|
|||
{
|
||||
view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, transparent_background);
|
||||
}
|
||||
|
||||
void Plater::priv::generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background)
|
||||
{
|
||||
thumbnails.clear();
|
||||
for (const Vec2d& size : sizes)
|
||||
{
|
||||
thumbnails.push_back(ThumbnailData());
|
||||
Point isize(size); // round to ints
|
||||
generate_thumbnail(thumbnails.back(), isize.x(), isize.y(), printable_only, parts_only, transparent_background);
|
||||
if (!thumbnails.back().is_valid())
|
||||
thumbnails.pop_back();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
void Plater::priv::msw_rescale_object_menu()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue