Merge branch 'main' into dev/cut-keep-paint

This commit is contained in:
Noisyfox
2026-05-12 16:18:34 +08:00
committed by GitHub
1589 changed files with 63801 additions and 161436 deletions
+8 -8
View File
@@ -34,7 +34,7 @@ public:
void intersect_ray(const indexed_triangle_set &its,
const Vec3d & s,
const Vec3d & dir,
igl::Hit & hit)
igl::Hit<float> & hit)
{
AABBTreeIndirect::intersect_ray_first_hit(its.vertices, its.indices,
m_tree, s, dir, hit, m_triangle_ray_epsilon);
@@ -43,7 +43,7 @@ public:
void intersect_ray(const indexed_triangle_set &its,
const Vec3d & s,
const Vec3d & dir,
std::vector<igl::Hit> & hits)
std::vector<igl::Hit<float>> & hits)
{
AABBTreeIndirect::intersect_ray_all_hits(its.vertices, its.indices,
m_tree, s, dir, hits, m_triangle_ray_epsilon);
@@ -152,7 +152,7 @@ AABBMesh::hit_result
AABBMesh::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
{
assert(is_approx(dir.norm(), 1.));
igl::Hit hit{-1, -1, 0.f, 0.f, 0.f};
igl::Hit<float> hit{-1, -1, 0.f, 0.f, 0.f};
hit.t = std::numeric_limits<float>::infinity();
#ifdef SLIC3R_HOLE_RAYCASTER
@@ -181,23 +181,23 @@ std::vector<AABBMesh::hit_result>
AABBMesh::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
{
std::vector<AABBMesh::hit_result> outs;
std::vector<igl::Hit> hits;
std::vector<igl::Hit<float>> hits;
m_aabb->intersect_ray(*m_tm, s, dir, hits);
// The sort is necessary, the hits are not always sorted.
std::sort(hits.begin(), hits.end(),
[](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
[](const igl::Hit<float>& a, const igl::Hit<float>& b) { return a.t < b.t; });
// Remove duplicates. They sometimes appear, for example when the ray is cast
// along an axis of a cube due to floating-point approximations in igl (?)
hits.erase(std::unique(hits.begin(), hits.end(),
[](const igl::Hit& a, const igl::Hit& b)
[](const igl::Hit<float>& a, const igl::Hit<float>& b)
{ return a.t == b.t; }),
hits.end());
// Convert the igl::Hit into hit_result
// Convert the igl::Hit<float> into hit_result
outs.reserve(hits.size());
for (const igl::Hit& hit : hits) {
for (const igl::Hit<float>& hit : hits) {
outs.emplace_back(AABBMesh::hit_result(*this));
outs.back().m_t = double(hit.t);
outs.back().m_dir = dir;
+8 -8
View File
@@ -257,7 +257,7 @@ namespace detail {
template<typename VertexType, typename IndexedFaceType, typename TreeType, typename VectorType>
struct RayIntersectorHits : RayIntersector<VertexType, IndexedFaceType, TreeType, VectorType> {
std::vector<igl::Hit> hits;
std::vector<igl::Hit<float> > hits;
};
//FIXME implement SSE for float AABB trees with float ray queries.
@@ -397,7 +397,7 @@ namespace detail {
RayIntersectorType &ray_intersector,
size_t node_idx,
Scalar min_t,
igl::Hit &hit)
igl::Hit<float> &hit)
{
const auto &node = ray_intersector.tree.node(node_idx);
assert(node.is_valid());
@@ -414,7 +414,7 @@ namespace detail {
ray_intersector.vertices[face(0)], ray_intersector.vertices[face(1)], ray_intersector.vertices[face(2)],
t, u, v, ray_intersector.eps)
&& t > 0.) {
hit = igl::Hit { int(node.idx), -1, float(u), float(v), float(t) };
hit = igl::Hit<float> { int(node.idx), -1, float(u), float(v), float(t) };
return true;
} else
return false;
@@ -422,8 +422,8 @@ namespace detail {
// Left / right child node index.
size_t left = node_idx * 2 + 1;
size_t right = left + 1;
igl::Hit left_hit;
igl::Hit right_hit;
igl::Hit<float> left_hit;
igl::Hit<float> right_hit;
bool left_ret = intersect_ray_recursive_first_hit(ray_intersector, left, min_t, left_hit);
if (left_ret && left_hit.t < min_t) {
min_t = left_hit.t;
@@ -459,7 +459,7 @@ namespace detail {
ray_intersector.vertices[face(0)], ray_intersector.vertices[face(1)], ray_intersector.vertices[face(2)],
t, u, v, ray_intersector.eps)
&& t > 0.) {
ray_intersector.hits.emplace_back(igl::Hit{ int(node.idx), -1, float(u), float(v), float(t) });
ray_intersector.hits.emplace_back(igl::Hit<float>{ int(node.idx), -1, float(u), float(v), float(t) });
}
} else {
// Left / right child node index.
@@ -732,7 +732,7 @@ inline bool intersect_ray_first_hit(
// Direction of the ray.
const VectorType &dir,
// First intersection of the ray with the indexed triangle set.
igl::Hit &hit,
igl::Hit<float> &hit,
// Epsilon for the ray-triangle intersection, it should be proportional to an average triangle edge length.
const double eps = 0.000001)
{
@@ -764,7 +764,7 @@ inline bool intersect_ray_all_hits(
// Direction of the ray.
const VectorType &dir,
// All intersections of the ray with the indexed triangle set, sorted by parameter t.
std::vector<igl::Hit> &hits,
std::vector<igl::Hit<float> > &hits,
// Epsilon for the ray-triangle intersection, it should be proportional to an average triangle edge length.
const double eps = 0.000001)
{
+4 -4
View File
@@ -484,7 +484,7 @@ if (APPLE)
)
endif ()
add_library(libslic3r STATIC ${lisbslic3r_sources}
add_library(libslic3r STATIC ${lisbslic3r_sources}
"${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h"
${OpenVDBUtils_SOURCES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${lisbslic3r_sources})
@@ -500,7 +500,7 @@ find_package(CGAL REQUIRED)
find_package(OpenCV REQUIRED core)
cmake_policy(POP)
add_library(libslic3r_cgal STATIC
add_library(libslic3r_cgal STATIC
CutSurface.hpp CutSurface.cpp
IntersectionPoints.hpp IntersectionPoints.cpp
MeshBoolean.hpp MeshBoolean.cpp
@@ -525,7 +525,7 @@ if (_opts)
target_compile_options(libslic3r_cgal PRIVATE "${_opts_bad}")
endif()
target_link_libraries(libslic3r_cgal PRIVATE ${_cgal_tgt} eigen admesh libigl mcut boost_libs)
target_link_libraries(libslic3r_cgal PRIVATE ${_cgal_tgt} admesh libigl mcut boost_libs)
if (MSVC AND "${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") # 32 bit MSVC workaround
target_compile_definitions(libslic3r_cgal PRIVATE CGAL_DO_NOT_USE_MPZF)
@@ -576,6 +576,7 @@ set(OCCT_LIBS
target_link_libraries(libslic3r
PUBLIC
Eigen3::Eigen
admesh
libigl
libnest2d
@@ -590,7 +591,6 @@ target_link_libraries(libslic3r
clipper
Clipper2
draco::draco
eigen
glu-libtess
JPEG::JPEG
libslic3r_cgal
+11
View File
@@ -3925,6 +3925,17 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
// New Marlin uses M205 J[mm] for junction deviation (only apply if it is > 0)
file.write_format(writer().set_junction_deviation(config().machine_max_junction_deviation.values.front()).c_str());
// Orca: Override input shaping values
if (print.config().input_shaping_emit.value && flavor != gcfMarlinLegacy) {
const bool input_shaping_disable = print.config().input_shaping_type.value == InputShaperType::Disable;
file.write_format(writer().set_input_shaping('X', print.config().input_shaping_damp_x.value,
print.config().input_shaping_freq_x.value, print.config().opt_serialize("input_shaping_type")).c_str());
if (flavor != gcfRepRapFirmware && !input_shaping_disable) {
file.write_format(writer().set_input_shaping('Y', print.config().input_shaping_damp_y.value,
print.config().input_shaping_freq_y.value, "").c_str());
}
}
}
}
+2 -2
View File
@@ -154,7 +154,7 @@ std::vector<float> raycast_visibility(const AABBTreeIndirect::Tree<3, float> &ra
[&triangles, &precomputed_sample_directions, model_contains_negative_parts, negative_volumes_start_index,
&raycasting_tree, &result, &samples, seam_position](tbb::blocked_range<size_t> r) {
// Maintaining hits memory outside of the loop, so it does not have to be reallocated for each query.
std::vector<igl::Hit> hits;
std::vector<igl::Hit<float>> hits;
for (size_t s_idx = r.begin(); s_idx < r.end(); ++s_idx) {
result[s_idx] = 1.0f;
constexpr float decrease_step = 1.0f
@@ -174,7 +174,7 @@ std::vector<float> raycast_visibility(const AABBTreeIndirect::Tree<3, float> &ra
for (const auto &dir : precomputed_sample_directions) {
Vec3f final_ray_dir = (f.to_world(dir));
if (!model_contains_negative_parts) {
igl::Hit hitpoint;
igl::Hit<float> hitpoint;
// FIXME: This AABBTTreeIndirect query will not compile for float ray origin and
// direction.
Vec3d final_ray_dir_d = final_ray_dir.cast<double>();
+60 -40
View File
@@ -350,7 +350,7 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je
std::string GCodeWriter::set_junction_deviation(double junction_deviation){
std::ostringstream gcode;
if (FLAVOR_IS(gcfMarlinFirmware) && junction_deviation > 0 && m_max_junction_deviation > 0) {
if (FLAVOR_IS(gcfMarlinFirmware) && m_max_junction_deviation > 0 && junction_deviation > 0) {
// Clamp the junction deviation to the allowed maximum.
gcode << "M205 J";
if (junction_deviation <= m_max_junction_deviation) {
@@ -390,68 +390,88 @@ std::string GCodeWriter::set_pressure_advance(double pa) const
return gcode.str();
}
// Orca: input shaping support
std::string GCodeWriter::set_input_shaping(char axis, float damp, float freq, std::string type) const
{
if (FLAVOR_IS(gcfMarlinLegacy))
throw std::runtime_error("Input shaping is not supported by Marlin < 2.1.2.\nCheck your firmware version and update your G-code flavor to ´Marlin 2´");
if (freq < 0.0f || damp < 0.f || damp > 1.0f || (axis != 'X' && axis != 'Y' && axis != 'Z' && axis != 'A'))// A = all axis
{
throw std::runtime_error("Invalid input shaping parameters: freq=" + std::to_string(freq) + ", damp=" + std::to_string(damp));
bool disable = type == "Disable";
if (disable){
freq = 0.0f;
damp = 0.0f;
axis = 'A';
type = "Default";
} else if (freq < 0.0f || damp < 0.f || damp > 1.0f || (axis != 'X' && axis != 'Y' && axis != 'Z' && axis != 'A')) { // A = all axis
throw std::runtime_error("Invalid input shaping parameters: axis=" + std::string(1, axis) + ", freq=" + std::to_string(freq) + ", damp=" + std::to_string(damp));
}
std::ostringstream gcode;
if (FLAVOR_IS(gcfKlipper)) {
gcode << "SET_INPUT_SHAPER";
std::ostringstream params;
switch (this->config.gcode_flavor) {
case gcfKlipper: {
if (!type.empty() && type != "Default") {
gcode << " SHAPER_TYPE=" << type;
params << " SHAPER_TYPE=" << type;
}
if (axis != 'A')
{
if (freq > 0.0f) {
gcode << " SHAPER_FREQ_" << axis << "=" << std::fixed << std::setprecision(2) << freq;
}
if (damp > 0.0f){
gcode << " DAMPING_RATIO_" << axis << "=" << std::fixed << std::setprecision(3) << damp;
}
} else {
if (freq > 0.0f) {
gcode << " SHAPER_FREQ_X=" << std::fixed << std::setprecision(2) << freq << " SHAPER_FREQ_Y=" << std::fixed << std::setprecision(2) << freq;
params << " SHAPER_FREQ_" << axis << "=" << std::fixed << std::setprecision(2) << freq;
}
if (damp > 0.0f) {
gcode << " DAMPING_RATIO_X=" << std::fixed << std::setprecision(3) << damp << " DAMPING_RATIO_Y=" << std::fixed << std::setprecision(3) << damp;
params << " DAMPING_RATIO_" << axis << "=" << std::fixed << std::setprecision(3) << damp;
}
} else {
if (freq > 0.0f || disable) {
params << " SHAPER_FREQ_X=" << std::fixed << std::setprecision(2) << freq << " SHAPER_FREQ_Y=" << std::fixed << std::setprecision(2) << freq;
}
if (damp > 0.0f || disable) {
params << " DAMPING_RATIO_X=" << std::fixed << std::setprecision(3) << damp << " DAMPING_RATIO_Y=" << std::fixed << std::setprecision(3) << damp;
}
}
} else if (FLAVOR_IS(gcfRepRapFirmware)) {
gcode << "M593";
if (!params.str().empty()) {
gcode << "SET_INPUT_SHAPER" << params.str();
}
break;
}
case gcfRepRapFirmware: {
if (!type.empty() && type != "Default" && type != "DAA") {
gcode << " P\"" << type << "\"";
params << " P\"" << type << "\"";
}
if (freq > 0.0f) {
gcode << " F" << std::fixed << std::setprecision(2) << freq;
if (freq > 0.0f || disable) {
params << " F" << std::fixed << std::setprecision(2) << freq;
}
if (damp > 0.0f){
gcode << " S" << std::fixed << std::setprecision(3) << damp;
if (damp > 0.0f || disable) {
params << " S" << std::fixed << std::setprecision(3) << damp;
}
} else if (FLAVOR_IS(gcfMarlinFirmware)) {
gcode << "M593";
if (axis != 'A')
{
gcode << " " << axis;
if (!params.str().empty()) {
gcode << "M593" << params.str();
}
if (freq > 0.0f)
{
gcode << " F" << std::fixed << std::setprecision(2) << freq;
break;
}
case gcfMarlinFirmware: {
if (axis != 'A') {
params << " " << axis;
}
if (damp > 0.0f)
{
gcode << " D" << std::fixed << std::setprecision(3) << damp;
if (freq > 0.0f || disable) {
params << " F" << std::fixed << std::setprecision(2) << freq;
}
} else {
if (damp > 0.0f || disable) {
params << " D" << std::fixed << std::setprecision(3) << damp;
}
if (!params.str().empty()) {
gcode << "M593" << params.str();
}
break;
}
case gcfMarlinLegacy: {
throw std::runtime_error("Input shaping is not supported by Marlin < 2.1.2.\nCheck your firmware version and update your G-code flavor to ´Marlin 2´");
}
default:
throw std::runtime_error("Input shaping is only supported by Klipper, RepRapFirmware and Marlin 2");
}
if (GCodeWriter::full_gcode_comment){
gcode << " ; Override input shaping";
if (!gcode.str().empty()) {
if (GCodeWriter::full_gcode_comment) {
gcode << " ; Override input shaping";
}
gcode << "\n";
}
gcode << "\n";
return gcode.str();
}
+2
View File
@@ -1318,6 +1318,8 @@ static std::vector<std::string> s_Preset_machine_limits_options {
"machine_max_junction_deviation",
//resonance avoidance ported from qidi slicer
"resonance_avoidance", "min_resonance_avoidance_speed", "max_resonance_avoidance_speed",
// Orca: input shaping
"input_shaping_emit", "input_shaping_type", "input_shaping_freq_x", "input_shaping_freq_y", "input_shaping_damp_x", "input_shaping_damp_y",
};
static std::vector<std::string> s_Preset_printer_options {
+32 -17
View File
@@ -60,6 +60,7 @@ const char *PresetBundle::ORCA_DEFAULT_PRINTER_MODEL = "MyKlipper 0.4 nozzle";
const char *PresetBundle::ORCA_DEFAULT_PRINTER_VARIANT = "0.4";
const char *PresetBundle::ORCA_DEFAULT_FILAMENT = "Generic PLA @System";
const char *PresetBundle::ORCA_FILAMENT_LIBRARY = "OrcaFilamentLibrary";
const char *PresetBundle::ORCA_DEFAULT_FILAMENT_PLACEHOLDER = "Default Filament";
DynamicPrintConfig PresetBundle::construct_full_config(
Preset& in_printer_preset,
@@ -317,7 +318,7 @@ std::string PresetBundle::find_preset_vendor(const std::string &preset_name, Pre
PresetBundle::PresetBundle()
: prints(Preset::TYPE_PRINT, Preset::print_options(), static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()))
, filaments(Preset::TYPE_FILAMENT, Preset::filament_options(), static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()), "Default Filament")
, filaments(Preset::TYPE_FILAMENT, Preset::filament_options(), static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()), ORCA_DEFAULT_FILAMENT_PLACEHOLDER)
, sla_materials(Preset::TYPE_SLA_MATERIAL, Preset::sla_material_options(), static_cast<const SLAMaterialConfig &>(SLAFullPrintConfig::defaults()))
, sla_prints(Preset::TYPE_SLA_PRINT, Preset::sla_print_options(), static_cast<const SLAPrintObjectConfig &>(SLAFullPrintConfig::defaults()))
, printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()), "Default Printer")
@@ -2634,7 +2635,10 @@ void PresetBundle::update_selections(AppConfig &config)
std::string first_visible_filament_name;
for (auto & fp : filament_presets) {
if (auto it = filaments.find_preset_internal(fp); it == filaments.end() || !it->is_visible || !it->is_compatible) {
// Orca: also match the ORCA_DEFAULT_FILAMENT_PLACEHOLDER placeholder. update_compatible_internal
// iterates from m_num_default_presets, so the placeholder's is_compatible flag
// stays true and the not-found/visible/compatible predicate alone would miss it.
if (auto it = filaments.find_preset_internal(fp); fp == ORCA_DEFAULT_FILAMENT_PLACEHOLDER || it == filaments.end() || !it->is_visible || !it->is_compatible) {
if (first_visible_filament_name.empty())
first_visible_filament_name = filaments.first_compatible().name;
fp = first_visible_filament_name;
@@ -2685,13 +2689,13 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
initial_print_profile_name = prefered_print_profile;
const std::vector<std::string>& prefered_filament_profiles = preferred_printer->config.option<ConfigOptionStrings>("default_filament_profile")->values;
if ((!initial_filament_profile_name.compare("Default Filament")) && (prefered_filament_profiles.size() > 0)) {
if ((!initial_filament_profile_name.compare(ORCA_DEFAULT_FILAMENT_PLACEHOLDER)) && (prefered_filament_profiles.size() > 0)) {
// Check if preferred filament is visible
const Preset* preferred_preset = this->filaments.find_preset(prefered_filament_profiles[0], false);
if (preferred_preset && preferred_preset->is_visible) {
initial_filament_profile_name = prefered_filament_profiles[0];
}
// If not visible, keep the default "Default Filament" which will be resolved later
// If not visible, keep the default ORCA_DEFAULT_FILAMENT_PLACEHOLDER which will be resolved later
}
}
@@ -2792,7 +2796,8 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
std::string first_visible_filament_name;
for (auto & fp : filament_presets) {
if (auto it = filaments.find_preset_internal(fp); it == filaments.end() || !it->is_visible || !it->is_compatible) {
// Orca: also match the ORCA_DEFAULT_FILAMENT_PLACEHOLDER placeholder — see update_selections.
if (auto it = filaments.find_preset_internal(fp); fp == ORCA_DEFAULT_FILAMENT_PLACEHOLDER || it == filaments.end() || !it->is_visible || !it->is_compatible) {
if (first_visible_filament_name.empty())
first_visible_filament_name = filaments.first_compatible().name;
fp = first_visible_filament_name;
@@ -5034,19 +5039,22 @@ void PresetBundle::update_multi_material_filament_presets(size_t to_delete_filam
if (printers.get_edited_preset().printer_technology() != ptFFF)
return;
// BBS
#if 0
// Orca: when the number of existing filament presets is less than the number of extruders, we will append new filament presets with the
// same value as the last existing one.
//
// Verify and select the filament presets.
auto *nozzle_diameter = static_cast<const ConfigOptionFloats*>(printers.get_edited_preset().config.option("nozzle_diameter"));
size_t num_extruders = nozzle_diameter->values.size();
// Verify validity of the current filament presets.
for (size_t i = 0; i < std::min(this->filament_presets.size(), num_extruders); ++ i)
this->filament_presets[i] = this->filaments.find_preset(this->filament_presets[i], true)->name;
// Append the rest of filament presets.
this->filament_presets.resize(num_extruders, this->filament_presets.empty() ? this->filaments.first_visible().name : this->filament_presets.back());
#else
size_t num_filaments = this->filament_presets.size();
#endif
auto* nozzle_diameter = static_cast<const ConfigOptionFloats*>(printers.get_edited_preset().config.option("nozzle_diameter"));
size_t num_extruders = nozzle_diameter->values.size();
if (num_extruders > num_filaments) { // Verify validity of the current filament presets.
for (size_t i = 0; i < std::min(this->filament_presets.size(), num_extruders); ++i)
this->filament_presets[i] = this->filaments.find_preset(this->filament_presets[i], true)->name;
// Append the rest of filament presets.
this->filament_presets.resize(num_extruders, this->filament_presets.empty() ? this->filaments.first_visible().name :
this->filament_presets.back());
num_filaments = this->filament_presets.size();
}
if (to_delete_filament_id == -1)
to_delete_filament_id = num_filaments;
@@ -5081,7 +5089,14 @@ void PresetBundle::update_multi_material_filament_presets(size_t to_delete_filam
unsigned int old_i = i >= to_delete_filament_id ? i + 1 : i;
unsigned int old_j = j >= to_delete_filament_id ? j + 1 : j;
for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) {
new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = old_matrix[old_i * old_number_of_filaments + old_j + old_matrix_size * nozzle_id];
// Orca: only copy from old_matrix when the old layout actually has data
// for this nozzle slot; otherwise initialize from the per-filament
// flush volumes the same way the (i,j) out-of-range branch does.
if (nozzle_id < old_nozzle_nums) {
new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = old_matrix[old_i * old_number_of_filaments + old_j + old_matrix_size * nozzle_id];
} else {
new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = (i == j ? 0. : filaments[2 * i] + filaments[2 * j + 1]);
}
}
} else {
for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) {
+1
View File
@@ -465,6 +465,7 @@ public:
static const char *ORCA_DEFAULT_PRINTER_VARIANT;
static const char *ORCA_DEFAULT_FILAMENT;
static const char *ORCA_FILAMENT_LIBRARY;
static const char *ORCA_DEFAULT_FILAMENT_PLACEHOLDER;
static std::array<Preset::Type, 3> types_list(PrinterTechnology pt) {
+88 -2
View File
@@ -91,6 +91,25 @@ size_t get_extruder_index(const GCodeConfig& config, unsigned int filament_id)
return 0;
}
// Orca: input shaping values types by flavor
std::vector<std::string> get_shaper_type_values_for_flavor(GCodeFlavor flavor)
{
switch (flavor) {
case GCodeFlavor::gcfKlipper:
return {"Default", "MZV", "ZV", "ZVD", "EI", "2HUMP_EI", "3HUMP_EI"};
case GCodeFlavor::gcfRepRapFirmware:
return {"Default", "MZV", "ZV", "ZVD", "ZVDD", "ZVDDD", "EI2", "EI3", "DAA"};
case GCodeFlavor::gcfMarlinFirmware:
return {"ZV"};
case GCodeFlavor::gcfMarlinLegacy:
return {};
default:
break;
}
return {"Default"};
}
static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &enum_keys_map)
{
t_config_enum_names names;
@@ -481,6 +500,23 @@ static t_config_enum_values s_keys_map_PrinterStructure {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrinterStructure)
static t_config_enum_values s_keys_map_InputShaperType {
{"Default", int(InputShaperType::Default)},
{"MZV", int(InputShaperType::MZV)},
{"ZV", int(InputShaperType::ZV)},
{"ZVD", int(InputShaperType::ZVD)},
{"ZVDD", int(InputShaperType::ZVDD)},
{"ZVDDD", int(InputShaperType::ZVDDD)},
{"EI", int(InputShaperType::EI)},
{"EI2", int(InputShaperType::EI2)},
{"2HUMP_EI",int(InputShaperType::TwoHumpEI)},
{"EI3", int(InputShaperType::EI3)},
{"3HUMP_EI",int(InputShaperType::ThreeHumpEI)},
{"DAA", int(InputShaperType::DAA)},
{"Disable", int(InputShaperType::Disable)}
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InputShaperType)
static t_config_enum_values s_keys_map_PerimeterGeneratorType{
{ "classic", int(PerimeterGeneratorType::Classic) },
{ "arachne", int(PerimeterGeneratorType::Arachne) }
@@ -4243,8 +4279,8 @@ void PrintConfigDef::init_fff_params()
def = this->add("emit_machine_limits_to_gcode", coBool);
def->label = L("Emit limits to G-code");
def->category = L("Machine limits");
def->tooltip = L("If enabled, the machine limits will be emitted to G-code file.\nThis option will be ignored if the G-code flavor is "
"set to Klipper.");
def->tooltip = L("If enabled, the machine limits will be emitted to G-code file.\nThis option will be ignored if the G-code flavor is "
"set to Klipper.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
@@ -4455,6 +4491,56 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(120));
// Orca: Input Shaping support
def = this->add("input_shaping_emit", coBool);
def->label = L("Emit input shaping");
def->tooltip = L("Override firmware input shaping settings.\nIf disabled, firmware settings are used.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("input_shaping_type", coEnum);
def->label = L("Input shaper type");
def->tooltip = L("Choose the input shaper algorithm.\nDefault uses the firmware default settings.\nDisable turns off input shaping in the firmware.");
def->enum_keys_map = &ConfigOptionEnum<InputShaperType>::get_enum_values();
def->enum_values = {"Default", "MZV", "ZV", "ZVD", "ZVDD", "ZVDDD", "EI", "EI2", "2HUMP_EI", "EI3", "3HUMP_EI", "DAA", "Disable"};
def->enum_labels = {L("Default"), L("MZV"), L("ZV"), L("ZVD"), L("ZVDD"), L("ZVDDD"), L("EI"), L("EI2"), L("2HUMP_EI"), L("EI3"), L("3HUMP_EI"), L("DAA"), L("Disable")};
def->mode = comExpert;
def->set_default_value(new ConfigOptionEnum<InputShaperType>(InputShaperType::Default));
def = this->add("input_shaping_freq_x", coFloat);
def->label = L("X");
def->tooltip = L("Resonant frequency for the X axis input shaper.\nZero will use the firmware frequency.\nTo disable input shaping, use the Disable type.\nRRF: X and Y values are equal.");
def->sidetext = "Hz";
def->min = 0;
def->max = 1000;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("input_shaping_freq_y", coFloat);
def->label = L("Y");
def->tooltip = L("Resonant frequency for the Y axis input shaper.\nZero will use the firmware frequency.\nTo disable input shaping, use the Disable type.");
def->sidetext = "Hz";
def->min = 0;
def->max = 1000;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("input_shaping_damp_x", coFloat);
def->label = L("X");
def->tooltip = L("Damping ratio for the X axis input shaper.\nZero will use the firmware damping ratio.\nTo disable input shaping, use the Disable type.\nRRF: X and Y values are equal.");
def->min = 0;
def->max = 1;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0.1));
def = this->add("input_shaping_damp_y", coFloat);
def->label = L("Y");
def->tooltip = L("Damping ratio for the Y axis input shaper.\nZero will use the firmware damping ratio.\nTo disable input shaping, use the Disable type.");
def->min = 0;
def->max = 1;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0.1));
def = this->add("fan_max_speed", coFloats);
def->label = L("Fan speed");
def->tooltip = L("Part cooling fan speed may be increased when auto cooling is enabled. "
+25
View File
@@ -362,6 +362,22 @@ enum PrinterStructure {
psDelta
};
enum class InputShaperType : unsigned char {
Default = 0,
MZV,
ZV,
ZVD,
ZVDD,
ZVDDD,
EI,
EI2,
TwoHumpEI,
EI3,
ThreeHumpEI,
DAA,
Disable
};
// BBS
enum ZHopType {
zhtAuto = 0,
@@ -525,6 +541,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BrimType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(TimelapseType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BedType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SkirtType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InputShaperType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(DraftShield)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ForwardCompatibilitySubstitutionRule)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeThumbnailsFormat)
@@ -1259,6 +1276,14 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, resonance_avoidance))
((ConfigOptionFloat, min_resonance_avoidance_speed))
((ConfigOptionFloat, max_resonance_avoidance_speed))
//Orca: Input shaping
((ConfigOptionBool, input_shaping_emit))
((ConfigOptionEnum<InputShaperType>, input_shaping_type))
((ConfigOptionFloat, input_shaping_freq_x))
((ConfigOptionFloat, input_shaping_freq_y))
((ConfigOptionFloat, input_shaping_damp_x))
((ConfigOptionFloat, input_shaping_damp_y))
)
// This object is mapped to Perl as Slic3r::Config::GCode.
+8 -8
View File
@@ -36,7 +36,7 @@ public:
void intersect_ray(const indexed_triangle_set &its,
const Vec3d & s,
const Vec3d & dir,
igl::Hit & hit)
igl::Hit<float> & hit)
{
AABBTreeIndirect::intersect_ray_first_hit(its.vertices, its.indices,
m_tree, s, dir, hit, m_triangle_ray_epsilon);
@@ -45,7 +45,7 @@ public:
void intersect_ray(const indexed_triangle_set &its,
const Vec3d & s,
const Vec3d & dir,
std::vector<igl::Hit> & hits)
std::vector<igl::Hit<float>> & hits)
{
AABBTreeIndirect::intersect_ray_all_hits(its.vertices, its.indices,
m_tree, s, dir, hits, m_triangle_ray_epsilon);
@@ -146,7 +146,7 @@ IndexedMesh::hit_result
IndexedMesh::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
{
assert(is_approx(dir.norm(), 1.));
igl::Hit hit{-1, -1, 0.f, 0.f, 0.f};
igl::Hit<float> hit{-1, -1, 0.f, 0.f, 0.f};
hit.t = std::numeric_limits<float>::infinity();
#ifdef SLIC3R_HOLE_RAYCASTER
@@ -175,24 +175,24 @@ std::vector<IndexedMesh::hit_result>
IndexedMesh::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
{
std::vector<IndexedMesh::hit_result> outs;
std::vector<igl::Hit> hits;
std::vector<igl::Hit<float>> hits;
m_aabb->intersect_ray(*m_tm, s, dir, hits);
// The sort is necessary, the hits are not always sorted.
std::sort(hits.begin(), hits.end(),
[](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
[](const igl::Hit<float>& a, const igl::Hit<float>& b) { return a.t < b.t; });
// Remove duplicates. They sometimes appear, for example when the ray is cast
// along an axis of a cube due to floating-point approximations in igl (?)
// BBS: STUDIO-2591 A mesh with overlapping faces cannot be painted
//hits.erase(std::unique(hits.begin(), hits.end(),
// [](const igl::Hit& a, const igl::Hit& b)
// [](const igl::Hit<float>& a, const igl::Hit<float>& b)
// { return a.t == b.t; }),
// hits.end());
// Convert the igl::Hit into hit_result
// Convert the igl::Hit<float> into hit_result
outs.reserve(hits.size());
for (const igl::Hit& hit : hits) {
for (const igl::Hit<float>& hit : hits) {
outs.emplace_back(IndexedMesh::hit_result(*this));
outs.back().m_t = double(hit.t);
outs.back().m_dir = dir;
+32 -46
View File
@@ -1,55 +1,41 @@
#include "TriangleMeshDeal.hpp"
#include <igl/read_triangle_mesh.h>
#include <igl/loop.h>
#include <igl/upsample.h>
#include <igl/false_barycentric_subdivision.h>
#undef NDEBUG
#include <assert.h>
#include <boost/log/trivial.hpp>
namespace Slic3r {
TriangleMesh TriangleMeshDeal::smooth_triangle_mesh(const TriangleMesh &mesh, bool &ok)
TriangleMesh TriangleMeshDeal::smooth_triangle_mesh(const TriangleMesh& mesh, bool& ok)
{
{
using namespace std;
using namespace igl;
Eigen::MatrixXi OF, F;
Eigen::MatrixXd OV, V;
auto vertices_count = mesh.its.vertices.size();
OV = Eigen::MatrixXd(vertices_count, 3);
for (int i = 0; i < vertices_count; i++) {
auto v = mesh.its.vertices[i];
OV.row(i) << v[0], v[1], v[2];
}
auto indices_count = mesh.its.indices.size();
OF = Eigen::MatrixXi(indices_count, 3);
for (int i = 0; i < indices_count; i++) {
auto face = mesh.its.indices[i];
OF.row(i) << face[0], face[1], face[2];
}
//igl:: read_triangle_mesh( "E:/Download/libigl-2.6.0/out/build/x64-Debug/_deps/libigl_tutorial_data-src/decimated-knight.off", OV, OF);
V = OV;
F = OF;
{
using namespace igl;
typedef Eigen::Matrix<float, Eigen::Dynamic, 3, Eigen::DontAlign | Eigen::RowMajor> RowMatrixX3f;
typedef Eigen::Matrix<int, Eigen::Dynamic, 3, Eigen::DontAlign | Eigen::RowMajor> RowMatrixX3i;
//igl::upsample(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F);
ok = true;
if (!igl::loop(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F)) {
ok = false;
return TriangleMesh();
}
//igl::false_barycentric_subdivision(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F);
indexed_triangle_set its;
int vertex_count = V.rows();
its.vertices.resize(vertex_count);
for (int i = 0; i < vertex_count; i++) {
its.vertices[i] = V.row(i).cast<float>();
}
int indice_count = F.rows();
its.indices.resize(indice_count);
for (int i = 0; i < indice_count; i++) {
auto cur = F.row(i);
its.indices[i] = Slic3r::Vec3i32(cur[0], cur[1], cur[2]);
}
TriangleMesh result_mesh(its);
return result_mesh;
}
auto vertices_count = mesh.its.vertices.size();
auto indices_count = mesh.its.indices.size();
// Use Map to map the vertices and indicies into Matrixes without requiring a copy.
const Eigen::Map<const RowMatrixX3f> OV(mesh.its.vertices[0].data(), vertices_count, 3);
const Eigen::Map<const RowMatrixX3i> OF(mesh.its.indices[0].data(), indices_count, 3);
Eigen::MatrixX3f V;
Eigen::MatrixX3i F;
ok = true;
// TODO: add validation checks for the input mesh? Is this really necessary?
// if ( <not OK> ) {
// ok = false;
// return TriangleMesh();
// }
loop(OV, OF, V, F);
indexed_triangle_set its;
auto iterv = V.rowwise();
auto iterf = F.rowwise();
its.vertices.assign(iterv.cbegin(), iterv.cend());
its.indices.assign(iterf.cbegin(), iterf.cend());
TriangleMesh result_mesh(its);
return result_mesh;
}
}
} // namespace Slic3r
+6 -5
View File
@@ -114,12 +114,13 @@ void set_logging_level(unsigned int level)
{
logSeverity = level_to_boost(level);
// Force at debug level logging for pre-release builds.
// Orca: force at info or lower level logging for pre-release builds.
// Note: not setting to debug or trace as they might affect long time usage especially with BBL printers.
const std::string version = SoftFever_VERSION;
if (boost::algorithm::icontains(version, "dev") ||
boost::algorithm::icontains(version, "alpha") ||
boost::algorithm::icontains(version, "beta")) {
logSeverity = boost::log::trivial::debug;
if (level > (unsigned int) boost::log::trivial::info &&
(boost::algorithm::icontains(version, "dev") || boost::algorithm::icontains(version, "alpha") ||
boost::algorithm::icontains(version, "beta"))) {
logSeverity = boost::log::trivial::info;
}
boost::log::core::get()->set_filter