mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-27 18:51:11 -06:00
Merge branch 'master' into lm_tm_hollowing
This commit is contained in:
commit
b3f15b1c98
68 changed files with 1399 additions and 917 deletions
|
|
@ -679,133 +679,73 @@ ClipperLib::PolyTree union_pt(ExPolygons &&subject, bool safety_offset_)
|
|||
return _clipper_do<ClipperLib::PolyTree>(ClipperLib::ctUnion, std::move(subject), Polygons(), ClipperLib::pftEvenOdd, safety_offset_);
|
||||
}
|
||||
|
||||
Polygons
|
||||
union_pt_chained(const Polygons &subject, bool safety_offset_)
|
||||
{
|
||||
ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
|
||||
|
||||
Polygons retval;
|
||||
traverse_pt(polytree.Childs, &retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes)
|
||||
// Simple spatial ordering of Polynodes
|
||||
ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes)
|
||||
{
|
||||
// collect ordering points
|
||||
Points ordering_points;
|
||||
ordering_points.reserve(nodes.size());
|
||||
|
||||
for (const ClipperLib::PolyNode *node : nodes)
|
||||
ordering_points.emplace_back(Point(node->Contour.front().X, node->Contour.front().Y));
|
||||
|
||||
ordering_points.emplace_back(
|
||||
Point(node->Contour.front().X, node->Contour.front().Y));
|
||||
|
||||
// perform the ordering
|
||||
ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes);
|
||||
|
||||
ClipperLib::PolyNodes ordered_nodes =
|
||||
chain_clipper_polynodes(ordering_points, nodes);
|
||||
|
||||
return ordered_nodes;
|
||||
}
|
||||
|
||||
enum class e_ordering {
|
||||
ORDER_POLYNODES,
|
||||
DONT_ORDER_POLYNODES
|
||||
};
|
||||
|
||||
template<e_ordering o>
|
||||
void foreach_node(const ClipperLib::PolyNodes &nodes,
|
||||
std::function<void(const ClipperLib::PolyNode *)> fn);
|
||||
|
||||
template<> void foreach_node<e_ordering::DONT_ORDER_POLYNODES>(
|
||||
const ClipperLib::PolyNodes & nodes,
|
||||
std::function<void(const ClipperLib::PolyNode *)> fn)
|
||||
static void traverse_pt_noholes(const ClipperLib::PolyNodes &nodes, Polygons *out)
|
||||
{
|
||||
for (auto &n : nodes) fn(n);
|
||||
foreach_node<e_ordering::ON>(nodes, [&out](const ClipperLib::PolyNode *node)
|
||||
{
|
||||
traverse_pt_noholes(node->Childs, out);
|
||||
out->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour));
|
||||
if (node->IsHole()) out->back().reverse(); // ccw
|
||||
});
|
||||
}
|
||||
|
||||
template<> void foreach_node<e_ordering::ORDER_POLYNODES>(
|
||||
const ClipperLib::PolyNodes & nodes,
|
||||
std::function<void(const ClipperLib::PolyNode *)> fn)
|
||||
{
|
||||
auto ordered_nodes = order_nodes(nodes);
|
||||
for (auto &n : ordered_nodes) fn(n);
|
||||
}
|
||||
|
||||
template<e_ordering o>
|
||||
void _traverse_pt(const ClipperLib::PolyNodes &nodes, Polygons *retval)
|
||||
static void traverse_pt_old(ClipperLib::PolyNodes &nodes, Polygons* retval)
|
||||
{
|
||||
/* use a nearest neighbor search to order these children
|
||||
TODO: supply start_near to chained_path() too? */
|
||||
|
||||
// collect ordering points
|
||||
Points ordering_points;
|
||||
ordering_points.reserve(nodes.size());
|
||||
for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
||||
Point p((*it)->Contour.front().X, (*it)->Contour.front().Y);
|
||||
ordering_points.push_back(p);
|
||||
}
|
||||
|
||||
// perform the ordering
|
||||
ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes);
|
||||
|
||||
// push results recursively
|
||||
foreach_node<o>(nodes, [&retval](const ClipperLib::PolyNode *node) {
|
||||
for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) {
|
||||
// traverse the next depth
|
||||
_traverse_pt<o>(node->Childs, retval);
|
||||
retval->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour));
|
||||
if (node->IsHole()) retval->back().reverse(); // ccw
|
||||
});
|
||||
traverse_pt_old((*it)->Childs, retval);
|
||||
retval->push_back(ClipperPath_to_Slic3rPolygon((*it)->Contour));
|
||||
if ((*it)->IsHole()) retval->back().reverse(); // ccw
|
||||
}
|
||||
}
|
||||
|
||||
template<e_ordering o>
|
||||
void _traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *retval)
|
||||
Polygons union_pt_chained(const Polygons &subject, bool safety_offset_)
|
||||
{
|
||||
if (!retval || !tree) return;
|
||||
ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
|
||||
|
||||
ExPolygons &retv = *retval;
|
||||
Polygons retval;
|
||||
traverse_pt_old(polytree.Childs, &retval);
|
||||
return retval;
|
||||
|
||||
std::function<void(const ClipperLib::PolyNode*, ExPolygon&)> hole_fn;
|
||||
// TODO: This needs to be tested:
|
||||
// ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
|
||||
|
||||
auto contour_fn = [&retv, &hole_fn](const ClipperLib::PolyNode *pptr) {
|
||||
ExPolygon poly;
|
||||
poly.contour.points = ClipperPath_to_Slic3rPolygon(pptr->Contour);
|
||||
auto fn = std::bind(hole_fn, std::placeholders::_1, poly);
|
||||
foreach_node<o>(pptr->Childs, fn);
|
||||
retv.push_back(poly);
|
||||
};
|
||||
|
||||
hole_fn = [&contour_fn](const ClipperLib::PolyNode *pptr, ExPolygon& poly)
|
||||
{
|
||||
poly.holes.emplace_back();
|
||||
poly.holes.back().points = ClipperPath_to_Slic3rPolygon(pptr->Contour);
|
||||
foreach_node<o>(pptr->Childs, contour_fn);
|
||||
};
|
||||
|
||||
contour_fn(tree);
|
||||
}
|
||||
|
||||
template<e_ordering o>
|
||||
void _traverse_pt(const ClipperLib::PolyNodes &nodes, ExPolygons *retval)
|
||||
{
|
||||
// Here is the actual traverse
|
||||
foreach_node<o>(nodes, [&retval](const ClipperLib::PolyNode *node) {
|
||||
_traverse_pt<o>(node, retval);
|
||||
});
|
||||
}
|
||||
|
||||
void traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *retval)
|
||||
{
|
||||
_traverse_pt<e_ordering::ORDER_POLYNODES>(tree, retval);
|
||||
}
|
||||
|
||||
void traverse_pt_unordered(const ClipperLib::PolyNode *tree, ExPolygons *retval)
|
||||
{
|
||||
_traverse_pt<e_ordering::DONT_ORDER_POLYNODES>(tree, retval);
|
||||
}
|
||||
|
||||
void traverse_pt(const ClipperLib::PolyNodes &nodes, Polygons *retval)
|
||||
{
|
||||
_traverse_pt<e_ordering::ORDER_POLYNODES>(nodes, retval);
|
||||
}
|
||||
|
||||
void traverse_pt(const ClipperLib::PolyNodes &nodes, ExPolygons *retval)
|
||||
{
|
||||
_traverse_pt<e_ordering::ORDER_POLYNODES>(nodes, retval);
|
||||
}
|
||||
|
||||
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Polygons *retval)
|
||||
{
|
||||
_traverse_pt<e_ordering::DONT_ORDER_POLYNODES>(nodes, retval);
|
||||
}
|
||||
|
||||
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, ExPolygons *retval)
|
||||
{
|
||||
_traverse_pt<e_ordering::DONT_ORDER_POLYNODES>(nodes, retval);
|
||||
// Polygons retval;
|
||||
// traverse_pt_noholes(polytree.Childs, &retval);
|
||||
// return retval;
|
||||
}
|
||||
|
||||
Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear)
|
||||
|
|
|
|||
|
|
@ -214,7 +214,6 @@ inline Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject, bool safety_
|
|||
return _clipper_ex(ClipperLib::ctUnion, to_polygons(subject), Slic3r::Polygons(), safety_offset_);
|
||||
}
|
||||
|
||||
|
||||
ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject, bool safety_offset_ = false);
|
||||
ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject, bool safety_offset_ = false);
|
||||
ClipperLib::PolyTree union_pt(Slic3r::Polygons &&subject, bool safety_offset_ = false);
|
||||
|
|
@ -222,13 +221,95 @@ ClipperLib::PolyTree union_pt(Slic3r::ExPolygons &&subject, bool safety_offset_
|
|||
|
||||
Slic3r::Polygons union_pt_chained(const Slic3r::Polygons &subject, bool safety_offset_ = false);
|
||||
|
||||
void traverse_pt(const ClipperLib::PolyNodes &nodes, Slic3r::Polygons *retval);
|
||||
void traverse_pt(const ClipperLib::PolyNodes &nodes, Slic3r::ExPolygons *retval);
|
||||
void traverse_pt(const ClipperLib::PolyNode *tree, Slic3r::ExPolygons *retval);
|
||||
ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes);
|
||||
|
||||
// Implementing generalized loop (foreach) over a list of nodes which can be
|
||||
// ordered or unordered (performance gain) based on template parameter
|
||||
enum class e_ordering {
|
||||
ON,
|
||||
OFF
|
||||
};
|
||||
|
||||
// Create a template struct, template functions can not be partially specialized
|
||||
template<e_ordering o, class Fn> struct _foreach_node {
|
||||
void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn);
|
||||
};
|
||||
|
||||
// Specialization with NO ordering
|
||||
template<class Fn> struct _foreach_node<e_ordering::OFF, Fn> {
|
||||
void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn)
|
||||
{
|
||||
for (auto &n : nodes) fn(n);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization with ordering
|
||||
template<class Fn> struct _foreach_node<e_ordering::ON, Fn> {
|
||||
void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn)
|
||||
{
|
||||
auto ordered_nodes = order_nodes(nodes);
|
||||
for (auto &n : nodes) fn(n);
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper function for the foreach_node which can deduce arguments automatically
|
||||
template<e_ordering o, class Fn>
|
||||
void foreach_node(const ClipperLib::PolyNodes &nodes, Fn &&fn)
|
||||
{
|
||||
_foreach_node<o, Fn>()(nodes, std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
// Collecting polygons of the tree into a list of Polygons, holes have clockwise
|
||||
// orientation.
|
||||
template<e_ordering ordering = e_ordering::OFF>
|
||||
void traverse_pt(const ClipperLib::PolyNode *tree, Polygons *out)
|
||||
{
|
||||
if (!tree) return; // terminates recursion
|
||||
|
||||
// Push the contour of the current level
|
||||
out->emplace_back(ClipperPath_to_Slic3rPolygon(tree->Contour));
|
||||
|
||||
// Do the recursion for all the children.
|
||||
traverse_pt<ordering>(tree->Childs, out);
|
||||
}
|
||||
|
||||
// Collecting polygons of the tree into a list of ExPolygons.
|
||||
template<e_ordering ordering = e_ordering::OFF>
|
||||
void traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *out)
|
||||
{
|
||||
if (!tree) return;
|
||||
else if(tree->IsHole()) {
|
||||
// Levels of holes are skipped and handled together with the
|
||||
// contour levels.
|
||||
traverse_pt<ordering>(tree->Childs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
ExPolygon level;
|
||||
level.contour = ClipperPath_to_Slic3rPolygon(tree->Contour);
|
||||
|
||||
foreach_node<ordering>(tree->Childs,
|
||||
[out, &level] (const ClipperLib::PolyNode *node) {
|
||||
|
||||
// Holes are collected here.
|
||||
level.holes.emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour));
|
||||
|
||||
// By doing a recursion, a new level expoly is created with the contour
|
||||
// and holes of the lower level. Doing this for all the childs.
|
||||
traverse_pt<ordering>(node->Childs, out);
|
||||
});
|
||||
|
||||
out->emplace_back(level);
|
||||
}
|
||||
|
||||
template<e_ordering o = e_ordering::OFF, class ExOrJustPolygons>
|
||||
void traverse_pt(const ClipperLib::PolyNodes &nodes, ExOrJustPolygons *retval)
|
||||
{
|
||||
foreach_node<o>(nodes, [&retval](const ClipperLib::PolyNode *node) {
|
||||
traverse_pt<o>(node, retval);
|
||||
});
|
||||
}
|
||||
|
||||
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Slic3r::Polygons *retval);
|
||||
void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Slic3r::ExPolygons *retval);
|
||||
void traverse_pt_unordered(const ClipperLib::PolyNode *tree, Slic3r::ExPolygons *retval);
|
||||
|
||||
/* OTHER */
|
||||
Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject, bool preserve_collinear = false);
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ void ConfigBase::load_from_gcode_file(const std::string &file)
|
|||
}
|
||||
ifs.seekg(0, ifs.end);
|
||||
auto file_length = ifs.tellg();
|
||||
auto data_length = std::min<std::fstream::streampos>(65535, file_length);
|
||||
auto data_length = std::min<std::fstream::pos_type>(65535, file_length);
|
||||
ifs.seekg(file_length - data_length, ifs.beg);
|
||||
std::vector<char> data(size_t(data_length) + 1, 0);
|
||||
ifs.read(data.data(), data_length);
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
|
|||
float l2 = (pthis - pprev).squaredNorm();
|
||||
if (l2 < dist_min2) {
|
||||
float l = sqrt(l2);
|
||||
int jprev = exchange(j, prev_idx_modulo(j, contour));
|
||||
int jprev = std::exchange(j, prev_idx_modulo(j, contour));
|
||||
while (j != i) {
|
||||
const Vec2f pp = contour[j].cast<float>();
|
||||
const float lthis = (pp - pprev).norm();
|
||||
|
|
@ -487,7 +487,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
|
|||
prev = use_min ? std::min(prev, compensation[j]) : compensation[j];
|
||||
pprev = pp;
|
||||
l = lnext;
|
||||
jprev = exchange(j, prev_idx_modulo(j, contour));
|
||||
jprev = std::exchange(j, prev_idx_modulo(j, contour));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,7 +497,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
|
|||
l2 = (pprev - pthis).squaredNorm();
|
||||
if (l2 < dist_min2) {
|
||||
float l = sqrt(l2);
|
||||
int jprev = exchange(j, next_idx_modulo(j, contour));
|
||||
int jprev = std::exchange(j, next_idx_modulo(j, contour));
|
||||
while (j != i) {
|
||||
const Vec2f pp = contour[j].cast<float>();
|
||||
const float lthis = (pp - pprev).norm();
|
||||
|
|
@ -512,7 +512,7 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
|
|||
next = use_min ? std::min(next, compensation[j]) : compensation[j];
|
||||
pprev = pp;
|
||||
l = lnext;
|
||||
jprev = exchange(j, next_idx_modulo(j, contour));
|
||||
jprev = std::exchange(j, next_idx_modulo(j, contour));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,12 @@ namespace pt = boost::property_tree;
|
|||
// VERSION NUMBERS
|
||||
// 0 : .3mf, files saved by older slic3r or other applications. No version definition in them.
|
||||
// 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files.
|
||||
// 2 : Meshes saved in their local system; Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file.
|
||||
const unsigned int VERSION_3MF = 2;
|
||||
// 2 : Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file, meshes transformed back to their coordinate system on loading.
|
||||
// WARNING !! -> the version number has been rolled back to 1
|
||||
// the next change should use 3
|
||||
const unsigned int VERSION_3MF = 1;
|
||||
// Allow loading version 2 file as well.
|
||||
const unsigned int VERSION_3MF_COMPATIBLE = 2;
|
||||
const char* SLIC3RPE_3MF_VERSION = "slic3rpe:Version3mf"; // definition of the metadata name saved into .model file
|
||||
|
||||
const std::string MODEL_FOLDER = "3D/";
|
||||
|
|
@ -52,7 +56,7 @@ const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights
|
|||
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml";
|
||||
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
|
||||
const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";
|
||||
const std::string CUSTOM_GCODE_PER_HEIGHT_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_height.xml";
|
||||
const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml";
|
||||
|
||||
const char* MODEL_TAG = "model";
|
||||
const char* RESOURCES_TAG = "resources";
|
||||
|
|
@ -422,7 +426,7 @@ namespace Slic3r {
|
|||
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||
void _extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||
|
||||
void _extract_custom_gcode_per_height_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||
void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||
|
||||
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
|
||||
bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
|
||||
|
|
@ -638,10 +642,10 @@ namespace Slic3r {
|
|||
// extract slic3r print config file
|
||||
_extract_print_config_from_archive(archive, stat, config, filename);
|
||||
}
|
||||
if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_HEIGHT_FILE))
|
||||
if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_PRINT_Z_FILE))
|
||||
{
|
||||
// extract slic3r layer config ranges file
|
||||
_extract_custom_gcode_per_height_from_archive(archive, stat);
|
||||
_extract_custom_gcode_per_print_z_from_archive(archive, stat);
|
||||
}
|
||||
else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE))
|
||||
{
|
||||
|
|
@ -1163,7 +1167,7 @@ namespace Slic3r {
|
|||
return true;
|
||||
}
|
||||
|
||||
void _3MF_Importer::_extract_custom_gcode_per_height_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
|
||||
void _3MF_Importer::_extract_custom_gcode_per_print_z_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
|
||||
{
|
||||
if (stat.m_uncomp_size > 0)
|
||||
{
|
||||
|
|
@ -1178,24 +1182,23 @@ namespace Slic3r {
|
|||
pt::ptree main_tree;
|
||||
pt::read_xml(iss, main_tree);
|
||||
|
||||
if (main_tree.front().first != "custom_gcodes_per_height")
|
||||
if (main_tree.front().first != "custom_gcodes_per_print_z")
|
||||
return;
|
||||
pt::ptree code_tree = main_tree.front().second;
|
||||
|
||||
if (!m_model->custom_gcode_per_height.empty())
|
||||
m_model->custom_gcode_per_height.clear();
|
||||
m_model->custom_gcode_per_print_z.clear();
|
||||
|
||||
for (const auto& code : code_tree)
|
||||
{
|
||||
if (code.first != "code")
|
||||
continue;
|
||||
pt::ptree tree = code.second;
|
||||
double height = tree.get<double>("<xmlattr>.height");
|
||||
std::string gcode = tree.get<std::string>("<xmlattr>.gcode");
|
||||
int extruder = tree.get<int>("<xmlattr>.extruder");
|
||||
std::string color = tree.get<std::string>("<xmlattr>.color");
|
||||
double print_z = tree.get<double> ("<xmlattr>.print_z" );
|
||||
std::string gcode = tree.get<std::string> ("<xmlattr>.gcode" );
|
||||
int extruder = tree.get<int> ("<xmlattr>.extruder" );
|
||||
std::string color = tree.get<std::string> ("<xmlattr>.color" );
|
||||
|
||||
m_model->custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color)) ;
|
||||
m_model->custom_gcode_per_print_z.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1611,7 +1614,7 @@ namespace Slic3r {
|
|||
{
|
||||
m_version = (unsigned int)atoi(m_curr_characters.c_str());
|
||||
|
||||
if (m_check_version && (m_version > VERSION_3MF))
|
||||
if (m_check_version && (m_version > VERSION_3MF_COMPATIBLE))
|
||||
{
|
||||
// std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
|
||||
// throw version_error(msg.c_str());
|
||||
|
|
@ -1797,20 +1800,19 @@ namespace Slic3r {
|
|||
return false;
|
||||
}
|
||||
|
||||
Slic3r::Geometry::Transformation transform;
|
||||
if (m_version > 1)
|
||||
Transform3d volume_matrix_to_object = Transform3d::Identity();
|
||||
bool has_transform = false;
|
||||
// extract the volume transformation from the volume's metadata, if present
|
||||
for (const Metadata& metadata : volume_data.metadata)
|
||||
{
|
||||
// extract the volume transformation from the volume's metadata, if present
|
||||
for (const Metadata& metadata : volume_data.metadata)
|
||||
if (metadata.key == MATRIX_KEY)
|
||||
{
|
||||
if (metadata.key == MATRIX_KEY)
|
||||
{
|
||||
transform.set_from_string(metadata.value);
|
||||
break;
|
||||
}
|
||||
volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value);
|
||||
has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Transform3d inv_matrix = transform.get_matrix().inverse();
|
||||
Transform3d inv_matrix = volume_matrix_to_object.inverse();
|
||||
|
||||
// splits volume out of imported geometry
|
||||
TriangleMesh triangle_mesh;
|
||||
|
|
@ -1831,10 +1833,10 @@ namespace Slic3r {
|
|||
{
|
||||
unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
|
||||
Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
|
||||
if (m_version > 1)
|
||||
facet.vertex[v] = has_transform ?
|
||||
// revert the vertices to the original mesh reference system
|
||||
vertex = (inv_matrix * vertex.cast<double>()).cast<float>();
|
||||
::memcpy(facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float));
|
||||
(inv_matrix * vertex.cast<double>()).cast<float>() :
|
||||
vertex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1843,8 +1845,8 @@ namespace Slic3r {
|
|||
|
||||
ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
|
||||
// apply the volume matrix taken from the metadata, if present
|
||||
if (m_version > 1)
|
||||
volume->set_transformation(transform);
|
||||
if (has_transform)
|
||||
volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object));
|
||||
volume->calculate_convex_hull();
|
||||
|
||||
// apply the remaining volume's metadata
|
||||
|
|
@ -1985,7 +1987,7 @@ namespace Slic3r {
|
|||
bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
|
||||
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
|
||||
bool _add_custom_gcode_per_height_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||
};
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -2096,9 +2098,9 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
|
||||
// Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_height.xml").
|
||||
// Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml").
|
||||
// All custom gcode per height of whole Model are stored here
|
||||
if (!_add_custom_gcode_per_height_file_to_archive(archive, model))
|
||||
if (!_add_custom_gcode_per_print_z_file_to_archive(archive, model))
|
||||
{
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(filename);
|
||||
|
|
@ -2622,6 +2624,9 @@ namespace Slic3r {
|
|||
bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data)
|
||||
{
|
||||
std::stringstream stream;
|
||||
// Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
|
||||
// when loaded as accurately as possible.
|
||||
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
|
||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
stream << "<" << CONFIG_TAG << ">\n";
|
||||
|
||||
|
|
@ -2719,20 +2724,20 @@ namespace Slic3r {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool _3MF_Exporter::_add_custom_gcode_per_height_file_to_archive( mz_zip_archive& archive, Model& model)
|
||||
bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archive& archive, Model& model)
|
||||
{
|
||||
std::string out = "";
|
||||
|
||||
if (!model.custom_gcode_per_height.empty())
|
||||
if (!model.custom_gcode_per_print_z.empty())
|
||||
{
|
||||
pt::ptree tree;
|
||||
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
|
||||
pt::ptree& main_tree = tree.add("custom_gcodes_per_print_z", "");
|
||||
|
||||
for (const Model::CustomGCode& code : model.custom_gcode_per_height)
|
||||
for (const Model::CustomGCode& code : model.custom_gcode_per_print_z)
|
||||
{
|
||||
pt::ptree& code_tree = main_tree.add("code", "");
|
||||
// store minX and maxZ
|
||||
code_tree.put("<xmlattr>.height" , code.height );
|
||||
code_tree.put("<xmlattr>.print_z" , code.print_z );
|
||||
code_tree.put("<xmlattr>.gcode" , code.gcode );
|
||||
code_tree.put("<xmlattr>.extruder" , code.extruder );
|
||||
code_tree.put("<xmlattr>.color" , code.color );
|
||||
|
|
@ -2751,9 +2756,9 @@ bool _3MF_Exporter::_add_custom_gcode_per_height_file_to_archive( mz_zip_archive
|
|||
|
||||
if (!out.empty())
|
||||
{
|
||||
if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_HEIGHT_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
|
||||
if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_PRINT_Z_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
|
||||
{
|
||||
add_error("Unable to add custom Gcodes per height file to archive");
|
||||
add_error("Unable to add custom Gcodes per print_z file to archive");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,11 @@ namespace pt = boost::property_tree;
|
|||
// Added x and y components of rotation
|
||||
// Added x, y and z components of scale
|
||||
// Added x, y and z components of mirror
|
||||
// 3 : Meshes saved in their local system; Added volumes' matrices and source data
|
||||
const unsigned int VERSION_AMF = 3;
|
||||
// 3 : Added volumes' matrices and source data, meshes transformed back to their coordinate system on loading.
|
||||
// WARNING !! -> the version number has been rolled back to 2
|
||||
// the next change should use 4
|
||||
const unsigned int VERSION_AMF = 2;
|
||||
const unsigned int VERSION_AMF_COMPATIBLE = 3;
|
||||
const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version";
|
||||
|
||||
const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config";
|
||||
|
|
@ -228,6 +231,8 @@ struct AMFParserContext
|
|||
ModelVolume *m_volume;
|
||||
// Faces collected for the current m_volume.
|
||||
std::vector<int> m_volume_facets;
|
||||
// Transformation matrix of a volume mesh from its coordinate system to Object's coordinate system.
|
||||
Transform3d m_volume_transform;
|
||||
// Current material allocated for an amf/metadata subtree.
|
||||
ModelMaterial *m_material;
|
||||
// Current instance allocated for an amf/constellation/instance subtree.
|
||||
|
|
@ -319,6 +324,7 @@ void AMFParserContext::startElement(const char *name, const char **atts)
|
|||
else if (strcmp(name, "volume") == 0) {
|
||||
assert(! m_volume);
|
||||
m_volume = m_object->add_volume(TriangleMesh());
|
||||
m_volume_transform = Transform3d::Identity();
|
||||
node_type_new = NODE_TYPE_VOLUME;
|
||||
}
|
||||
} else if (m_path[2] == NODE_TYPE_INSTANCE) {
|
||||
|
|
@ -578,27 +584,25 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||
stl.stats.original_num_facets = stl.stats.number_of_facets;
|
||||
stl_allocate(&stl);
|
||||
|
||||
Slic3r::Geometry::Transformation transform;
|
||||
if (m_version > 2)
|
||||
transform = m_volume->get_transformation();
|
||||
|
||||
Transform3d inv_matrix = transform.get_matrix().inverse();
|
||||
|
||||
bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10);
|
||||
Transform3d inv_matrix = m_volume_transform.inverse();
|
||||
for (size_t i = 0; i < m_volume_facets.size();) {
|
||||
stl_facet &facet = stl.facet_start[i/3];
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
unsigned int tri_id = m_volume_facets[i++] * 3;
|
||||
Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
|
||||
if (m_version > 2)
|
||||
facet.vertex[v] = has_transform ?
|
||||
// revert the vertices to the original mesh reference system
|
||||
vertex = (inv_matrix * vertex.cast<double>()).cast<float>();
|
||||
::memcpy((void*)facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float));
|
||||
(inv_matrix * vertex.cast<double>()).cast<float>() :
|
||||
vertex;
|
||||
}
|
||||
}
|
||||
}
|
||||
stl_get_size(&stl);
|
||||
mesh.repair();
|
||||
m_volume->set_mesh(std::move(mesh));
|
||||
if (has_transform)
|
||||
m_volume->set_transformation(m_volume_transform);
|
||||
if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART))
|
||||
{
|
||||
m_volume->source.object_idx = (int)m_model.objects.size() - 1;
|
||||
|
|
@ -637,7 +641,7 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||
int extruder = atoi(m_value[2].c_str());
|
||||
const std::string& color = m_value[3];
|
||||
|
||||
m_model.custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color));
|
||||
m_model.custom_gcode_per_print_z.push_back(Model::CustomGCode{height, gcode, extruder, color});
|
||||
|
||||
for (std::string& val: m_value)
|
||||
val.clear();
|
||||
|
|
@ -718,9 +722,7 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||
m_volume->set_type(ModelVolume::type_from_string(m_value[1]));
|
||||
}
|
||||
else if (strcmp(opt_key, "matrix") == 0) {
|
||||
Geometry::Transformation transform;
|
||||
transform.set_from_string(m_value[1]);
|
||||
m_volume->set_transformation(transform);
|
||||
m_volume_transform = Slic3r::Geometry::transform3d_from_string(m_value[1]);
|
||||
}
|
||||
else if (strcmp(opt_key, "source_file") == 0) {
|
||||
m_volume->source.input_file = m_value[1];
|
||||
|
|
@ -910,7 +912,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
|
|||
|
||||
ctx.endDocument();
|
||||
|
||||
if (check_version && (ctx.m_version > VERSION_AMF))
|
||||
if (check_version && (ctx.m_version > VERSION_AMF_COMPATIBLE))
|
||||
{
|
||||
// std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
|
||||
// throw std::runtime_error(msg.c_str());
|
||||
|
|
@ -1146,6 +1148,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.matrix\">";
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
|
||||
for (int r = 0; r < 4; ++r)
|
||||
{
|
||||
for (int c = 0; c < 4; ++c)
|
||||
|
|
@ -1165,6 +1168,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
stream << " <metadata type=\"slic3r.source_offset_y\">" << volume->source.mesh_offset(1) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_offset_z\">" << volume->source.mesh_offset(2) << "</metadata>\n";
|
||||
}
|
||||
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
for (size_t i = 0; i < its.indices.size(); ++i) {
|
||||
stream << " <triangle>\n";
|
||||
|
|
@ -1221,21 +1225,21 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
stream << " </constellation>\n";
|
||||
}
|
||||
|
||||
if (!model->custom_gcode_per_height.empty())
|
||||
if (!model->custom_gcode_per_print_z.empty())
|
||||
{
|
||||
std::string out = "";
|
||||
pt::ptree tree;
|
||||
|
||||
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
|
||||
|
||||
for (const Model::CustomGCode& code : model->custom_gcode_per_height)
|
||||
for (const Model::CustomGCode& code : model->custom_gcode_per_print_z)
|
||||
{
|
||||
pt::ptree& code_tree = main_tree.add("code", "");
|
||||
// store minX and maxZ
|
||||
code_tree.put("<xmlattr>.height", code.height);
|
||||
code_tree.put("<xmlattr>.gcode", code.gcode);
|
||||
code_tree.put("<xmlattr>.extruder", code.extruder);
|
||||
code_tree.put("<xmlattr>.color", code.color);
|
||||
code_tree.put("<xmlattr>.print_z" , code.print_z );
|
||||
code_tree.put("<xmlattr>.gcode" , code.gcode );
|
||||
code_tree.put("<xmlattr>.extruder" , code.extruder );
|
||||
code_tree.put("<xmlattr>.color" , code.color );
|
||||
}
|
||||
|
||||
if (!tree.empty())
|
||||
|
|
|
|||
|
|
@ -936,7 +936,7 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
|
||||
// Initialize custom gcode
|
||||
Model* model = print.get_object(0)->model_object()->get_model();
|
||||
m_custom_g_code_heights = model->custom_gcode_per_height;
|
||||
m_custom_gcode_per_print_z = model->custom_gcode_per_print_z;
|
||||
|
||||
// Initialize autospeed.
|
||||
{
|
||||
|
|
@ -1124,20 +1124,22 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
}
|
||||
print.throw_if_canceled();
|
||||
|
||||
// #ys_FIXME_no_exported_codes
|
||||
/*
|
||||
/* To avoid change filament for non-used extruder for Multi-material,
|
||||
* check model->custom_gcode_per_height using tool_ordering values
|
||||
* */
|
||||
if (!m_custom_g_code_heights. empty())
|
||||
* check model->custom_gcode_per_print_z using tool_ordering values
|
||||
* /
|
||||
if (!m_custom_gcode_per_print_z. empty())
|
||||
{
|
||||
bool delete_executed = false;
|
||||
auto it = m_custom_g_code_heights.end();
|
||||
while (it != m_custom_g_code_heights.begin())
|
||||
auto it = m_custom_gcode_per_print_z.end();
|
||||
while (it != m_custom_gcode_per_print_z.begin())
|
||||
{
|
||||
--it;
|
||||
if (it->gcode != ColorChangeCode)
|
||||
continue;
|
||||
|
||||
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->height));
|
||||
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->print_z));
|
||||
|
||||
bool used_extruder = false;
|
||||
for (; it_layer_tools != tool_ordering.end(); it_layer_tools++)
|
||||
|
|
@ -1154,16 +1156,16 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
|
||||
/* If we are there, current extruder wouldn't be used,
|
||||
* so this color change is a redundant move.
|
||||
* Delete this item from m_custom_g_code_heights
|
||||
* */
|
||||
it = m_custom_g_code_heights.erase(it);
|
||||
* Delete this item from m_custom_gcode_per_print_z
|
||||
* /
|
||||
it = m_custom_gcode_per_print_z.erase(it);
|
||||
delete_executed = true;
|
||||
}
|
||||
|
||||
if (delete_executed)
|
||||
model->custom_gcode_per_height = m_custom_g_code_heights;
|
||||
model->custom_gcode_per_print_z = m_custom_gcode_per_print_z;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
m_cooling_buffer->set_current_extruder(initial_extruder_id);
|
||||
|
||||
|
|
@ -1461,7 +1463,7 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
dst.first += buf;
|
||||
++ dst.second;
|
||||
};
|
||||
print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>(extruder.id(), (float)used_filament));
|
||||
print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>{extruder.id(), (float)used_filament});
|
||||
append(out_filament_used_mm, "%.1lf", used_filament);
|
||||
append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001);
|
||||
if (filament_weight > 0.) {
|
||||
|
|
@ -1835,15 +1837,15 @@ void GCode::process_layer(
|
|||
std::string custom_code = "";
|
||||
std::string pause_print_msg = "";
|
||||
int m600_before_extruder = -1;
|
||||
while (!m_custom_g_code_heights.empty() && m_custom_g_code_heights.front().height-EPSILON < layer.print_z) {
|
||||
custom_code = m_custom_g_code_heights.front().gcode;
|
||||
while (!m_custom_gcode_per_print_z.empty() && m_custom_gcode_per_print_z.front().print_z - EPSILON < layer.print_z) {
|
||||
custom_code = m_custom_gcode_per_print_z.front().gcode;
|
||||
|
||||
if (custom_code == ColorChangeCode && m_custom_g_code_heights.front().extruder > 0)
|
||||
m600_before_extruder = m_custom_g_code_heights.front().extruder - 1;
|
||||
if (custom_code == ColorChangeCode && m_custom_gcode_per_print_z.front().extruder > 0)
|
||||
m600_before_extruder = m_custom_gcode_per_print_z.front().extruder - 1;
|
||||
if (custom_code == PausePrintCode)
|
||||
pause_print_msg = m_custom_g_code_heights.front().color;
|
||||
pause_print_msg = m_custom_gcode_per_print_z.front().color;
|
||||
|
||||
m_custom_g_code_heights.erase(m_custom_g_code_heights.begin());
|
||||
m_custom_gcode_per_print_z.erase(m_custom_gcode_per_print_z.begin());
|
||||
colorprint_change = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ protected:
|
|||
* Updated before the export and erased during the process,
|
||||
* so no toolchange occurs twice.
|
||||
* */
|
||||
std::vector<Model::CustomGCode> m_custom_g_code_heights;
|
||||
std::vector<Model::CustomGCode> m_custom_gcode_per_print_z;
|
||||
|
||||
// Time estimators
|
||||
GCodeTimeEstimator m_normal_time_estimator;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
// Additional Codes which can be set by user using DoubleSlider
|
||||
static constexpr char ColorChangeCode[] = "M600";
|
||||
static constexpr char PausePrintCode[] = "M601";
|
||||
static constexpr char ExtruderChangeCode[] = "tool_change";
|
||||
|
||||
class GCodeWriter {
|
||||
public:
|
||||
GCodeConfig config;
|
||||
|
|
|
|||
|
|
@ -1187,14 +1187,12 @@ MedialAxis::validate_edge(const VD::edge_type* edge)
|
|||
return true;
|
||||
}
|
||||
|
||||
const Line&
|
||||
MedialAxis::retrieve_segment(const VD::cell_type* cell) const
|
||||
const Line& MedialAxis::retrieve_segment(const VD::cell_type* cell) const
|
||||
{
|
||||
return this->lines[cell->source_index()];
|
||||
}
|
||||
|
||||
const Point&
|
||||
MedialAxis::retrieve_endpoint(const VD::cell_type* cell) const
|
||||
const Point& MedialAxis::retrieve_endpoint(const VD::cell_type* cell) const
|
||||
{
|
||||
const Line& line = this->retrieve_segment(cell);
|
||||
if (cell->source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT) {
|
||||
|
|
@ -1208,11 +1206,8 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation, const
|
|||
{
|
||||
transform = Transform3d::Identity();
|
||||
transform.translate(translation);
|
||||
transform.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
|
||||
transform.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY()));
|
||||
transform.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX()));
|
||||
transform.scale(scale);
|
||||
transform.scale(mirror);
|
||||
transform.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rotation(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rotation(0), Vec3d::UnitX()));
|
||||
transform.scale(scale.cwiseProduct(mirror));
|
||||
}
|
||||
|
||||
Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale, const Vec3d& mirror)
|
||||
|
|
@ -1420,32 +1415,6 @@ void Transformation::set_from_transform(const Transform3d& transform)
|
|||
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
|
||||
}
|
||||
|
||||
void Transformation::set_from_string(const std::string& transform_str)
|
||||
{
|
||||
Transform3d transform = Transform3d::Identity();
|
||||
|
||||
if (!transform_str.empty())
|
||||
{
|
||||
std::vector<std::string> mat_elements_str;
|
||||
boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on);
|
||||
|
||||
unsigned int size = (unsigned int)mat_elements_str.size();
|
||||
if (size == 16)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (unsigned int r = 0; r < 4; ++r)
|
||||
{
|
||||
for (unsigned int c = 0; c < 4; ++c)
|
||||
{
|
||||
transform(r, c) = ::atof(mat_elements_str[i++].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_from_transform(transform);
|
||||
}
|
||||
|
||||
void Transformation::reset()
|
||||
{
|
||||
m_offset = Vec3d::Zero();
|
||||
|
|
@ -1536,6 +1505,33 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
|
|||
return out;
|
||||
}
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
Transform3d transform3d_from_string(const std::string& transform_str)
|
||||
{
|
||||
Transform3d transform = Transform3d::Identity();
|
||||
|
||||
if (!transform_str.empty())
|
||||
{
|
||||
std::vector<std::string> mat_elements_str;
|
||||
boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on);
|
||||
|
||||
unsigned int size = (unsigned int)mat_elements_str.size();
|
||||
if (size == 16)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (unsigned int r = 0; r < 4; ++r)
|
||||
{
|
||||
for (unsigned int c = 0; c < 4; ++c)
|
||||
{
|
||||
transform(r, c) = ::atof(mat_elements_str[i++].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
||||
{
|
||||
return
|
||||
|
|
|
|||
|
|
@ -360,7 +360,6 @@ public:
|
|||
void set_mirror(Axis axis, double mirror);
|
||||
|
||||
void set_from_transform(const Transform3d& transform);
|
||||
void set_from_string(const std::string& transform_str);
|
||||
|
||||
void reset();
|
||||
|
||||
|
|
@ -385,6 +384,9 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
extern Transform3d transform3d_from_string(const std::string& transform_str);
|
||||
|
||||
// Rotation when going from the first coordinate system with rotation rot_xyz_from applied
|
||||
// to a coordinate system with rot_xyz_to applied.
|
||||
extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "SVG.hpp"
|
||||
#include <Eigen/Dense>
|
||||
#include "GCodeWriter.hpp"
|
||||
#include "GCode/PreviewData.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
@ -43,7 +45,7 @@ Model& Model::assign_copy(const Model &rhs)
|
|||
}
|
||||
|
||||
// copy custom code per height
|
||||
this->custom_gcode_per_height = rhs.custom_gcode_per_height;
|
||||
this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +66,7 @@ Model& Model::assign_copy(Model &&rhs)
|
|||
rhs.objects.clear();
|
||||
|
||||
// copy custom code per height
|
||||
this->custom_gcode_per_height = rhs.custom_gcode_per_height;
|
||||
this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -124,6 +126,8 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
|
|||
if (add_default_instances)
|
||||
model.add_default_instances();
|
||||
|
||||
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
@ -159,6 +163,8 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
|
|||
if (add_default_instances)
|
||||
model.add_default_instances();
|
||||
|
||||
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
@ -595,16 +601,15 @@ std::string Model::propose_export_file_name_and_path(const std::string &new_exte
|
|||
std::vector<std::pair<double, DynamicPrintConfig>> Model::get_custom_tool_changes(double default_layer_height, size_t num_extruders) const
|
||||
{
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes;
|
||||
if (!custom_gcode_per_height.empty()) {
|
||||
for (const CustomGCode& custom_gcode : custom_gcode_per_height)
|
||||
if (custom_gcode.gcode == ExtruderChangeCode) {
|
||||
DynamicPrintConfig config;
|
||||
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
|
||||
config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder));
|
||||
// For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height
|
||||
custom_tool_changes.push_back({ custom_gcode.height - default_layer_height, config });
|
||||
}
|
||||
}
|
||||
for (const CustomGCode& custom_gcode : custom_gcode_per_print_z)
|
||||
if (custom_gcode.gcode == ExtruderChangeCode) {
|
||||
DynamicPrintConfig config;
|
||||
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
|
||||
config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder));
|
||||
// For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height
|
||||
custom_tool_changes.push_back({ custom_gcode.print_z - default_layer_height, config });
|
||||
}
|
||||
|
||||
return custom_tool_changes;
|
||||
}
|
||||
|
||||
|
|
@ -1304,6 +1309,8 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||
}
|
||||
|
||||
new_vol->set_offset(Vec3d::Zero());
|
||||
// reset the source to disable reload from disk
|
||||
new_vol->source = ModelVolume::Source();
|
||||
new_objects->emplace_back(new_object);
|
||||
delete mesh;
|
||||
}
|
||||
|
|
@ -1359,6 +1366,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
|||
model_volume->set_mirror(Vec3d(1., 1., 1.));
|
||||
// Move the reference point of the volume to compensate for the change of the instance trafo.
|
||||
model_volume->set_offset(volume_offset_correction * volume_trafo.get_offset());
|
||||
// reset the source to disable reload from disk
|
||||
model_volume->source = ModelVolume::Source();
|
||||
}
|
||||
|
||||
this->invalidate_bounding_box();
|
||||
|
|
@ -1670,6 +1679,8 @@ size_t ModelVolume::split(unsigned int max_extruders)
|
|||
this->calculate_convex_hull();
|
||||
// Assign a new unique ID, so that a new GLVolume will be generated.
|
||||
this->set_new_unique_id();
|
||||
// reset the source to disable reload from disk
|
||||
this->source = ModelVolume::Source();
|
||||
}
|
||||
else
|
||||
this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh)));
|
||||
|
|
@ -1940,6 +1951,30 @@ extern bool model_has_advanced_features(const Model &model)
|
|||
return false;
|
||||
}
|
||||
|
||||
extern void update_custom_gcode_per_print_z_from_config(std::vector<Model::CustomGCode>& custom_gcode_per_print_z, DynamicPrintConfig* config)
|
||||
{
|
||||
if (!config->has("colorprint_heights"))
|
||||
return;
|
||||
|
||||
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
|
||||
|
||||
const auto& colorprint_values = config->option<ConfigOptionFloats>("colorprint_heights")->values;
|
||||
|
||||
if (!colorprint_values.empty())
|
||||
{
|
||||
custom_gcode_per_print_z.clear();
|
||||
custom_gcode_per_print_z.reserve(colorprint_values.size());
|
||||
int i = 0;
|
||||
for (auto val : colorprint_values)
|
||||
custom_gcode_per_print_z.emplace_back(Model::CustomGCode{ val, ColorChangeCode, 1, colors[(++i)%7] });
|
||||
}
|
||||
|
||||
/* There is one and only place this configuration option is used now.
|
||||
* It wouldn't be used in the future, so erase it.
|
||||
* */
|
||||
config->erase("colorprint_heights");
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||
void check_model_ids_validity(const Model &model)
|
||||
|
|
|
|||
|
|
@ -470,6 +470,7 @@ public:
|
|||
|
||||
const Geometry::Transformation& get_transformation() const { return m_transformation; }
|
||||
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
|
||||
void set_transformation(const Transform3d &trafo) { m_transformation.set_from_transform(trafo); }
|
||||
|
||||
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
||||
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
||||
|
|
@ -753,33 +754,30 @@ public:
|
|||
// Extensions for color print
|
||||
struct CustomGCode
|
||||
{
|
||||
CustomGCode(double height, const std::string& code, int extruder, const std::string& color) :
|
||||
height(height), gcode(code), extruder(extruder), color(color) {}
|
||||
|
||||
bool operator<(const CustomGCode& other) const { return other.height > this->height; }
|
||||
bool operator<(const CustomGCode& other) const { return other.print_z > this->print_z; }
|
||||
bool operator==(const CustomGCode& other) const
|
||||
{
|
||||
return (other.height == this->height) &&
|
||||
(other.gcode == this->gcode) &&
|
||||
(other.extruder == this->extruder )&&
|
||||
(other.color == this->color );
|
||||
return (other.print_z == this->print_z ) &&
|
||||
(other.gcode == this->gcode ) &&
|
||||
(other.extruder == this->extruder ) &&
|
||||
(other.color == this->color );
|
||||
}
|
||||
bool operator!=(const CustomGCode& other) const
|
||||
{
|
||||
return (other.height != this->height) ||
|
||||
(other.gcode != this->gcode) ||
|
||||
(other.extruder != this->extruder )||
|
||||
(other.color != this->color );
|
||||
return (other.print_z != this->print_z ) ||
|
||||
(other.gcode != this->gcode ) ||
|
||||
(other.extruder != this->extruder ) ||
|
||||
(other.color != this->color );
|
||||
}
|
||||
|
||||
double height;
|
||||
double print_z;
|
||||
std::string gcode;
|
||||
int extruder; // 0 - "gcode" will be applied for whole print
|
||||
// else - "gcode" will be applied only for "extruder" print
|
||||
std::string color; // if gcode is equal to PausePrintCode,
|
||||
// this field is used for save a short message shown on Printer display
|
||||
};
|
||||
std::vector<CustomGCode> custom_gcode_per_height;
|
||||
std::vector<CustomGCode> custom_gcode_per_print_z;
|
||||
|
||||
// Default constructor assigns a new ID to the model.
|
||||
Model() { assert(this->id().valid()); }
|
||||
|
|
@ -845,7 +843,7 @@ public:
|
|||
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
|
||||
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
||||
|
||||
// from custom_gcode_per_height get just tool_change codes
|
||||
// from custom_gcode_per_print_z get just tool_change codes
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> get_custom_tool_changes(double default_layer_height, size_t num_extruders) const;
|
||||
|
||||
private:
|
||||
|
|
@ -881,6 +879,10 @@ extern bool model_volume_list_changed(const ModelObject &model_object_old, const
|
|||
extern bool model_has_multi_part_objects(const Model &model);
|
||||
// If the model has advanced features, then it cannot be processed in simple mode.
|
||||
extern bool model_has_advanced_features(const Model &model);
|
||||
/* If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer),
|
||||
* then model.custom_gcode_per_print_z should be updated considering this option
|
||||
* */
|
||||
extern void update_custom_gcode_per_print_z_from_config(std::vector<Model::CustomGCode>& custom_gcode_per_print_z, DynamicPrintConfig* config);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||
|
|
|
|||
|
|
@ -739,10 +739,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
model_object_status.emplace(model_object->id(), ModelObjectStatus::Old);
|
||||
|
||||
// But if custom gcode per layer height was changed
|
||||
if (m_model.custom_gcode_per_height != model.custom_gcode_per_height) {
|
||||
if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
|
||||
// we should stop background processing
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
m_model.custom_gcode_per_height = model.custom_gcode_per_height;
|
||||
m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
|
||||
}
|
||||
} else if (model_object_list_extended(m_model, model)) {
|
||||
// Add new objects. Their volumes and configs will be synchronized later.
|
||||
|
|
|
|||
|
|
@ -71,12 +71,6 @@ enum SLAPillarConnectionMode {
|
|||
slapcmDynamic
|
||||
};
|
||||
|
||||
// ys_FIXME ! may be, it's not a best place
|
||||
// Additional Codes which can be set by user using DoubleSlider
|
||||
static const std::string ColorChangeCode = "M600";
|
||||
static const std::string PausePrintCode = "M601";
|
||||
static const std::string ExtruderChangeCode = "tool_change";
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<PrinterTechnology>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
|
|
|
|||
|
|
@ -339,18 +339,15 @@ PadSkeleton divide_blueprint(const ExPolygons &bp)
|
|||
for (ClipperLib::PolyTree::PolyNode *node : ptree.Childs) {
|
||||
ExPolygon poly(ClipperPath_to_Slic3rPolygon(node->Contour));
|
||||
for (ClipperLib::PolyTree::PolyNode *child : node->Childs) {
|
||||
if (child->IsHole()) {
|
||||
poly.holes.emplace_back(
|
||||
ClipperPath_to_Slic3rPolygon(child->Contour));
|
||||
poly.holes.emplace_back(
|
||||
ClipperPath_to_Slic3rPolygon(child->Contour));
|
||||
|
||||
traverse_pt_unordered(child->Childs, &ret.inner);
|
||||
}
|
||||
else traverse_pt_unordered(child, &ret.inner);
|
||||
traverse_pt(child->Childs, &ret.inner);
|
||||
}
|
||||
|
||||
ret.outer.emplace_back(poly);
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -432,9 +429,11 @@ public:
|
|||
|
||||
ExPolygons fullpad = diff_ex(fullcvh, model_bp_sticks);
|
||||
|
||||
remove_redundant_parts(fullpad);
|
||||
|
||||
PadSkeleton divided = divide_blueprint(fullpad);
|
||||
|
||||
remove_redundant_parts(divided.outer);
|
||||
remove_redundant_parts(divided.inner);
|
||||
|
||||
outer = std::move(divided.outer);
|
||||
inner = std::move(divided.inner);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ std::vector<std::pair<size_t, bool>> chain_segments_closest_point(std::vector<En
|
|||
assert(next_idx < end_points.size());
|
||||
EndPointType &end_point = end_points[next_idx];
|
||||
end_point.chain_id = 1;
|
||||
out.emplace_back(next_idx / 2, (next_idx & 1) != 0);
|
||||
this_idx = next_idx ^ 1;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
|
|
@ -72,7 +73,7 @@ std::vector<std::pair<size_t, bool>> chain_segments_greedy_constrained_reversals
|
|||
else if (num_segments == 1)
|
||||
{
|
||||
// Just sort the end points so that the first point visited is closest to start_near.
|
||||
out.emplace_back(0, start_near != nullptr &&
|
||||
out.emplace_back(0, could_reverse_func(0) && start_near != nullptr &&
|
||||
(end_point_func(0, true) - *start_near).template cast<double>().squaredNorm() < (end_point_func(0, false) - *start_near).template cast<double>().squaredNorm());
|
||||
}
|
||||
else
|
||||
|
|
@ -999,13 +1000,13 @@ std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<Extrus
|
|||
auto segment_end_point = [&entities](size_t idx, bool first_point) -> const Point& { return first_point ? entities[idx]->first_point() : entities[idx]->last_point(); };
|
||||
auto could_reverse = [&entities](size_t idx) { const ExtrusionEntity *ee = entities[idx]; return ee->is_loop() || ee->can_reverse(); };
|
||||
std::vector<std::pair<size_t, bool>> out = chain_segments_greedy_constrained_reversals<Point, decltype(segment_end_point), decltype(could_reverse)>(segment_end_point, could_reverse, entities.size(), start_near);
|
||||
for (size_t i = 0; i < entities.size(); ++ i) {
|
||||
ExtrusionEntity *ee = entities[i];
|
||||
for (std::pair<size_t, bool> &segment : out) {
|
||||
ExtrusionEntity *ee = entities[segment.first];
|
||||
if (ee->is_loop())
|
||||
// Ignore reversals for loops, as the start point equals the end point.
|
||||
out[i].second = false;
|
||||
segment.second = false;
|
||||
// Is can_reverse() respected by the reversals?
|
||||
assert(entities[i]->can_reverse() || ! out[i].second);
|
||||
assert(ee->can_reverse() || ! segment.second);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,38 +224,14 @@ 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
|
||||
std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slicing_params, const ModelObject& object, float quality_factor)
|
||||
{
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// 1) Initialize the SlicingAdaptive class with the object meshes.
|
||||
SlicingAdaptive as;
|
||||
as.set_slicing_parameters(slicing_params);
|
||||
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();
|
||||
as.prepare(object);
|
||||
|
||||
// 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
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
double cusp_value = 0.2;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
std::vector<double> layer_height_profile;
|
||||
layer_height_profile.push_back(0.0);
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
|
|
@ -263,39 +239,41 @@ std::vector<coordf_t> layer_height_profile_adaptive(
|
|||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
layer_height_profile.push_back(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.0;
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
double print_z = slicing_params.first_object_layer_height;
|
||||
// last facet visited by the as.next_layer_height() function, where the facets are sorted by their increasing Z span.
|
||||
size_t current_facet = 0;
|
||||
// loop until we have at least one layer and the max slice_z reaches the object height
|
||||
while (print_z + EPSILON < slicing_params.object_print_z_height()) {
|
||||
float height = slicing_params.max_layer_height;
|
||||
// Slic3r::debugf "\n Slice layer: %d\n", $id;
|
||||
// determine next layer height
|
||||
double cusp_height = as.cusp_height((float)slice_z, cusp_value, current_facet);
|
||||
float cusp_height = as.next_layer_height(float(print_z), quality_factor, current_facet);
|
||||
|
||||
#if 0
|
||||
// check for horizontal features and object size
|
||||
/*
|
||||
if($self->config->get_value('match_horizontal_surfaces')) {
|
||||
my $horizontal_dist = $adaptive_slicing[$region_id]->horizontal_facet_distance(scale $slice_z+$cusp_height, $min_height);
|
||||
if(($horizontal_dist < $min_height) && ($horizontal_dist > 0)) {
|
||||
Slic3r::debugf "Horizontal feature ahead, distance: %f\n", $horizontal_dist;
|
||||
# can we shrink the current layer a bit?
|
||||
if($cusp_height-($min_height-$horizontal_dist) > $min_height) {
|
||||
# yes we can
|
||||
$cusp_height = $cusp_height-($min_height-$horizontal_dist);
|
||||
Slic3r::debugf "Shrink layer height to %f\n", $cusp_height;
|
||||
}else{
|
||||
# no, current layer would become too thin
|
||||
$cusp_height = $cusp_height+$horizontal_dist;
|
||||
Slic3r::debugf "Widen layer height to %f\n", $cusp_height;
|
||||
if (this->config.match_horizontal_surfaces.value) {
|
||||
coordf_t horizontal_dist = as.horizontal_facet_distance(print_z + height, min_layer_height);
|
||||
if ((horizontal_dist < min_layer_height) && (horizontal_dist > 0)) {
|
||||
#ifdef SLIC3R_DEBUG
|
||||
std::cout << "Horizontal feature ahead, distance: " << horizontal_dist << std::endl;
|
||||
#endif
|
||||
// can we shrink the current layer a bit?
|
||||
if (height-(min_layer_height - horizontal_dist) > min_layer_height) {
|
||||
// yes we can
|
||||
height -= (min_layer_height - horizontal_dist);
|
||||
#ifdef SLIC3R_DEBUG
|
||||
std::cout << "Shrink layer height to " << height << std::endl;
|
||||
#endif
|
||||
} else {
|
||||
// no, current layer would become too thin
|
||||
height += horizontal_dist;
|
||||
#ifdef SLIC3R_DEBUG
|
||||
std::cout << "Widen layer height to " << height << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
height = std::min(cusp_height, height);
|
||||
|
||||
// apply z-gradation
|
||||
|
|
@ -308,22 +286,22 @@ std::vector<coordf_t> layer_height_profile_adaptive(
|
|||
|
||||
// look for an applicable custom range
|
||||
/*
|
||||
if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) {
|
||||
if (my $range = first { $_->[0] <= $print_z && $_->[1] > $print_z } @{$self->layer_height_ranges}) {
|
||||
$height = $range->[2];
|
||||
|
||||
# if user set custom height to zero we should just skip the range and resume slicing over it
|
||||
if ($height == 0) {
|
||||
$slice_z += $range->[1] - $range->[0];
|
||||
$print_z += $range->[1] - $range->[0];
|
||||
next;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
layer_height_profile.push_back(slice_z);
|
||||
layer_height_profile.push_back(print_z);
|
||||
layer_height_profile.push_back(height);
|
||||
slice_z += height;
|
||||
print_z += height;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
layer_height_profile.push_back(slice_z);
|
||||
layer_height_profile.push_back(print_z);
|
||||
layer_height_profile.push_back(height);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
}
|
||||
|
|
@ -722,11 +700,7 @@ 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);
|
||||
#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
|
||||
assert(lo - EPSILON <= z && z <= hi + EPSILON);
|
||||
// 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,12 +18,7 @@ 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
|
||||
|
|
@ -142,10 +137,9 @@ 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);
|
||||
const ModelObject& object, float quality_factor);
|
||||
|
||||
struct HeightProfileSmoothingParams
|
||||
{
|
||||
|
|
@ -159,12 +153,6 @@ struct HeightProfileSmoothingParams
|
|||
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,156 +1,211 @@
|
|||
#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"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
// Based on the work of Florens Waserfall (@platch on github)
|
||||
// and his paper
|
||||
// Florens Wasserfall, Norman Hendrich, Jianwei Zhang:
|
||||
// Adaptive Slicing for the FDM Process Revisited
|
||||
// 13th IEEE Conference on Automation Science and Engineering (CASE-2017), August 20-23, Xi'an, China. DOI: 10.1109/COASE.2017.8256074
|
||||
// https://tams.informatik.uni-hamburg.de/publications/2017/Adaptive%20Slicing%20for%20the%20FDM%20Process%20Revisited.pdf
|
||||
|
||||
// Vojtech believes that there is a bug in @platch's derivation of the triangle area error metric.
|
||||
// Following Octave code paints graphs of recommended layer height versus surface slope angle.
|
||||
#if 0
|
||||
adeg=0:1:85;
|
||||
a=adeg*pi/180;
|
||||
t=tan(a);
|
||||
tsqr=sqrt(tan(a));
|
||||
lerr=1./cos(a);
|
||||
lerr2=1./(0.3+cos(a));
|
||||
plot(adeg, t, 'b', adeg, sqrt(t), 'g', adeg, 0.5 * lerr, 'm', adeg, 0.5 * lerr2, 'r')
|
||||
xlabel("angle(deg), 0 - horizontal wall, 90 - vertical wall");
|
||||
ylabel("layer height");
|
||||
legend("tan(a) as cura - topographic lines distance limit", "sqrt(tan(a)) as PrusaSlicer - error triangle area limit", "old slic3r - max distance metric", "new slic3r - Waserfall paper");
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define ADAPTIVE_LAYER_HEIGHT_DEBUG
|
||||
#endif /* NDEBUG */
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void SlicingAdaptive::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)
|
||||
static inline std::pair<float, float> face_z_span(const stl_facet &f)
|
||||
{
|
||||
return std::pair<float, float>(
|
||||
std::min(std::min(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)),
|
||||
std::max(std::max(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)));
|
||||
std::min(std::min(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2)),
|
||||
std::max(std::max(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2)));
|
||||
}
|
||||
|
||||
void SlicingAdaptive::prepare()
|
||||
// By Florens Waserfall aka @platch:
|
||||
// This constant essentially describes the volumetric error at the surface which is induced
|
||||
// by stacking "elliptic" extrusion threads. It is empirically determined by
|
||||
// 1. measuring the surface profile of printed parts to find
|
||||
// the ratio between layer height and profile height and then
|
||||
// 2. computing the geometric difference between the model-surface and the elliptic profile.
|
||||
//
|
||||
// The definition of the roughness formula is in
|
||||
// https://tams.informatik.uni-hamburg.de/publications/2017/Adaptive%20Slicing%20for%20the%20FDM%20Process%20Revisited.pdf
|
||||
// (page 51, formula (8))
|
||||
// Currenty @platch's error metric formula is not used.
|
||||
static constexpr double SURFACE_CONST = 0.18403;
|
||||
|
||||
// for a given facet, compute maximum height within the allowed surface roughness / stairstepping deviation
|
||||
static inline float layer_height_from_slope(const SlicingAdaptive::FaceZ &face, float max_surface_deviation)
|
||||
{
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
if (m_object == nullptr)
|
||||
return;
|
||||
// @platch's formula, see his paper "Adaptive Slicing for the FDM Process Revisited".
|
||||
// return float(max_surface_deviation / (SURFACE_CONST + 0.5 * std::abs(normal_z)));
|
||||
|
||||
// Constant stepping in horizontal direction, as used by Cura.
|
||||
// return (face.n_cos > 1e-5) ? float(max_surface_deviation * face.n_sin / face.n_cos) : FLT_MAX;
|
||||
|
||||
m_faces.clear();
|
||||
m_face_normal_z.clear();
|
||||
// Constant error measured as an area of the surface error triangle, Vojtech's formula.
|
||||
// return (face.n_cos > 1e-5) ? float(1.44 * max_surface_deviation * sqrt(face.n_sin / face.n_cos)) : FLT_MAX;
|
||||
|
||||
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());
|
||||
// Constant error measured as an area of the surface error triangle, Vojtech's formula with clamping to roughness at 90 degrees.
|
||||
return std::min(max_surface_deviation / 0.184f, (face.n_cos > 1e-5) ? float(1.44 * max_surface_deviation * sqrt(face.n_sin / face.n_cos)) : FLT_MAX);
|
||||
|
||||
// Constant stepping along the surface, equivalent to the "surface roughness" metric by Perez and later Pandey et all, see @platch's paper for references.
|
||||
// return float(max_surface_deviation * face.n_sin);
|
||||
}
|
||||
|
||||
void SlicingAdaptive::clear()
|
||||
{
|
||||
m_faces.clear();
|
||||
}
|
||||
|
||||
void SlicingAdaptive::prepare(const ModelObject &object)
|
||||
{
|
||||
this->clear();
|
||||
|
||||
TriangleMesh mesh = object.raw_mesh();
|
||||
const ModelInstance &first_instance = *object.instances.front();
|
||||
mesh.transform(first_instance.get_matrix(), first_instance.is_left_handed());
|
||||
|
||||
// 1) Collect faces from mesh.
|
||||
m_faces.reserve(m_mesh.stl.stats.number_of_facets);
|
||||
for (stl_facet& face : m_mesh.stl.facet_start)
|
||||
{
|
||||
face.normal.normalize();
|
||||
m_faces.emplace_back(&face);
|
||||
m_faces.reserve(mesh.stl.stats.number_of_facets);
|
||||
for (const stl_facet &face : mesh.stl.facet_start) {
|
||||
Vec3f n = face.normal.normalized();
|
||||
m_faces.emplace_back(FaceZ({ face_z_span(face), std::abs(n.z()), std::sqrt(n.x() * n.x() + n.y() * n.y()) }));
|
||||
}
|
||||
#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);
|
||||
#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) { return face_z_span(f1) < face_z_span(f2); });
|
||||
|
||||
// 3) Generate Z components of the facet normals.
|
||||
m_face_normal_z.assign(m_faces.size(), 0.0f);
|
||||
for (size_t iface = 0; iface < m_faces.size(); ++ iface)
|
||||
m_face_normal_z[iface] = m_faces[iface]->normal(2);
|
||||
std::sort(m_faces.begin(), m_faces.end(), [](const FaceZ &f1, const FaceZ &f2) { return f1.z_span < f2.z_span; });
|
||||
}
|
||||
|
||||
float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet)
|
||||
// current_facet is in/out parameter, rememebers the index of the last face of m_faces visited,
|
||||
// where this function will start from.
|
||||
// print_z - the top print surface of the previous layer.
|
||||
// returns height of the next layer.
|
||||
float SlicingAdaptive::next_layer_height(const float print_z, float quality_factor, size_t ¤t_facet)
|
||||
{
|
||||
float height = (float)m_slicing_params.max_layer_height;
|
||||
bool first_hit = false;
|
||||
float height = (float)m_slicing_params.max_layer_height;
|
||||
|
||||
float max_surface_deviation;
|
||||
|
||||
{
|
||||
#if 0
|
||||
// @platch's formula for quality:
|
||||
double delta_min = SURFACE_CONST * m_slicing_params.min_layer_height;
|
||||
double delta_mid = (SURFACE_CONST + 0.5) * m_slicing_params.layer_height;
|
||||
double delta_max = (SURFACE_CONST + 0.5) * m_slicing_params.max_layer_height;
|
||||
#else
|
||||
// Vojtech's formula for triangle area error metric.
|
||||
double delta_min = m_slicing_params.min_layer_height;
|
||||
double delta_mid = m_slicing_params.layer_height;
|
||||
double delta_max = m_slicing_params.max_layer_height;
|
||||
#endif
|
||||
max_surface_deviation = (quality_factor < 0.5f) ?
|
||||
lerp(delta_min, delta_mid, 2. * quality_factor) :
|
||||
lerp(delta_max, delta_mid, 2. * (1. - quality_factor));
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
if (zspan.second > z) {
|
||||
// first event?
|
||||
if (! first_hit) {
|
||||
first_hit = true;
|
||||
current_facet = ordered_id;
|
||||
}
|
||||
// skip touching facets which could otherwise cause small cusp values
|
||||
if (zspan.second <= z + EPSILON)
|
||||
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.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z));
|
||||
}
|
||||
size_t ordered_id = current_facet;
|
||||
{
|
||||
bool first_hit = false;
|
||||
for (; ordered_id < m_faces.size(); ++ ordered_id) {
|
||||
const std::pair<float, float> &zspan = m_faces[ordered_id].z_span;
|
||||
// facet's minimum is higher than slice_z -> end loop
|
||||
if (zspan.first >= print_z)
|
||||
break;
|
||||
// facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point
|
||||
if (zspan.second > print_z) {
|
||||
// first event?
|
||||
if (! first_hit) {
|
||||
first_hit = true;
|
||||
current_facet = ordered_id;
|
||||
}
|
||||
// skip touching facets which could otherwise cause small cusp values
|
||||
if (zspan.second < print_z + EPSILON)
|
||||
continue;
|
||||
// compute cusp-height for this facet and store minimum of all heights
|
||||
height = std::min(height, layer_height_from_slope(m_faces[ordered_id], max_surface_deviation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lower height limit due to printer capabilities
|
||||
height = std::max(height, float(m_slicing_params.min_layer_height));
|
||||
|
||||
// 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]);
|
||||
if (height > float(m_slicing_params.min_layer_height)) {
|
||||
for (; ordered_id < m_faces.size(); ++ ordered_id) {
|
||||
const std::pair<float, float> &zspan = m_faces[ordered_id].z_span;
|
||||
// facet's minimum is higher than slice_z + height -> end loop
|
||||
if (zspan.first >= z + height)
|
||||
if (zspan.first >= print_z + height)
|
||||
break;
|
||||
|
||||
// skip touching facets which could otherwise cause small cusp values
|
||||
if (zspan.second <= z + EPSILON)
|
||||
if (zspan.second < print_z + EPSILON)
|
||||
continue;
|
||||
|
||||
// Compute cusp-height for this facet and check against height.
|
||||
float normal_z = m_face_normal_z[ordered_id];
|
||||
float cusp = (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z);
|
||||
float reduced_height = layer_height_from_slope(m_faces[ordered_id], max_surface_deviation);
|
||||
|
||||
float z_diff = zspan.first - z;
|
||||
|
||||
// handle horizontal facets
|
||||
if (normal_z > 0.999f) {
|
||||
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
|
||||
float z_diff = zspan.first - print_z;
|
||||
if (reduced_height < z_diff) {
|
||||
assert(z_diff < height + EPSILON);
|
||||
// The currently visited triangle's slope limits the next layer height so much, that
|
||||
// the lowest point of the currently visible triangle is already above the newly proposed layer height.
|
||||
// This means, that we need to limit the layer height so that the offending newly visited triangle
|
||||
// is just above of the new layer.
|
||||
#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG
|
||||
BOOST_LOG_TRIVIAL(trace) << "cusp computation, height is reduced from " << height << "to " << z_diff << " due to z-diff";
|
||||
#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */
|
||||
height = z_diff;
|
||||
// Slic3r::debugf "to %f due to near horizontal facet\n", $height;
|
||||
} else if (cusp > z_diff) {
|
||||
if (cusp < height) {
|
||||
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
|
||||
height = cusp;
|
||||
// Slic3r::debugf "to %f due to new cusp height\n", $height;
|
||||
}
|
||||
} else {
|
||||
// Slic3r::debugf "cusp computation, height is reduced from %f", $height;
|
||||
height = z_diff;
|
||||
// Slic3r::debugf "to z-diff: %f\n", $height;
|
||||
} else if (reduced_height < height) {
|
||||
#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG
|
||||
BOOST_LOG_TRIVIAL(trace) << "adaptive layer computation: height is reduced from " << height << "to " << reduced_height << " due to higher facet";
|
||||
#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */
|
||||
height = reduced_height;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
#ifdef ADAPTIVE_LAYER_HEIGHT_DEBUG
|
||||
BOOST_LOG_TRIVIAL(trace) << "adaptive layer computation, layer-bottom at z:" << print_z << ", quality_factor:" << quality_factor << ", resulting layer height:" << height;
|
||||
#endif /* ADAPTIVE_LAYER_HEIGHT_DEBUG */
|
||||
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]);
|
||||
std::pair<float, float> zspan = m_faces[i].z_span;
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
@ -158,6 +213,5 @@ float SlicingAdaptive::horizontal_facet_distance(float z)
|
|||
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,50 +5,36 @@
|
|||
|
||||
#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:
|
||||
#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);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void clear();
|
||||
void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; }
|
||||
void prepare(const ModelObject &object);
|
||||
// Return next layer height starting from the last print_z, using a quality measure
|
||||
// (quality in range from 0 to 1, 0 - highest quality at low layer heights, 1 - lowest print quality at high layer heights).
|
||||
// The layer height curve shall be centered roughly around the default profile's layer height for quality 0.5.
|
||||
float next_layer_height(const float print_z, float quality, size_t ¤t_facet);
|
||||
float horizontal_facet_distance(float z);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
struct FaceZ {
|
||||
std::pair<float, float> z_span;
|
||||
// Cosine of the normal vector towards the Z axis.
|
||||
float n_cos;
|
||||
// Sine of the normal vector towards the Z axis.
|
||||
float n_sin;
|
||||
};
|
||||
|
||||
protected:
|
||||
SlicingParameters m_slicing_params;
|
||||
SlicingParameters m_slicing_params;
|
||||
|
||||
#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.
|
||||
std::vector<float> m_face_normal_z;
|
||||
std::vector<FaceZ> m_faces;
|
||||
};
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -53,4 +53,7 @@
|
|||
// Enable selection for missing files in reload from disk command
|
||||
#define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons
|
||||
#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
#endif // _technologies_h_
|
||||
|
|
|
|||
|
|
@ -217,14 +217,6 @@ inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER
|
|||
return container[next_idx_modulo(idx, container.size())];
|
||||
}
|
||||
|
||||
template<class T, class U = T>
|
||||
inline T exchange(T& obj, U&& new_value)
|
||||
{
|
||||
T old_value = std::move(obj);
|
||||
obj = std::forward<U>(new_value);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
extern std::string xml_escape(std::string text);
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue