This commit is contained in:
Enrico Turri 2018-12-17 08:29:23 +01:00
commit debbca0f14
23 changed files with 219 additions and 109 deletions

View file

@ -505,8 +505,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
.speed_override(100);
writer.set_initial_position(xy(0.f, 0.f)) // Always move to the starting position
.travel(cleaning_box.ld, 7200)
.set_extruder_trimpot(750); // Increase the extruder driver current to allow fast ramming.
.travel(cleaning_box.ld, 7200);
if (m_set_extruder_trimpot)
writer.set_extruder_trimpot(750); // Increase the extruder driver current to allow fast ramming.
for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) {
unsigned int tool = tools[idx_tool];
@ -533,8 +534,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
// in the output gcode - we should not remember emitting them (we will output them twice in the worst case)
// Reset the extruder current to a normal value.
writer.set_extruder_trimpot(550)
.feedrate(6000)
if (m_set_extruder_trimpot)
writer.set_extruder_trimpot(550);
writer.feedrate(6000)
.flush_planner_queue()
.reset_extruder()
.append("; CP PRIMING END\n"
@ -607,7 +609,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
// Increase the extruder driver current to allow fast ramming.
writer.set_extruder_trimpot(750);
if (m_set_extruder_trimpot)
writer.set_extruder_trimpot(550);
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
if (tool != (unsigned int)-1){ // This is not the last change.
@ -635,8 +638,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
}
}
writer.set_extruder_trimpot(550) // Reset the extruder current to a normal value.
.feedrate(6000)
if (m_set_extruder_trimpot)
writer.set_extruder_trimpot(550); // Reset the extruder current to a normal value.
writer.feedrate(6000)
.flush_planner_queue()
.reset_extruder()
.append("; CP TOOLCHANGE END\n"
@ -916,12 +920,10 @@ void WipeTowerPrusaMM::toolchange_Load(
.resume_preview();
// Reset the extruder current to the normal value.
writer.set_extruder_trimpot(550);
if (m_set_extruder_trimpot)
writer.set_extruder_trimpot(550);
}
// Wipe the newly loaded filament until the end of the assigned wipe area.
void WipeTowerPrusaMM::toolchange_Wipe(
PrusaMultiMaterial::Writer &writer,

View file

@ -44,7 +44,8 @@ public:
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
// wipe_area -- space available for one toolchange in mm
WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction,
float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, float bridging,
float cooling_tube_length, float parking_pos_retraction, float extra_loading_move,
float bridging, bool set_extruder_trimpot,
const std::vector<std::vector<float>>& wiping_matrix, unsigned int initial_tool) :
m_wipe_tower_pos(x, y),
m_wipe_tower_width(width),
@ -57,6 +58,7 @@ public:
m_parking_pos_retraction(parking_pos_retraction),
m_extra_loading_move(extra_loading_move),
m_bridging(bridging),
m_set_extruder_trimpot(set_extruder_trimpot),
m_current_tool(initial_tool),
wipe_volumes(wiping_matrix)
{}
@ -212,6 +214,7 @@ private:
float m_parking_pos_retraction = 0.f;
float m_extra_loading_move = 0.f;
float m_bridging = 0.f;
bool m_set_extruder_trimpot = false;
bool m_adhesion = true;
float m_perimeter_width = 0.4 * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.

View file

@ -17,6 +17,16 @@ Layer::~Layer()
m_regions.clear();
}
// Test whether whether there are any slices assigned to this layer.
bool Layer::empty() const
{
for (const LayerRegion *layerm : m_regions)
if (layerm != nullptr && ! layerm->slices.empty())
// Non empty layer.
return false;
return true;
}
LayerRegion* Layer::add_region(PrintRegion* print_region)
{
m_regions.emplace_back(new LayerRegion(this, print_region));

View file

@ -114,7 +114,8 @@ public:
LayerRegion* get_region(int idx) { return m_regions[idx]; }
LayerRegion* add_region(PrintRegion* print_region);
const LayerRegionPtrs& regions() const { return m_regions; }
// Test whether whether there are any slices assigned to this layer.
bool empty() const;
void make_slices();
void merge_slices();
template <class T> bool any_internal_region_slice_contains(const T &item) const {

View file

@ -34,23 +34,22 @@ bool Line::intersection_infinite(const Line &other, Point* point) const
return true;
}
/* distance to the closest point of line */
double Line::distance_to(const Point &point) const
// Distance to the closest point of line.
double Line::distance_to_squared(const Point &point, const Point &a, const Point &b)
{
const Line &line = *this;
const Vec2d v = (line.b - line.a).cast<double>();
const Vec2d va = (point - line.a).cast<double>();
const Vec2d v = (b - a).cast<double>();
const Vec2d va = (point - a).cast<double>();
const double l2 = v.squaredNorm(); // avoid a sqrt
if (l2 == 0.0)
// line.a == line.b case
return va.norm();
// Consider the line extending the segment, parameterized as line.a + t (line.b - line.a).
// a == b case
return va.squaredNorm();
// Consider the line extending the segment, parameterized as a + t (b - a).
// We find projection of this point onto the line.
// It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2
// It falls where t = [(this-a) . (b-a)] / |b-a|^2
const double t = va.dot(v) / l2;
if (t < 0.0) return va.norm(); // beyond the 'a' end of the segment
else if (t > 1.0) return (point - line.b).cast<double>().norm(); // beyond the 'b' end of the segment
return (t * v - va).norm();
if (t < 0.0) return va.squaredNorm(); // beyond the 'a' end of the segment
else if (t > 1.0) return (point - b).cast<double>().squaredNorm(); // beyond the 'b' end of the segment
return (t * v - va).squaredNorm();
}
double Line::perp_distance_to(const Point &point) const

View file

@ -31,7 +31,8 @@ public:
Point midpoint() const { return (this->a + this->b) / 2; }
bool intersection_infinite(const Line &other, Point* point) const;
bool operator==(const Line &rhs) const { return this->a == rhs.a && this->b == rhs.b; }
double distance_to(const Point &point) const;
double distance_to_squared(const Point &point) const { return distance_to_squared(point, this->a, this->b); }
double distance_to(const Point &point) const { return distance_to(point, this->a, this->b); }
double perp_distance_to(const Point &point) const;
bool parallel_to(double angle) const;
bool parallel_to(const Line &line) const { return this->parallel_to(line.direction()); }
@ -43,6 +44,9 @@ public:
bool intersection(const Line& line, Point* intersection) const;
double ccw(const Point& point) const { return point.ccw(*this); }
static double distance_to_squared(const Point &point, const Point &a, const Point &b);
static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); }
Point a;
Point b;
};

View file

@ -162,45 +162,51 @@ bool MultiPoint::first_intersection(const Line& line, Point* intersection) const
return found;
}
//FIXME This is very inefficient in term of memory use.
// The recursive algorithm shall run in place, not allocating temporary data in each recursion.
Points
MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, const double tolerance)
{
assert(points.size() >= 2);
Points results;
double dmax = 0;
size_t index = 0;
Line full(points.front(), points.back());
for (Points::const_iterator it = points.begin() + 1; it != points.end(); ++it) {
// we use shortest distance, not perpendicular distance
double d = full.distance_to(*it);
if (d > dmax) {
index = it - points.begin();
dmax = d;
std::vector<Point> result_pts;
if (! pts.empty()) {
const Point *anchor = &pts.front();
size_t anchor_idx = 0;
const Point *floater = &pts.back();
size_t floater_idx = pts.size() - 1;
result_pts.reserve(pts.size());
result_pts.emplace_back(*anchor);
if (anchor_idx != floater_idx) {
assert(pts.size() > 1);
std::vector<size_t> dpStack;
dpStack.reserve(pts.size());
dpStack.emplace_back(floater_idx);
for (;;) {
double max_distSq = 0.0;
size_t furthest_idx = anchor_idx;
// find point furthest from line seg created by (anchor, floater) and note it
for (size_t i = anchor_idx + 1; i < floater_idx; ++ i) {
double dist = Line::distance_to_squared(pts[i], *anchor, *floater);
if (dist > max_distSq) {
max_distSq = dist;
furthest_idx = i;
}
}
// remove point if less than tolerance
if (max_distSq <= tolerance) {
result_pts.emplace_back(*floater);
anchor_idx = floater_idx;
anchor = floater;
assert(dpStack.back() == floater_idx);
dpStack.pop_back();
if (dpStack.empty())
break;
floater_idx = dpStack.back();
} else {
floater_idx = furthest_idx;
dpStack.emplace_back(floater_idx);
}
floater = &pts[floater_idx];
}
}
}
if (dmax >= tolerance) {
Points dp0;
dp0.reserve(index + 1);
dp0.insert(dp0.end(), points.begin(), points.begin() + index + 1);
// Recursive call.
Points dp1 = MultiPoint::_douglas_peucker(dp0, tolerance);
results.reserve(results.size() + dp1.size() - 1);
results.insert(results.end(), dp1.begin(), dp1.end() - 1);
dp0.clear();
dp0.reserve(points.size() - index);
dp0.insert(dp0.end(), points.begin() + index, points.end());
// Recursive call.
dp1 = MultiPoint::_douglas_peucker(dp0, tolerance);
results.reserve(results.size() + dp1.size());
results.insert(results.end(), dp1.begin(), dp1.end());
} else {
results.push_back(points.front());
results.push_back(points.back());
}
return results;
return result_pts;
}
// Visivalingam simplification algorithm https://github.com/slic3r/Slic3r/pull/3825

View file

@ -213,6 +213,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|| opt_key == "filament_cooling_final_speed"
|| opt_key == "filament_ramming_parameters"
|| opt_key == "gcode_flavor"
|| opt_key == "high_current_on_filament_swap"
|| opt_key == "infill_first"
|| opt_key == "single_extruder_multi_material"
|| opt_key == "spiral_vase"
@ -1768,7 +1769,8 @@ void Print::_make_wipe_tower()
float(m_config.wipe_tower_width.value),
float(m_config.wipe_tower_rotation_angle.value), float(m_config.cooling_tube_retraction.value),
float(m_config.cooling_tube_length.value), float(m_config.parking_pos_retraction.value),
float(m_config.extra_loading_move.value), float(m_config.wipe_tower_bridging), wipe_volumes,
float(m_config.extra_loading_move.value), float(m_config.wipe_tower_bridging),
m_config.high_current_on_filament_swap.value, wipe_volumes,
m_wipe_tower_data.tool_ordering.first_extruder());
//wipe_tower.set_retract();

View file

@ -925,6 +925,15 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->default_value = new ConfigOptionEnum<GCodeFlavor>(gcfRepRap);
def = this->add("high_current_on_filament_swap", coBool);
def->label = L("High extruder current on filament swap");
def->tooltip = L("It may be beneficial to increase the extruder motor current during the filament exchange"
" sequence to allow for rapid ramming feed rates and to overcome resistance when loading"
" a filament with an ugly shaped tip.");
def->cli = "high-current-on-filament-swap!";
def->mode = comExpert;
def->default_value = new ConfigOptionBool(0);
def = this->add("infill_acceleration", coFloat);
def->label = L("Infill");
def->tooltip = L("This is the acceleration your printer will use for infill. Set zero to disable "
@ -2394,8 +2403,10 @@ void PrintConfigDef::init_sla_params()
def->tooltip = L("Display orientation");
def->cli = "display-orientation=s";
def->enum_keys_map = &ConfigOptionEnum<SLADisplayOrientation>::get_enum_values();
def->enum_values.push_back("Landscape");
def->enum_values.push_back("Portrait");
def->enum_values.push_back("landscape");
def->enum_values.push_back("portrait");
def->enum_labels.push_back(L("Landscape"));
def->enum_labels.push_back(L("Portrait"));
def->default_value = new ConfigOptionEnum<SLADisplayOrientation>(sladoPortrait);
def = this->add("printer_correction", coFloats);

View file

@ -155,8 +155,8 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<FilamentType>::ge
template<> inline const t_config_enum_values& ConfigOptionEnum<SLADisplayOrientation>::get_enum_values() {
static const t_config_enum_values keys_map = {
{ "Landscape", sladoLandscape},
{ "Portrait", sladoPortrait}
{ "landscape", sladoLandscape},
{ "portrait", sladoPortrait}
};
return keys_map;
@ -627,6 +627,7 @@ public:
ConfigOptionBool variable_layer_height;
ConfigOptionFloat cooling_tube_retraction;
ConfigOptionFloat cooling_tube_length;
ConfigOptionBool high_current_on_filament_swap;
ConfigOptionFloat parking_pos_retraction;
ConfigOptionBool remaining_times;
ConfigOptionBool silent_mode;
@ -695,6 +696,7 @@ protected:
OPT_PTR(variable_layer_height);
OPT_PTR(cooling_tube_retraction);
OPT_PTR(cooling_tube_length);
OPT_PTR(high_current_on_filament_swap);
OPT_PTR(parking_pos_retraction);
OPT_PTR(remaining_times);
OPT_PTR(silent_mode);

View file

@ -384,6 +384,14 @@ void PrintObject::generate_support_material()
m_print->set_status(85, "Generating support material");
this->_generate_support_material();
m_print->throw_if_canceled();
} else {
#if 0
// Printing without supports. Empty layer means some objects or object parts are levitating,
// therefore they cannot be printed without supports.
for (const Layer *layer : m_layers)
if (layer->empty())
throw std::runtime_error("Levitating objects cannot be printed without supports.");
#endif
}
this->set_done(posSupportMaterial);
}
@ -522,11 +530,13 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|| opt_key == "perimeter_speed"
|| opt_key == "small_perimeter_speed"
|| opt_key == "solid_infill_speed"
|| opt_key == "top_solid_infill_speed"
|| opt_key == "wipe_into_infill" // when these these two are changed, we only need to invalidate the wipe tower,
|| opt_key == "wipe_into_objects" // which we already did at the very beginning - nothing more to be done
) {
// these options only affect G-code export, so nothing to invalidate
|| opt_key == "top_solid_infill_speed") {
invalidated |= m_print->invalidate_step(psGCodeExport);
} else if (
opt_key == "wipe_into_infill"
|| opt_key == "wipe_into_objects") {
invalidated |= m_print->invalidate_step(psWipeTower);
invalidated |= m_print->invalidate_step(psGCodeExport);
} else {
// for legacy, if we can't handle this option let's invalidate all steps
this->invalidate_all_steps();
@ -1463,10 +1473,8 @@ void PrintObject::_slice()
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - removing top empty layers";
while (! m_layers.empty()) {
const Layer *layer = m_layers.back();
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
if (layer->m_regions[region_id] != nullptr && ! layer->m_regions[region_id]->slices.empty())
// Non empty layer.
goto end;
if (! layer->empty())
goto end;
delete layer;
m_layers.pop_back();
if (! m_layers.empty())

View file

@ -420,6 +420,12 @@ void swapXY(ExPolygon& expoly) {
}
template<class...Args>
void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) {
BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
p.set_status(st, msg, std::forward<Args>(args)...);
}
void SLAPrint::process()
{
using namespace sla;
@ -525,9 +531,11 @@ void SLAPrint::process()
// scaling for the sub operations
double d = *stthis / (objcount * 100.0);
ctl.statuscb = [this, init, d](unsigned st, const std::string& msg){
set_status(int(init + st*d), msg);
ctl.statuscb = [this, init, d](unsigned st, const std::string& msg)
{
report_status(*this, int(init + st*d), msg);
};
ctl.stopcondition = [this](){ return canceled(); };
ctl.cancelfn = [this]() { throw_if_canceled(); };
@ -537,9 +545,9 @@ void SLAPrint::process()
// Create the unified mesh
auto rc = SlicingStatus::RELOAD_SCENE;
set_status(-1, L("Visualizing supports"));
report_status(*this, -1, L("Visualizing supports"));
po.m_supportdata->support_tree_ptr->merged_mesh();
set_status(-1, L("Visualizing supports"), rc);
report_status(*this, -1, L("Visualizing supports"), rc);
} catch(sla::SLASupportsStoppedException&) {
// no need to rethrow
// throw_if_canceled();
@ -582,7 +590,7 @@ void SLAPrint::process()
po.throw_if_canceled();
auto rc = SlicingStatus::RELOAD_SCENE;
set_status(-1, L("Visualizing supports"), rc);
report_status(*this, -1, L("Visualizing supports"), rc);
};
// Slicing the support geometries similarly to the model slicing procedure.
@ -741,8 +749,12 @@ void SLAPrint::process()
auto lvlcnt = unsigned(m_printer_input.size());
printer.layers(lvlcnt);
// slot is the portion of 100% that is realted to rasterization
unsigned slot = PRINT_STEP_LEVELS[slapsRasterize];
// ist: initial state; pst: previous state
unsigned ist = max_objstatus, pst = ist;
// coefficient to map the rasterization state (0-99) to the allocated
// portion (slot) of the process state
double sd = (100 - ist) / 100.0;
SpinMutex slck;
@ -779,11 +791,11 @@ void SLAPrint::process()
// Finish the layer for later saving it.
printer.finish_layer(level_id);
// Status indication
// Status indication guarded with the spinlock
auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size());
{ std::lock_guard<SpinMutex> lck(slck);
if( st > pst) {
set_status(int(st), PRINT_STEP_LABELS[slapsRasterize]);
report_status(*this, int(st), PRINT_STEP_LABELS[slapsRasterize]);
pst = st;
}
}
@ -833,9 +845,14 @@ void SLAPrint::process()
unsigned st = min_objstatus;
unsigned incr = 0;
BOOST_LOG_TRIVIAL(info) << "Start slicing process.";
// TODO: this loop could run in parallel but should not exhaust all the CPU
// power available
for(SLAPrintObject * po : m_objects) {
BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name;
for(size_t s = 0; s < objectsteps.size(); ++s) {
auto currentstep = objectsteps[s];
@ -847,8 +864,7 @@ void SLAPrint::process()
st += unsigned(incr * ostepd);
if(po->m_stepmask[currentstep] && po->set_started(currentstep)) {
set_status(int(st), OBJ_STEP_LABELS[currentstep]);
report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]);
pobj_program[currentstep](*po);
po->set_done(currentstep);
}
@ -873,7 +889,7 @@ void SLAPrint::process()
if(m_stepmask[currentstep] && set_started(currentstep))
{
set_status(int(st), PRINT_STEP_LABELS[currentstep]);
report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]);
print_program[currentstep]();
set_done(currentstep);
}
@ -882,7 +898,7 @@ void SLAPrint::process()
}
// If everything vent well
set_status(100, L("Slicing done"));
report_status(*this, 100, L("Slicing done"));
}
bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)