mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-25 17:51:10 -06:00
Merge remote-tracking branch 'remotes/origin/master' into tm_relative_correction
This commit is contained in:
commit
0de084df8d
89 changed files with 3808 additions and 2930 deletions
|
|
@ -1034,6 +1034,15 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
}
|
||||
_write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
|
||||
_write(file, m_writer.postamble());
|
||||
|
||||
// adds tags for time estimators
|
||||
if (print.config().remaining_times.value)
|
||||
{
|
||||
_writeln(file, GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
_writeln(file, GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag);
|
||||
}
|
||||
|
||||
print.throw_if_canceled();
|
||||
|
||||
// calculates estimated printing time
|
||||
|
|
|
|||
|
|
@ -776,6 +776,9 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
|||
preview_data.ranges.width.update_from(width_range);
|
||||
preview_data.ranges.feedrate.update_from(feedrate_range);
|
||||
preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range);
|
||||
|
||||
// we need to sort the layers by their z as they can be shuffled in case of sequential prints
|
||||
std::sort(preview_data.extrusion.layers.begin(), preview_data.extrusion.layers.end(), [](const GCodePreviewData::Extrusion::Layer& l1, const GCodePreviewData::Extrusion::Layer& l2)->bool { return l1.z < l2.z; });
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||
|
|
@ -855,6 +858,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
|
|||
preview_data.ranges.height.update_from(height_range);
|
||||
preview_data.ranges.width.update_from(width_range);
|
||||
preview_data.ranges.feedrate.update_from(feedrate_range);
|
||||
|
||||
// we need to sort the polylines by their min z as they can be shuffled in case of sequential prints
|
||||
std::sort(preview_data.travel.polylines.begin(), preview_data.travel.polylines.end(),
|
||||
[](const GCodePreviewData::Travel::Polyline& p1, const GCodePreviewData::Travel::Polyline& p2)->bool
|
||||
{ return unscale<double>(p1.polyline.bounding_box().min(2)) < unscale<double>(p2.polyline.bounding_box().min(2)); });
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||
|
|
@ -877,6 +885,11 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da
|
|||
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
||||
preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
|
||||
}
|
||||
|
||||
// we need to sort the positions by their z as they can be shuffled in case of sequential prints
|
||||
std::sort(preview_data.retraction.positions.begin(), preview_data.retraction.positions.end(),
|
||||
[](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool
|
||||
{ return unscale<double>(p1.position(2)) < unscale<double>(p2.position(2)); });
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||
|
|
@ -899,6 +912,11 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_
|
|||
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
||||
preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
|
||||
}
|
||||
|
||||
// we need to sort the positions by their z as they can be shuffled in case of sequential prints
|
||||
std::sort(preview_data.unretraction.positions.begin(), preview_data.unretraction.positions.end(),
|
||||
[](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool
|
||||
{ return unscale<double>(p1.position(2)) < unscale<double>(p2.position(2)); });
|
||||
}
|
||||
|
||||
// Return an estimate of the memory consumed by the time estimator.
|
||||
|
|
|
|||
|
|
@ -171,6 +171,8 @@ namespace Slic3r {
|
|||
|
||||
const std::string GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag = "; NORMAL_FIRST_M73_OUTPUT_PLACEHOLDER";
|
||||
const std::string GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag = "; SILENT_FIRST_M73_OUTPUT_PLACEHOLDER";
|
||||
const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; NORMAL_LAST_M73_OUTPUT_PLACEHOLDER";
|
||||
const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; SILENT_LAST_M73_OUTPUT_PLACEHOLDER";
|
||||
|
||||
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
|
||||
: _mode(mode)
|
||||
|
|
@ -306,9 +308,17 @@ namespace Slic3r {
|
|||
sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(_time).c_str());
|
||||
gcode_line = time_line;
|
||||
}
|
||||
// replaces placeholders for final line M73 with the real lines
|
||||
else if (((_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) ||
|
||||
((_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag)))
|
||||
{
|
||||
sprintf(time_line, time_mask.c_str(), "100", "0");
|
||||
gcode_line = time_line;
|
||||
}
|
||||
else
|
||||
gcode_line += "\n";
|
||||
|
||||
|
||||
// add remaining time lines where needed
|
||||
_parser.parse_line(gcode_line,
|
||||
[this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ namespace Slic3r {
|
|||
public:
|
||||
static const std::string Normal_First_M73_Output_Placeholder_Tag;
|
||||
static const std::string Silent_First_M73_Output_Placeholder_Tag;
|
||||
static const std::string Normal_Last_M73_Output_Placeholder_Tag;
|
||||
static const std::string Silent_Last_M73_Output_Placeholder_Tag;
|
||||
|
||||
enum EMode : unsigned char
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1455,4 +1455,28 @@ Transformation Transformation::operator * (const Transformation& other) const
|
|||
return Transformation(get_matrix() * other.get_matrix());
|
||||
}
|
||||
|
||||
Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
||||
{
|
||||
return
|
||||
// From the current coordinate system to world.
|
||||
Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) *
|
||||
// From world to the initial coordinate system.
|
||||
Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ());
|
||||
}
|
||||
|
||||
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
|
||||
double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
||||
{
|
||||
Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
|
||||
Vec3d axis = angle_axis.axis();
|
||||
double angle = angle_axis.angle();
|
||||
#ifndef NDEBUG
|
||||
if (std::abs(angle) > 1e-8) {
|
||||
assert(std::abs(axis.x()) < 1e-8);
|
||||
assert(std::abs(axis.y()) < 1e-8);
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
return (axis.z() < 0) ? -angle : angle;
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -262,6 +262,13 @@ public:
|
|||
Transformation operator * (const Transformation& other) const;
|
||||
};
|
||||
|
||||
// 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);
|
||||
// Rotation by Z to align rot_xyz_from to rot_xyz_to.
|
||||
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
|
||||
extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to);
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -556,19 +556,9 @@ std::string Model::propose_export_file_name_and_path() const
|
|||
for (const ModelObject *model_object : this->objects)
|
||||
for (ModelInstance *model_instance : model_object->instances)
|
||||
if (model_instance->is_printable()) {
|
||||
input_file = model_object->input_file;
|
||||
if (! model_object->name.empty()) {
|
||||
if (input_file.empty())
|
||||
// model_object->input_file was empty, just use model_object->name
|
||||
input_file = model_object->name;
|
||||
else {
|
||||
// Replace file name in input_file with model_object->name, but keep the path and file extension.
|
||||
input_file = (boost::filesystem::path(model_object->name).parent_path().empty()) ?
|
||||
(boost::filesystem::path(input_file).parent_path() / model_object->name).make_preferred().string() :
|
||||
model_object->name;
|
||||
}
|
||||
}
|
||||
if (! input_file.empty())
|
||||
input_file = model_object->get_export_filename();
|
||||
|
||||
if (!input_file.empty())
|
||||
goto end;
|
||||
// Other instances will produce the same name, skip them.
|
||||
break;
|
||||
|
|
@ -1433,6 +1423,26 @@ void ModelObject::print_info() const
|
|||
cout << "volume = " << mesh.volume() << endl;
|
||||
}
|
||||
|
||||
std::string ModelObject::get_export_filename() const
|
||||
{
|
||||
std::string ret = input_file;
|
||||
|
||||
if (!name.empty())
|
||||
{
|
||||
if (ret.empty())
|
||||
// input_file was empty, just use name
|
||||
ret = name;
|
||||
else
|
||||
{
|
||||
// Replace file name in input_file with name, but keep the path and file extension.
|
||||
ret = (boost::filesystem::path(name).parent_path().empty()) ?
|
||||
(boost::filesystem::path(ret).parent_path() / name).make_preferred().string() : name;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ModelVolume::set_material_id(t_model_material_id material_id)
|
||||
{
|
||||
m_material_id = material_id;
|
||||
|
|
|
|||
|
|
@ -275,6 +275,8 @@ public:
|
|||
// Print object statistics to console.
|
||||
void print_info() const;
|
||||
|
||||
std::string get_export_filename() const;
|
||||
|
||||
protected:
|
||||
friend class Print;
|
||||
friend class SLAPrint;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "GCode/WipeTowerPrusaMM.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include "PrintExport.hpp"
|
||||
//#include "PrintExport.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "Rasterizer/Rasterizer.hpp"
|
||||
//#include <tbb/parallel_for.h>
|
||||
|
|
@ -72,7 +73,8 @@ public:
|
|||
void finish_layer();
|
||||
|
||||
// Save all the layers into the file (or dir) specified in the path argument
|
||||
void save(const std::string& path);
|
||||
// An optional project name can be added to be used for the layer file names
|
||||
void save(const std::string& path, const std::string& projectname = "");
|
||||
|
||||
// Save only the selected layer to the file specified in path argument.
|
||||
void save_layer(unsigned lyr, const std::string& path);
|
||||
|
|
@ -86,7 +88,8 @@ template<class T = void> struct VeryFalse { static const bool value = false; };
|
|||
template<class Fmt> class LayerWriter {
|
||||
public:
|
||||
|
||||
LayerWriter(const std::string& /*zipfile_path*/) {
|
||||
LayerWriter(const std::string& /*zipfile_path*/)
|
||||
{
|
||||
static_assert(VeryFalse<Fmt>::value,
|
||||
"No layer writer implementation provided!");
|
||||
}
|
||||
|
|
@ -99,10 +102,6 @@ public:
|
|||
void binary_entry(const std::string& /*fname*/,
|
||||
const std::uint8_t* buf, size_t len);
|
||||
|
||||
// Get the name of the archive but only the name part without the path or
|
||||
// the extension.
|
||||
std::string get_name() { return ""; }
|
||||
|
||||
// Test whether the object can still be used for writing.
|
||||
bool is_ok() { return false; }
|
||||
|
||||
|
|
@ -253,12 +252,14 @@ public:
|
|||
}
|
||||
|
||||
template<class LyrFmt>
|
||||
inline void save(const std::string& path) {
|
||||
inline void save(const std::string& fpath, const std::string& prjname = "")
|
||||
{
|
||||
try {
|
||||
LayerWriter<LyrFmt> writer(path);
|
||||
LayerWriter<LyrFmt> writer(fpath);
|
||||
if(!writer.is_ok()) return;
|
||||
|
||||
std::string project = writer.get_name();
|
||||
std::string project = prjname.empty()?
|
||||
boost::filesystem::path(fpath).stem().string() : prjname;
|
||||
|
||||
writer.next_entry("config.ini");
|
||||
if(!writer.is_ok()) return;
|
||||
|
|
|
|||
|
|
@ -1790,8 +1790,13 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
|||
if (! volumes.empty()) {
|
||||
// Compose mesh.
|
||||
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
|
||||
TriangleMesh mesh(volumes.front()->mesh);
|
||||
TriangleMesh mesh(volumes.front()->mesh);
|
||||
mesh.transform(volumes.front()->get_matrix(), true);
|
||||
assert(mesh.repaired);
|
||||
if (volumes.size() == 1 && mesh.repaired) {
|
||||
//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
|
||||
stl_check_facets_exact(&mesh.stl);
|
||||
}
|
||||
for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) {
|
||||
const ModelVolume &model_volume = *volumes[idx_volume];
|
||||
TriangleMesh vol_mesh(model_volume.mesh);
|
||||
|
|
@ -1821,6 +1826,10 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
|
|||
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
|
||||
TriangleMesh mesh(volume.mesh);
|
||||
mesh.transform(volume.get_matrix(), true);
|
||||
if (mesh.repaired) {
|
||||
//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
|
||||
stl_check_facets_exact(&mesh.stl);
|
||||
}
|
||||
if (mesh.stl.stats.number_of_facets > 0) {
|
||||
mesh.transform(m_trafo, true);
|
||||
// apply XY shift
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public:
|
|||
float minimal_distance;
|
||||
float head_diameter;
|
||||
///////////////
|
||||
inline float support_force() const { return 10.f / density_relative; } // a force one point can support (arbitrary force unit)
|
||||
inline float support_force() const { return 7.7f / density_relative; } // a force one point can support (arbitrary force unit)
|
||||
inline float tear_pressure() const { return 1.f; } // pressure that the display exerts (the force unit per mm2)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "SLA/SLABasePool.hpp"
|
||||
#include "SLA/SLAAutoSupports.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "MTUtils.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
|
|
@ -118,13 +119,18 @@ static Transform3d sla_trafo(const SLAPrint& p, const ModelObject &model_object)
|
|||
static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &model_object)
|
||||
{
|
||||
std::vector<SLAPrintObject::Instance> instances;
|
||||
for (ModelInstance *model_instance : model_object.instances)
|
||||
if (model_instance->is_printable()) {
|
||||
instances.emplace_back(
|
||||
model_instance->id(),
|
||||
Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)),
|
||||
float(model_instance->get_rotation(Z)));
|
||||
}
|
||||
assert(! model_object.instances.empty());
|
||||
if (! model_object.instances.empty()) {
|
||||
Vec3d rotation0 = model_object.instances.front()->get_rotation();
|
||||
rotation0(2) = 0.;
|
||||
for (ModelInstance *model_instance : model_object.instances)
|
||||
if (model_instance->is_printable()) {
|
||||
instances.emplace_back(
|
||||
model_instance->id(),
|
||||
Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)),
|
||||
float(Geometry::rotation_diff_z(rotation0, model_instance->get_rotation())));
|
||||
}
|
||||
}
|
||||
return instances;
|
||||
}
|
||||
|
||||
|
|
@ -1078,11 +1084,11 @@ void SLAPrint::process()
|
|||
hole.reserve(h.points.size() + 1);
|
||||
|
||||
if(needreverse)
|
||||
for(auto& p : h.points)
|
||||
hole.emplace_back(p.x(), p.y());
|
||||
else
|
||||
for(auto it = h.points.rbegin(); it != h.points.rend(); ++it)
|
||||
hole.emplace_back(it->x(), it->y());
|
||||
else
|
||||
for(auto& p : h.points)
|
||||
hole.emplace_back(p.x(), p.y());
|
||||
}
|
||||
|
||||
if(is_lefthanded) {
|
||||
|
|
|
|||
|
|
@ -320,10 +320,8 @@ struct SLAPrintStatistics
|
|||
}
|
||||
};
|
||||
|
||||
struct SLAminzZipper {};
|
||||
|
||||
// The implementation of creating zipped archives with wxWidgets
|
||||
template<> class LayerWriter<SLAminzZipper> {
|
||||
template<> class LayerWriter<Zipper> {
|
||||
Zipper m_zip;
|
||||
public:
|
||||
|
||||
|
|
@ -332,16 +330,12 @@ public:
|
|||
void next_entry(const std::string& fname) { m_zip.add_entry(fname); }
|
||||
|
||||
void binary_entry(const std::string& fname,
|
||||
const std::uint8_t* buf,
|
||||
size_t l)
|
||||
const std::uint8_t* buf,
|
||||
size_t l)
|
||||
{
|
||||
m_zip.add_entry(fname, buf, l);
|
||||
}
|
||||
|
||||
std::string get_name() const {
|
||||
return m_zip.get_name();
|
||||
}
|
||||
|
||||
template<class T> inline LayerWriter& operator<<(T&& arg) {
|
||||
m_zip << std::forward<T>(arg); return *this;
|
||||
}
|
||||
|
|
@ -389,9 +383,11 @@ public:
|
|||
// Returns true if the last step was finished with success.
|
||||
bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); }
|
||||
|
||||
template<class Fmt = SLAminzZipper>
|
||||
void export_raster(const std::string& fname) {
|
||||
if(m_printer) m_printer->save<Fmt>(fname);
|
||||
template<class Fmt = Zipper>
|
||||
inline void export_raster(const std::string& fpath,
|
||||
const std::string& projectname = "")
|
||||
{
|
||||
if(m_printer) m_printer->save<Fmt>(fpath, projectname);
|
||||
}
|
||||
|
||||
const PrintObjects& objects() const { return m_objects; }
|
||||
|
|
|
|||
|
|
@ -273,6 +273,11 @@ void TriangleMesh::translate(float x, float y, float z)
|
|||
stl_invalidate_shared_vertices(&this->stl);
|
||||
}
|
||||
|
||||
void TriangleMesh::translate(const Vec3f &displacement)
|
||||
{
|
||||
translate(displacement(0), displacement(1), displacement(2));
|
||||
}
|
||||
|
||||
void TriangleMesh::rotate(float angle, const Axis &axis)
|
||||
{
|
||||
if (angle == 0.f)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public:
|
|||
void scale(float factor);
|
||||
void scale(const Vec3d &versor);
|
||||
void translate(float x, float y, float z);
|
||||
void translate(const Vec3f &displacement);
|
||||
void rotate(float angle, const Axis &axis);
|
||||
void rotate(float angle, const Vec3d& axis);
|
||||
void rotate_x(float angle) { this->rotate(angle, X); }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "Zipper.hpp"
|
||||
#include "miniz/miniz_zip.h"
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include "I18N.hpp"
|
||||
|
|
@ -213,10 +212,6 @@ void Zipper::finish_entry()
|
|||
m_entry.clear();
|
||||
}
|
||||
|
||||
std::string Zipper::get_name() const {
|
||||
return boost::filesystem::path(m_impl->m_zipname).stem().string();
|
||||
}
|
||||
|
||||
void Zipper::finalize()
|
||||
{
|
||||
finish_entry();
|
||||
|
|
|
|||
|
|
@ -81,9 +81,6 @@ public:
|
|||
/// file is up to minz after the erroneous write.
|
||||
void finish_entry();
|
||||
|
||||
/// Gets the name of the archive without the path or extension.
|
||||
std::string get_name() const;
|
||||
|
||||
void finalize();
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue