Merge remote-tracking branch 'origin/master' into ys_color_print_extension

This commit is contained in:
YuSanka 2019-11-28 09:01:14 +01:00
commit dfd38c7818
53 changed files with 15880 additions and 502 deletions

View file

@ -2,6 +2,7 @@
#include "../ClipperUtils.hpp"
#include "../EdgeGrid.hpp"
#include "../Geometry.hpp"
#include "../Surface.hpp"
#include "../PrintConfig.hpp"
#include "../libslic3r.h"
@ -777,6 +778,8 @@ void mark_boundary_segments_touching_infill(
const Vec2d *pt2;
} visitor(grid, boundary, boundary_data, distance_colliding * distance_colliding);
BoundingBoxf bboxf(boundary_bbox.min.cast<double>(), boundary_bbox.max.cast<double>());
bboxf.offset(- SCALED_EPSILON);
for (const Polyline &polyline : infill) {
// Clip the infill polyline by the Eucledian distance along the polyline.
SegmentPoint start_point = clip_start_segment_and_point(polyline.points, clip_distance);
@ -814,10 +817,12 @@ void mark_boundary_segments_touching_infill(
Vec2d vperp(-v.y(), v.x());
Vec2d a = pt1 - v - vperp;
Vec2d b = pt1 + v - vperp;
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
if (Geometry::liang_barsky_line_clipping(a, b, bboxf))
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
a = pt1 - v + vperp;
b = pt1 + v + vperp;
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
if (Geometry::liang_barsky_line_clipping(a, b, bboxf))
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
#endif
}
}

View file

@ -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"
@ -35,9 +32,7 @@
#include <Shiny/Shiny.h>
#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
#include "miniz_extension.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
#if 0
// Enable debugging and asserts, even in the release build.
@ -695,7 +690,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 +720,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 +788,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 +807,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 +904,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 +923,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 custom gcode
Model* model = print.get_object(0)->model_object()->get_model();
m_custom_g_code_heights = model->custom_gcode_per_height;
@ -937,31 +933,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
@ -974,7 +970,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());
@ -992,15 +988,15 @@ 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, true);
for (const ThumbnailData& data : thumbnails)
{
if (data.is_valid())
{
#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
size_t png_size = 0;
void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
if (png_data != nullptr)
@ -1026,39 +1022,6 @@ void GCode::_do_export(Print &print, FILE *file)
mz_free(png_data);
}
#else
_write_format(file, "\n;\n; thumbnail begin %dx%d\n", data.width, data.height);
size_t row_size = 4 * data.width;
for (int r = (int)data.height - 1; r >= 0; --r)
{
std::string encoded;
encoded.resize(boost::beast::detail::base64::encoded_size(row_size));
encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)(data.pixels.data() + r * row_size), row_size));
unsigned int row_count = 0;
while (encoded.size() > max_row_length)
{
if (row_count == 0)
_write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str());
else
_write_format(file, ";>%s\n", encoded.substr(0, max_row_length).c_str());
encoded = encoded.substr(max_row_length);
++row_count;
}
if (encoded.size() > 0)
{
if (row_count == 0)
_write_format(file, "; %s\n", encoded.c_str());
else
_write_format(file, ";>%s\n", encoded.c_str());
}
}
_write(file, "; thumbnail end\n;\n");
#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE
}
print.throw_if_canceled();
}

View file

@ -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

View file

@ -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

View file

@ -137,6 +137,79 @@ inline bool segments_intersect(
segments_could_intersect(jp1, jp2, ip1, ip2) <= 0;
}
// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html
template<typename T>
bool liang_barsky_line_clipping(
// Start and end points of the source line, result will be stored there as well.
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &x0,
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &x1,
// Bounding box to clip with.
const BoundingBoxBase<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &bbox)
{
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> v = x1 - x0;
double t0 = 0.0;
double t1 = 1.0;
// Traverse through left, right, bottom, top edges.
for (int edge = 0; edge < 4; ++ edge)
{
double p, q;
switch (edge) {
case 0: p = - v.x(); q = - bbox.min.x() + x0.x(); break;
case 1: p = v.x(); q = bbox.max.x() - x0.x(); break;
case 2: p = - v.y(); q = - bbox.min.y() + x0.y(); break;
default: p = v.y(); q = bbox.max.y() - x0.y(); break;
}
if (p == 0) {
if (q < 0)
// Line parallel to the bounding box edge is fully outside of the bounding box.
return false;
// else don't clip
} else {
double r = q / p;
if (p < 0) {
if (r > t1)
// Fully clipped.
return false;
if (r > t0)
// Partially clipped.
t0 = r;
} else {
assert(p > 0);
if (r < t0)
// Fully clipped.
return false;
if (r < t1)
// Partially clipped.
t1 = r;
}
}
}
// Clipped successfully.
x1 = x0 + t1 * v;
x0 += t0 * v;
return true;
}
// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html
template<typename T>
bool liang_barsky_line_clipping(
// Start and end points of the source line.
const Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &x0src,
const Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &x1src,
// Bounding box to clip with.
const BoundingBoxBase<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &bbox,
// Start and end points of the clipped line.
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &x0clip,
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &x1clip)
{
x0clip = x0src;
x1clip = x1src;
return liang_barsky_line_clipping(x0clip, x1clip, bbox);
}
Pointf3s convex_hull(Pointf3s points);
Polygon convex_hull(Points points);
Polygon convex_hull(const Polygons &polygons);

View file

@ -107,6 +107,17 @@ bool Line::intersection(const Line &l2, Point *intersection) const
return false; // not intersecting
}
bool Line::clip_with_bbox(const BoundingBox &bbox)
{
Vec2d x0clip, x1clip;
bool result = Geometry::liang_barsky_line_clipping<double>(this->a.cast<double>(), this->b.cast<double>(), BoundingBoxf(bbox.min.cast<double>(), bbox.max.cast<double>()), x0clip, x1clip);
if (result) {
this->a = x0clip.cast<coord_t>();
this->b = x1clip.cast<coord_t>();
}
return result;
}
Vec3d Linef3::intersect_plane(double z) const
{
auto v = (this->b - this->a).cast<double>();

View file

@ -6,6 +6,7 @@
namespace Slic3r {
class BoundingBox;
class Line;
class Line3;
class Linef3;
@ -43,6 +44,8 @@ public:
Vector normal() const { return Vector((this->b(1) - this->a(1)), -(this->b(0) - this->a(0))); }
bool intersection(const Line& line, Point* intersection) const;
double ccw(const Point& point) const { return point.ccw(*this); }
// Clip a line with a bounding box. Returns false if the line is completely outside of the bounding box.
bool clip_with_bbox(const BoundingBox &bbox);
static double distance_to_squared(const Point &point, const Point &a, const Point &b);
static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); }

View file

@ -319,7 +319,7 @@ Polyline MotionPlannerGraph::shortest_path(size_t node_start, size_t node_end) c
std::vector<size_t> map_node_to_queue_id(m_adjacency_list.size(), size_t(-1));
distance[node_start] = 0.;
auto queue = make_mutable_priority_queue<node_t>(
auto queue = make_mutable_priority_queue<node_t, false>(
[&map_node_to_queue_id](const node_t node, size_t idx) { map_node_to_queue_id[node] = idx; },
[&distance](const node_t node1, const node_t node2) { return distance[node1] < distance[node2]; });
queue.reserve(m_adjacency_list.size());

View file

@ -3,7 +3,7 @@
#include <assert.h>
template<typename T, typename IndexSetter, typename LessPredicate>
template<typename T, typename IndexSetter, typename LessPredicate, const bool ResetIndexWhenRemoved = false>
class MutablePriorityQueue
{
public:
@ -42,26 +42,30 @@ private:
LessPredicate m_less_predicate;
};
template<typename T, typename IndexSetter, typename LessPredicate>
MutablePriorityQueue<T, IndexSetter, LessPredicate> make_mutable_priority_queue(IndexSetter &&index_setter, LessPredicate &&less_predicate)
template<typename T, const bool ResetIndexWhenRemoved, typename IndexSetter, typename LessPredicate>
MutablePriorityQueue<T, IndexSetter, LessPredicate, ResetIndexWhenRemoved> make_mutable_priority_queue(IndexSetter &&index_setter, LessPredicate &&less_predicate)
{
return MutablePriorityQueue<T, IndexSetter, LessPredicate>(
return MutablePriorityQueue<T, IndexSetter, LessPredicate, ResetIndexWhenRemoved>(
std::forward<IndexSetter>(index_setter), std::forward<LessPredicate>(less_predicate));
}
template<class T, class LessPredicate, class IndexSetter>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::clear()
template<class T, class LessPredicate, class IndexSetter, const bool ResetIndexWhenRemoved>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter, ResetIndexWhenRemoved>::clear()
{
#ifndef NDEBUG
for (size_t idx = 0; idx < m_heap.size(); ++ idx)
// Mark as removed from the queue.
m_index_setter(m_heap[idx], std::numeric_limits<size_t>::max());
#ifdef NDEBUG
// Only mark as removed from the queue in release mode, if configured so.
if (ResetIndexWhenRemoved)
#endif /* NDEBUG */
{
for (size_t idx = 0; idx < m_heap.size(); ++ idx)
// Mark as removed from the queue.
m_index_setter(m_heap[idx], std::numeric_limits<size_t>::max());
}
m_heap.clear();
}
template<class T, class LessPredicate, class IndexSetter>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::push(const T &item)
template<class T, class LessPredicate, class IndexSetter, const bool ResetIndexWhenRemoved>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter, ResetIndexWhenRemoved>::push(const T &item)
{
size_t idx = m_heap.size();
m_heap.emplace_back(item);
@ -69,8 +73,8 @@ inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::push(const T &i
update_heap_up(0, idx);
}
template<class T, class LessPredicate, class IndexSetter>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::push(T &&item)
template<class T, class LessPredicate, class IndexSetter, const bool ResetIndexWhenRemoved>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter, ResetIndexWhenRemoved>::push(T &&item)
{
size_t idx = m_heap.size();
m_heap.emplace_back(std::move(item));
@ -78,14 +82,18 @@ inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::push(T &&item)
update_heap_up(0, idx);
}
template<class T, class LessPredicate, class IndexSetter>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::pop()
template<class T, class LessPredicate, class IndexSetter, const bool ResetIndexWhenRemoved>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter, ResetIndexWhenRemoved>::pop()
{
assert(! m_heap.empty());
#ifndef NDEBUG
// Mark as removed from the queue.
m_index_setter(m_heap.front(), std::numeric_limits<size_t>::max());
#ifdef NDEBUG
// Only mark as removed from the queue in release mode, if configured so.
if (ResetIndexWhenRemoved)
#endif /* NDEBUG */
{
// Mark as removed from the queue.
m_index_setter(m_heap.front(), std::numeric_limits<size_t>::max());
}
if (m_heap.size() > 1) {
m_heap.front() = m_heap.back();
m_heap.pop_back();
@ -95,14 +103,18 @@ inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::pop()
m_heap.clear();
}
template<class T, class LessPredicate, class IndexSetter>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::remove(size_t idx)
template<class T, class LessPredicate, class IndexSetter, const bool ResetIndexWhenRemoved>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter, ResetIndexWhenRemoved>::remove(size_t idx)
{
assert(idx < m_heap.size());
#ifndef NDEBUG
// Mark as removed from the queue.
m_index_setter(m_heap[idx], std::numeric_limits<size_t>::max());
#ifdef NDEBUG
// Only mark as removed from the queue in release mode, if configured so.
if (ResetIndexWhenRemoved)
#endif /* NDEBUG */
{
// Mark as removed from the queue.
m_index_setter(m_heap[idx], std::numeric_limits<size_t>::max());
}
if (idx + 1 == m_heap.size()) {
m_heap.pop_back();
return;
@ -114,8 +126,8 @@ inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::remove(size_t i
update_heap_up(0, idx);
}
template<class T, class LessPredicate, class IndexSetter>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::update_heap_up(size_t top, size_t bottom)
template<class T, class LessPredicate, class IndexSetter, const bool ResetIndexWhenRemoved>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter, ResetIndexWhenRemoved>::update_heap_up(size_t top, size_t bottom)
{
size_t childIdx = bottom;
T *child = &m_heap[childIdx];
@ -138,8 +150,8 @@ inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::update_heap_up(
}
}
template<class T, class LessPredicate, class IndexSetter>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter>::update_heap_down(size_t top, size_t bottom)
template<class T, class LessPredicate, class IndexSetter, const bool ResetIndexWhenRemoved>
inline void MutablePriorityQueue<T, LessPredicate, IndexSetter, ResetIndexWhenRemoved>::update_heap_down(size_t top, size_t bottom)
{
size_t parentIdx = top;
T *parent = &m_heap[parentIdx];

View file

@ -1600,7 +1600,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
@ -1621,7 +1621,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

View file

@ -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

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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 = slicing_params.max_layer_height;
#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.

View file

@ -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,

View file

@ -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 &current_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
@ -67,8 +94,8 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int &current_facet
continue;
// compute cusp-height for this facet and store minimum of all heights
float normal_z = m_face_normal_z[ordered_id];
height = std::min(height, (normal_z == 0.f) ? 9999.f : std::abs(cusp_value / normal_z));
}
height = std::min(height, (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z));
}
}
// lower height limit due to printer capabilities
@ -77,8 +104,8 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int &current_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;
@ -88,13 +115,13 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int &current_facet
// Compute cusp-height for this facet and check against height.
float normal_z = m_face_normal_z[ordered_id];
float cusp = (normal_z == 0) ? 9999 : abs(cusp_value / normal_z);
float cusp = (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : abs(cusp_value / normal_z);
float z_diff = zspan.first - z;
// handle horizontal facets
if (m_face_normal_z[ordered_id] > 0.999) {
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
if (normal_z > 0.999f) {
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
height = z_diff;
// Slic3r::debugf "to %f due to near horizontal facet\n", $height;
} else if (cusp > z_diff) {
@ -112,29 +139,30 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int &current_facet
// lower height limit due to printer capabilities again
height = std::max(height, float(m_slicing_params.min_layer_height));
}
// Slic3r::debugf "cusp computation, layer-bottom at z:%f, cusp_value:%f, resulting layer height:%f\n", unscale $z, $cusp_value, $height;
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

View file

@ -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 &current_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;
};

View file

@ -40,6 +40,8 @@
// Enable thumbnail generator
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1)
#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_