mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-01 12:51:12 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1d14329d9 | ||
|
|
236a8786ef | ||
|
|
92d30fbc55 |
@@ -6,8 +6,6 @@
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace Slic3r {
|
||||
using RGB = std::array<float, 3>;
|
||||
using RGBA = std::array<float, 4>;
|
||||
|
||||
@@ -1692,9 +1692,9 @@ void Layer::make_ironing()
|
||||
ironing_params.just_infill = false;
|
||||
// ORCA: Get filament-specific overrides if configured, otherwise use process values
|
||||
size_t extruder_idx = ironing_params.extruder - 1;
|
||||
ironing_params.line_spacing = (!config.filament_ironing_spacing.is_nil(extruder_idx)
|
||||
ironing_params.line_spacing = std::max(IRONING_SPACING_MIN, !config.filament_ironing_spacing.is_nil(extruder_idx)
|
||||
? config.filament_ironing_spacing.get_at(extruder_idx)
|
||||
: config.ironing_spacing);
|
||||
: config.ironing_spacing.value);
|
||||
ironing_params.inset = (!config.filament_ironing_inset.is_nil(extruder_idx)
|
||||
? config.filament_ironing_inset.get_at(extruder_idx)
|
||||
: config.ironing_inset);
|
||||
|
||||
@@ -22,6 +22,9 @@ void FillConcentric::_fill_surface_single(
|
||||
|
||||
coord_t min_spacing = scale_(this->spacing) * params.multiline;
|
||||
coord_t distance = coord_t(min_spacing / params.density);
|
||||
// A non-positive step never shrinks the region, so the inset loop below would not end.
|
||||
if (min_spacing <= 0 || distance <= 0)
|
||||
return;
|
||||
|
||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
||||
@@ -108,6 +111,8 @@ void FillConcentric::_fill_surface_single(const FillParams& params,
|
||||
// no rotation is supported for this infill pattern
|
||||
Point bbox_size = expolygon.contour.bounding_box().size();
|
||||
coord_t min_spacing = scaled<coord_t>(this->spacing);
|
||||
if (min_spacing <= 0)
|
||||
return;
|
||||
|
||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
|
||||
|
||||
+23
-13
@@ -7313,7 +7313,7 @@ static std::unique_ptr<EdgeGrid::Grid> calculate_layer_edge_grid(const Layer& la
|
||||
std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
|
||||
const std::string& description,
|
||||
double speed,
|
||||
const ExtrusionEntitiesPtr& region_perimeters,
|
||||
const std::vector<const ExtrusionEntity*>& region_perimeters,
|
||||
const Point* start_point,
|
||||
const WipeInwardSupport* wipe_support)
|
||||
{
|
||||
@@ -7662,7 +7662,7 @@ std::string GCode::extrude_multi_path(const ExtrusionMultiPath& multipath, const
|
||||
std::string GCode::extrude_entity(const ExtrusionEntity& entity,
|
||||
const std::string& description,
|
||||
double speed,
|
||||
const ExtrusionEntitiesPtr& region_perimeters,
|
||||
const std::vector<const ExtrusionEntity*>& region_perimeters,
|
||||
const WipeInwardSupport* wipe_support)
|
||||
{
|
||||
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
|
||||
@@ -7755,22 +7755,31 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
|
||||
std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, bool ironing)
|
||||
{
|
||||
std::string gcode;
|
||||
ExtrusionEntitiesPtr extrusions;
|
||||
std::vector<const ExtrusionEntity*> extrusions;
|
||||
std::vector<std::unique_ptr<ExtrusionEntity>> reversed;
|
||||
const char* extrusion_name = ironing ? "ironing" : "infill";
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
||||
if (! region.infills.empty()) {
|
||||
extrusions.clear();
|
||||
extrusions.reserve(region.infills.size());
|
||||
for (ExtrusionEntity *ee : region.infills)
|
||||
for (const ExtrusionEntity *ee : region.infills)
|
||||
if ((ee->role() == erIroning) == ironing)
|
||||
extrusions.emplace_back(ee);
|
||||
if (! extrusions.empty()) {
|
||||
m_config.apply(print.get_print_region(®ion - &by_region.front()).config());
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
|
||||
reversed.clear();
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point(), reversed);
|
||||
// The reversed copies are in chain order.
|
||||
auto next_reversed = reversed.begin();
|
||||
for (const ExtrusionEntity *fill : extrusions) {
|
||||
ExtrusionEntity *own_copy = next_reversed != reversed.end() && next_reversed->get() == fill ? (next_reversed++)->get() : nullptr;
|
||||
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
||||
if (eec) {
|
||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos.to_point()).entities)
|
||||
// A reversed copy is owned here and can be moved from.
|
||||
ExtrusionEntityCollection chained = own_copy ? std::move(static_cast<ExtrusionEntityCollection&>(*own_copy)) : ExtrusionEntityCollection(*eec);
|
||||
if (!chained.no_sort)
|
||||
chain_and_reorder_extrusion_entities(chained.entities, m_last_pos.to_point());
|
||||
for (ExtrusionEntity *ee : chained.entities)
|
||||
gcode += this->extrude_entity(*ee, extrusion_name);
|
||||
} else
|
||||
gcode += this->extrude_entity(*fill, extrusion_name);
|
||||
@@ -7808,9 +7817,9 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
|
||||
std::string gcode;
|
||||
if (!support_fills.entities.empty()) {
|
||||
|
||||
ExtrusionEntitiesPtr extrusions;
|
||||
std::vector<const ExtrusionEntity*> extrusions;
|
||||
extrusions.reserve(support_fills.entities.size());
|
||||
for (ExtrusionEntity* ee : support_fills.entities) {
|
||||
for (const ExtrusionEntity* ee : support_fills.entities) {
|
||||
const auto role = ee->role();
|
||||
if ((role == support_extrusion_role) || (support_extrusion_role == erMixed && role != erIroning)) {
|
||||
extrusions.emplace_back(ee);
|
||||
@@ -7819,9 +7828,10 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
|
||||
if (extrusions.empty())
|
||||
return gcode;
|
||||
|
||||
std::vector<std::unique_ptr<ExtrusionEntity>> reversed;
|
||||
//ORCA: Respect no_sort to preserve support base outline->fill order.
|
||||
if (!support_fills.no_sort)
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point(), reversed);
|
||||
|
||||
for (const ExtrusionEntity *ee : extrusions) {
|
||||
ExtrusionRole role = ee->role();
|
||||
@@ -10054,8 +10064,8 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
||||
// Now we are going to iterate through perimeters and infills and pick ones that are supposed to be printed
|
||||
// References are used so that we don't have to repeat the same code
|
||||
for (int iter = 0; iter < 2; ++iter) {
|
||||
const ExtrusionEntitiesPtr& entities = (iter ? reg.infills : reg.perimeters);
|
||||
ExtrusionEntitiesPtr& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters);
|
||||
const std::vector<const ExtrusionEntity*>& entities = (iter ? reg.infills : reg.perimeters);
|
||||
std::vector<const ExtrusionEntity*>& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters);
|
||||
const std::vector<const WipingExtrusions::ExtruderPerCopy*>& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides);
|
||||
|
||||
// Now the most important thing - which extrusion should we print.
|
||||
@@ -10090,7 +10100,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
||||
void GCode::ObjectByExtruder::Island::Region::append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copies_extruder)
|
||||
{
|
||||
// We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves:
|
||||
ExtrusionEntitiesPtr* perimeters_or_infills;
|
||||
std::vector<const ExtrusionEntity*>* perimeters_or_infills;
|
||||
std::vector<const WipingExtrusions::ExtruderPerCopy*>* perimeters_or_infills_overrides;
|
||||
|
||||
switch (type) {
|
||||
@@ -10114,7 +10124,7 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
|
||||
for (auto* ee : eec->entities)
|
||||
perimeters_or_infills->emplace_back(ee);
|
||||
} else
|
||||
perimeters_or_infills->emplace_back(const_cast<ExtrusionEntityCollection*>(eec));
|
||||
perimeters_or_infills->emplace_back(eec);
|
||||
|
||||
if (copies_extruder != nullptr) {
|
||||
// Don't reallocate overrides if not needed.
|
||||
|
||||
@@ -453,14 +453,14 @@ private:
|
||||
std::string extrude_entity(const ExtrusionEntity& entity,
|
||||
const std::string& description = "",
|
||||
double speed = -1.,
|
||||
const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr(),
|
||||
const std::vector<const ExtrusionEntity*>& region_perimeters = {},
|
||||
const WipeInwardSupport* wipe_support = nullptr);
|
||||
// Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop
|
||||
// should be executed
|
||||
std::string extrude_loop(const ExtrusionLoop& loop,
|
||||
const std::string& description,
|
||||
double speed = -1.,
|
||||
const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr(),
|
||||
const std::vector<const ExtrusionEntity*>& region_perimeters = {},
|
||||
const Point* start_point = nullptr,
|
||||
const WipeInwardSupport* wipe_support = nullptr);
|
||||
std::string extrude_multi_path(const ExtrusionMultiPath& multipath, const std::string& description = "", double speed = -1.);
|
||||
@@ -493,10 +493,9 @@ private:
|
||||
{
|
||||
struct Region {
|
||||
// Non-owned references to LayerRegion::perimeters::entities
|
||||
// std::vector<const ExtrusionEntity*> would be better here, but there is no way in C++ to convert from std::vector<T*> std::vector<const T*> without copying.
|
||||
ExtrusionEntitiesPtr perimeters;
|
||||
std::vector<const ExtrusionEntity*> perimeters;
|
||||
// Non-owned references to LayerRegion::fills::entities
|
||||
ExtrusionEntitiesPtr infills;
|
||||
std::vector<const ExtrusionEntity*> infills;
|
||||
|
||||
std::vector<const WipingExtrusions::ExtruderPerCopy*> infills_overrides;
|
||||
std::vector<const WipingExtrusions::ExtruderPerCopy*> perimeters_overrides;
|
||||
|
||||
@@ -180,6 +180,10 @@ enum class IroningType {
|
||||
Count,
|
||||
};
|
||||
|
||||
// Smallest usable ironing line spacing. Anything tighter yields an unprintable number of lines,
|
||||
// and zero stops the fillers from making progress.
|
||||
constexpr double IRONING_SPACING_MIN = 0.05;
|
||||
|
||||
//BBS
|
||||
enum class WallInfillOrder {
|
||||
InnerOuterInfill,
|
||||
|
||||
@@ -1024,13 +1024,14 @@ std::vector<std::pair<size_t, bool>> chain_segments_greedy2(SegmentEndPointFunc
|
||||
return chain_segments_greedy_constrained_reversals2_<PointType, SegmentEndPointFunc, false, decltype(could_reverse_func)>(end_point_func, could_reverse_func, num_segments, start_near);
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
|
||||
template<typename EntityPtr>
|
||||
static std::vector<std::pair<size_t, bool>> chain_extrusion_entities_impl(const std::vector<EntityPtr> &entities, const Point *start_near)
|
||||
{
|
||||
auto segment_end_point = [&entities](size_t idx, bool first_point) -> 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 (std::pair<size_t, bool> &segment : out) {
|
||||
ExtrusionEntity *ee = entities[segment.first];
|
||||
const ExtrusionEntity *ee = entities[segment.first];
|
||||
if (ee->is_loop())
|
||||
// Ignore reversals for loops, as the start point equals the end point.
|
||||
segment.second = false;
|
||||
@@ -1040,6 +1041,20 @@ std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<Extrus
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
|
||||
{
|
||||
return chain_extrusion_entities_impl(entities, start_near);
|
||||
}
|
||||
|
||||
// Orca: Reordering queries first_point() / last_point(); drop entities that cannot provide valid endpoints.
|
||||
template<typename EntityPtr>
|
||||
static void remove_entities_without_endpoints(std::vector<EntityPtr> &entities)
|
||||
{
|
||||
entities.erase(std::remove_if(entities.begin(), entities.end(),
|
||||
[](const ExtrusionEntity *entity) { return !extrusion_entity_has_endpoints(entity); }),
|
||||
entities.end());
|
||||
}
|
||||
|
||||
void reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const std::vector<std::pair<size_t, bool>> &chain)
|
||||
{
|
||||
assert(entities.size() == chain.size());
|
||||
@@ -1061,14 +1076,27 @@ void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entitie
|
||||
|
||||
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
|
||||
{
|
||||
// Orca: Reordering queries first_point() / last_point(); drop entities that cannot provide valid endpoints.
|
||||
entities.erase(std::remove_if(entities.begin(), entities.end(), [](ExtrusionEntity *entity) {
|
||||
return !extrusion_entity_has_endpoints(entity);
|
||||
}),
|
||||
entities.end());
|
||||
remove_entities_without_endpoints(entities);
|
||||
reorder_extrusion_entities(entities, chain_extrusion_entities(entities, start_near));
|
||||
}
|
||||
|
||||
void chain_and_reorder_extrusion_entities(std::vector<const ExtrusionEntity*> &entities, const Point &start_near,
|
||||
std::vector<std::unique_ptr<ExtrusionEntity>> &reversed_clones)
|
||||
{
|
||||
remove_entities_without_endpoints(entities);
|
||||
std::vector<const ExtrusionEntity*> out;
|
||||
out.reserve(entities.size());
|
||||
for (const auto &[idx, reverse] : chain_extrusion_entities_impl(entities, &start_near)) {
|
||||
if (reverse) {
|
||||
ExtrusionEntity *clone = reversed_clones.emplace_back(entities[idx]->clone()).get();
|
||||
clone->reverse();
|
||||
out.emplace_back(clone);
|
||||
} else
|
||||
out.emplace_back(entities[idx]);
|
||||
}
|
||||
entities.swap(out);
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_t, bool>> chain_extrusion_paths(std::vector<ExtrusionPath> &extrusion_paths, const Point *start_near)
|
||||
{
|
||||
auto segment_end_point = [&extrusion_paths](size_t idx, bool first_point) -> Point { return first_point ? extrusion_paths[idx].first_point() : extrusion_paths[idx].last_point(); };
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "Point.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -24,6 +25,9 @@ std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<Extrus
|
||||
void reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const std::vector<std::pair<size_t, bool>> &chain);
|
||||
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point &start_near);
|
||||
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near = nullptr);
|
||||
// Each entity the chain reverses is replaced by a reversed clone that reversed_clones owns, so the originals stay unchanged.
|
||||
void chain_and_reorder_extrusion_entities(std::vector<const ExtrusionEntity*> &entities, const Point &start_near,
|
||||
std::vector<std::unique_ptr<ExtrusionEntity>> &reversed_clones);
|
||||
|
||||
std::vector<std::pair<size_t, bool>> chain_extrusion_paths(std::vector<ExtrusionPath> &extrusion_paths, const Point *start_near = nullptr);
|
||||
void reorder_extrusion_paths(std::vector<ExtrusionPath> &extrusion_paths, std::vector<std::pair<size_t, bool>> &chain);
|
||||
|
||||
@@ -64,7 +64,7 @@ struct SupportParameters {
|
||||
|
||||
this->ironing = object_config.support_ironing;
|
||||
this->ironing_flow = support_material_interface_flow.with_height(support_material_interface_flow.height() * 0.01 * object_config.support_ironing_flow.value);
|
||||
this->ironing_spacing = object_config.support_ironing_spacing;
|
||||
this->ironing_spacing = std::max(IRONING_SPACING_MIN, object_config.support_ironing_spacing.value);
|
||||
this->ironing_pattern = object_config.support_ironing_pattern;
|
||||
|
||||
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
|
||||
|
||||
@@ -212,6 +212,30 @@ void ConfigManipulation::check_filament_max_volumetric_speed(DynamicPrintConfig
|
||||
|
||||
}
|
||||
|
||||
void ConfigManipulation::check_filament_ironing_spacing(DynamicPrintConfig *config)
|
||||
{
|
||||
const auto *opt = config->option<ConfigOptionFloatsNullable>("filament_ironing_spacing");
|
||||
if (opt == nullptr)
|
||||
return;
|
||||
std::vector<double> values = opt->values;
|
||||
bool reset = false;
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
if (!opt->is_nil(i) && values[i] < IRONING_SPACING_MIN) {
|
||||
values[i] = 0.1;
|
||||
reset = true;
|
||||
}
|
||||
if (!reset)
|
||||
return;
|
||||
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *config;
|
||||
is_msg_dlg_already_exist = true;
|
||||
dialog.ShowModal();
|
||||
new_conf.set_key_value("filament_ironing_spacing", new ConfigOptionFloatsNullable(values));
|
||||
apply(config, &new_conf);
|
||||
is_msg_dlg_already_exist = false;
|
||||
}
|
||||
|
||||
void ConfigManipulation::check_chamber_temperature(DynamicPrintConfig* config)
|
||||
{
|
||||
bool support_chamber_temp_control=GUI::wxGetApp().preset_bundle->printers.get_selected_preset().config.opt_bool("support_chamber_temp_control");
|
||||
@@ -334,7 +358,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
}
|
||||
|
||||
//BBS: ironing_spacing shouldn't be too small or equal to zero
|
||||
if (config->opt_float("ironing_spacing") < 0.05)
|
||||
if (config->opt_float("ironing_spacing") < IRONING_SPACING_MIN)
|
||||
{
|
||||
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||
@@ -345,7 +369,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
apply(config, &new_conf);
|
||||
is_msg_dlg_already_exist = false;
|
||||
}
|
||||
if (config->opt_float("support_ironing_spacing") < 0.05)
|
||||
if (config->opt_float("support_ironing_spacing") < IRONING_SPACING_MIN)
|
||||
{
|
||||
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
void check_nozzle_temperature_initial_layer_range(DynamicPrintConfig* config, unsigned int variant_index);
|
||||
void check_adaptive_pressure_advance_model(DynamicPrintConfig* config);
|
||||
void check_filament_max_volumetric_speed(DynamicPrintConfig *config);
|
||||
void check_filament_ironing_spacing(DynamicPrintConfig *config);
|
||||
void check_chamber_temperature(DynamicPrintConfig* config);
|
||||
void check_chamber_minimal_temperature(DynamicPrintConfig* config);
|
||||
bool check_layer_height(DynamicPrintConfig* config);
|
||||
|
||||
@@ -4911,6 +4911,7 @@ void TabFilament::update()
|
||||
return; // ys_FIXME
|
||||
|
||||
m_config_manipulation.check_filament_max_volumetric_speed(m_config);
|
||||
m_config_manipulation.check_filament_ironing_spacing(m_config);
|
||||
|
||||
m_update_cnt++;
|
||||
|
||||
|
||||
@@ -748,6 +748,61 @@ TEST_CASE("A region with ironing turned off is never ironed", "[Fill]")
|
||||
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
||||
}
|
||||
|
||||
// Ironing path count and total length in mm, over the whole object.
|
||||
static std::pair<size_t, double> ironing_extent(const Print &print)
|
||||
{
|
||||
size_t paths = 0;
|
||||
double length = 0.;
|
||||
for (const Layer *layer : print.objects().front()->layers())
|
||||
for (const LayerRegion *region : layer->regions())
|
||||
for (const ExtrusionEntity *entity : region->fills.flatten().entities)
|
||||
if (ironing_role(entity->role())) {
|
||||
++paths;
|
||||
length += unscale<double>(entity->length());
|
||||
}
|
||||
return {paths, length};
|
||||
}
|
||||
|
||||
TEST_CASE("Ironing spacing below the minimum irons at the minimum spacing", "[Fill]")
|
||||
{
|
||||
const std::string pattern = GENERATE("rectilinear", "concentric");
|
||||
const bool via_filament = GENERATE(false, true);
|
||||
const double spacing = GENERATE(0., 0.001);
|
||||
CAPTURE(pattern, via_filament, spacing);
|
||||
|
||||
auto ironing_for = [&pattern, via_filament](double spacing) {
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
config.set_deserialize_strict({{"ironing_type", "top"},
|
||||
{"ironing_pattern", pattern},
|
||||
{"layer_height", 0.2}});
|
||||
// The filament override replaces the process spacing, which stays at a usable value.
|
||||
if (via_filament)
|
||||
config.set_deserialize_strict({{"ironing_spacing", 0.1}, {"filament_ironing_spacing", spacing}});
|
||||
else
|
||||
config.set_deserialize_strict({{"ironing_spacing", spacing}});
|
||||
Print print;
|
||||
Slic3r::Test::init_and_process_print({Slic3r::Test::cube(20)}, print, config);
|
||||
return ironing_extent(print);
|
||||
};
|
||||
|
||||
const std::pair<size_t, double> clamped = ironing_for(spacing);
|
||||
const std::pair<size_t, double> minimum = ironing_for(IRONING_SPACING_MIN);
|
||||
REQUIRE(minimum.first > 0);
|
||||
CHECK(clamped.first == minimum.first);
|
||||
CHECK_THAT(clamped.second, Catch::Matchers::WithinRel(minimum.second, 1e-9));
|
||||
}
|
||||
|
||||
TEST_CASE("Concentric fill at zero spacing returns without paths", "[Fill]")
|
||||
{
|
||||
std::unique_ptr<Fill> filler(Fill::new_from_type(ipConcentric));
|
||||
filler->spacing = 0.;
|
||||
filler->bounding_box = BoundingBox(Point(0, 0), Point::new_scale(10, 10));
|
||||
FillParams params;
|
||||
params.density = 1.f;
|
||||
Surface surface(stTop, ExPolygon({Point(0, 0), Point::new_scale(10, 0), Point::new_scale(10, 10), Point::new_scale(0, 10)}));
|
||||
CHECK(filler->fill_surface(&surface, params).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
||||
{
|
||||
auto angles_for = [](int direction) {
|
||||
|
||||
@@ -225,7 +225,7 @@ DynamicPrintConfig multifilament_config(unsigned int filaments, std::initializer
|
||||
}
|
||||
|
||||
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
|
||||
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> *per_object_overrides, bool arrange)
|
||||
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> *per_object_overrides, bool arrange, size_t instances)
|
||||
{
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
config.apply(config_in);
|
||||
@@ -236,6 +236,7 @@ void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r
|
||||
ModelObject *object = model.add_object();
|
||||
object->name += "object.stl";
|
||||
object->add_volume(std::move(t));
|
||||
for (size_t i = 0; i < instances; ++i)
|
||||
object->add_instance();
|
||||
|
||||
if (per_object_overrides && object_idx < per_object_overrides->size() && !(*per_object_overrides)[object_idx].empty()) {
|
||||
|
||||
@@ -72,9 +72,11 @@ Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh);
|
||||
DynamicPrintConfig multifilament_config(unsigned int filaments,
|
||||
std::initializer_list<Slic3r::ConfigBase::SetDeserializeItem> extra = {});
|
||||
|
||||
// Apply `meshes` and config to `print`/`model`; optional per-object overrides, auto-arranged unless `arrange` is false.
|
||||
// Apply `meshes` and config to `print`/`model`, each object with `instances` copies; optional per-object overrides,
|
||||
// auto-arranged unless `arrange` is false.
|
||||
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
|
||||
const std::vector<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> *per_object_overrides = nullptr, bool arrange = true);
|
||||
const std::vector<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> *per_object_overrides = nullptr, bool arrange = true,
|
||||
size_t instances = 1);
|
||||
void init_print(std::initializer_list<TestMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config());
|
||||
void init_print(std::initializer_list<TriangleMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config());
|
||||
void init_print(std::initializer_list<TestMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, std::initializer_list<Slic3r::ConfigBase::SetDeserializeItem> config_items);
|
||||
|
||||
@@ -561,6 +561,40 @@ TEST_CASE("export_gcode writes G-code without a result pointer", "[Print][export
|
||||
REQUIRE_FALSE(gcode.empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Exporting a sliced print again gives the same G-code", "[Print][export_gcode][Regression]")
|
||||
{
|
||||
const int instances = GENERATE(1, 3);
|
||||
CAPTURE(instances);
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
TestMesh mesh = TestMesh::ipadstand;
|
||||
SECTION("infill reversed by chaining") { config.set_deserialize_strict({{"sparse_infill_pattern", "gyroid"}}); }
|
||||
SECTION("support reversed by chaining") {
|
||||
mesh = TestMesh::overhang;
|
||||
config.set_deserialize_strict({{"enable_support", true}, {"support_interface_pattern", "concentric"}});
|
||||
}
|
||||
Print print;
|
||||
Model model;
|
||||
Slic3r::Test::init_print({Slic3r::Test::mesh(mesh)}, print, model, config, nullptr, true, instances);
|
||||
|
||||
const auto export_without_timestamp = [&print]() {
|
||||
std::string gcode = Slic3r::Test::gcode(print);
|
||||
const size_t line = gcode.find("; generated by ");
|
||||
REQUIRE(line != std::string::npos);
|
||||
gcode.erase(line, gcode.find('\n', line) - line);
|
||||
return gcode;
|
||||
};
|
||||
const std::string first = export_without_timestamp();
|
||||
const std::string second = export_without_timestamp();
|
||||
|
||||
// Shows the first differing line on failure.
|
||||
const size_t diff = std::mismatch(first.begin(), first.end(), second.begin(), second.end()).first - first.begin();
|
||||
const size_t line_start = diff == 0 ? 0 : first.rfind('\n', diff - 1) + 1;
|
||||
INFO("first export: " << first.substr(line_start, first.find('\n', diff) - line_start));
|
||||
INFO("second export: " << second.substr(line_start, second.find('\n', diff) - line_start));
|
||||
CHECK(diff == first.size());
|
||||
CHECK(first.size() == second.size());
|
||||
}
|
||||
|
||||
TEST_CASE("Sequential printing follows model order", "[Print]")
|
||||
{
|
||||
// Two objects of different heights, taller one added first. Orca prints
|
||||
|
||||
@@ -1,39 +1,6 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "slic3r/Utils/Http.hpp"
|
||||
#include "slic3r/Utils/OrcaCloudServiceAgent.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
nlohmann::json flat_session_json(const nlohmann::json& fields)
|
||||
{
|
||||
nlohmann::json session = {
|
||||
{"access_token", "test-token"},
|
||||
{"user_id", "test-user-id"}
|
||||
};
|
||||
session.update(fields);
|
||||
return session;
|
||||
}
|
||||
|
||||
nlohmann::json nested_session_json(const nlohmann::json& metadata)
|
||||
{
|
||||
return {
|
||||
{"access_token", "test-token"},
|
||||
{"user", {
|
||||
{"id", "test-user-id"},
|
||||
{"user_metadata", metadata}
|
||||
}}
|
||||
};
|
||||
}
|
||||
|
||||
std::string resolved_display_name(const nlohmann::json& session)
|
||||
{
|
||||
Slic3r::OrcaCloudServiceAgent agent("");
|
||||
REQUIRE(agent.set_user_session(session, false));
|
||||
return agent.get_user_nickname();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") {
|
||||
|
||||
@@ -53,62 +20,6 @@ TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") {
|
||||
REQUIRE(status == 200);
|
||||
}
|
||||
|
||||
TEST_CASE("Orca cloud flat session resolves display name consistently", "[OrcaCloudServiceAgent]")
|
||||
{
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"display_name", "Display Name"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Display Name");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Nickname");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"full_name", "Full Name"}
|
||||
})) == "Full Name");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"name", "Provider Name"}
|
||||
})) == "Provider Name");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"}
|
||||
})) == "orca_username");
|
||||
}
|
||||
|
||||
TEST_CASE("Orca cloud nested session resolves display name consistently", "[OrcaCloudServiceAgent]")
|
||||
{
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"display_name", "Display Name"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Display Name");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Nickname");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"full_name", "Full Name"}
|
||||
})) == "Full Name");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"name", "Provider Name"}
|
||||
})) == "Provider Name");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"}
|
||||
})) == "orca_username");
|
||||
}
|
||||
|
||||
TEST_CASE("Http digest authentication", "[Http][NotWorking]") {
|
||||
Slic3r::Http g = Slic3r::Http::get("https://httpbingo.org/digest-auth/auth/guest/guest");
|
||||
|
||||
|
||||
@@ -27,6 +27,37 @@ std::unique_ptr<OrcaCloudServiceAgent> make_file_backed_agent(const fs::path& di
|
||||
|
||||
fs::path secret_file(const fs::path& dir) { return dir / secret_constants::USER_SECRET_FILENAME; }
|
||||
|
||||
nlohmann::json flat_session_json(const nlohmann::json& fields)
|
||||
{
|
||||
nlohmann::json session = {
|
||||
{"access_token", "test-token"},
|
||||
{"user_id", "test-user-id"}
|
||||
};
|
||||
session.update(fields);
|
||||
return session;
|
||||
}
|
||||
|
||||
nlohmann::json nested_session_json(const nlohmann::json& metadata)
|
||||
{
|
||||
return {
|
||||
{"access_token", "test-token"},
|
||||
{"user", {
|
||||
{"id", "test-user-id"},
|
||||
{"user_metadata", metadata}
|
||||
}}
|
||||
};
|
||||
}
|
||||
|
||||
// set_user_session() persists the session, so it goes to a throwaway token file rather than the
|
||||
// system keychain of whoever runs the tests.
|
||||
std::string resolved_display_name(const nlohmann::json& session)
|
||||
{
|
||||
ScopedTemporaryDir dir("orca-secret");
|
||||
auto agent = make_file_backed_agent(dir.path());
|
||||
REQUIRE(agent->set_user_session(session, false));
|
||||
return agent->get_user_nickname();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Logging out removes the secret this instance saved", "[OrcaCloudServiceAgent]")
|
||||
@@ -84,3 +115,59 @@ TEST_CASE("Logging out leaves a secret this instance could not read alone", "[Or
|
||||
agent->user_logout(false);
|
||||
CHECK(fs::exists(secret_file(dir.path())));
|
||||
}
|
||||
|
||||
TEST_CASE("Orca cloud flat session resolves display name consistently", "[OrcaCloudServiceAgent]")
|
||||
{
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"display_name", "Display Name"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Display Name");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Nickname");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"full_name", "Full Name"}
|
||||
})) == "Full Name");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"name", "Provider Name"}
|
||||
})) == "Provider Name");
|
||||
|
||||
CHECK(resolved_display_name(flat_session_json({
|
||||
{"username", "orca_username"}
|
||||
})) == "orca_username");
|
||||
}
|
||||
|
||||
TEST_CASE("Orca cloud nested session resolves display name consistently", "[OrcaCloudServiceAgent]")
|
||||
{
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"display_name", "Display Name"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Display Name");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"nickname", "Nickname"}
|
||||
})) == "Nickname");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"full_name", "Full Name"}
|
||||
})) == "Full Name");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"},
|
||||
{"name", "Provider Name"}
|
||||
})) == "Provider Name");
|
||||
|
||||
CHECK(resolved_display_name(nested_session_json({
|
||||
{"username", "orca_username"}
|
||||
})) == "orca_username");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user