mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-15 23:12:08 +00:00
refactor(plugin): prefix SlicingPipelineStepPlugin values with pos/ps to mirror Print steps
This commit is contained in:
@@ -10,12 +10,12 @@
|
||||
# ///
|
||||
"""Inset Every Slice -- a small, WORKING SlicingPipeline sample plugin.
|
||||
|
||||
At Step.Slice, for every layer/region of the sliced object, this shrinks each
|
||||
At Step.posSlice, for every layer/region of the sliced object, this shrinks each
|
||||
sliced surface by INSET_MM using a real polygon offset (ExPolygon.offset) and
|
||||
writes the result back with SurfaceCollection.set(). After the per-region edits,
|
||||
layer.make_slices() re-derives the layer's merged islands (lslices) so
|
||||
overhang/bridge detection, skirt/brim and support stay coherent with the inset
|
||||
geometry. At Step.Slice the split slice loop runs make_perimeters() right after
|
||||
geometry. At Step.posSlice the split slice loop runs make_perimeters() right after
|
||||
the hook, so the change cascades into perimeters, infill and the final G-code
|
||||
-- the toolpath preview shrinks.
|
||||
|
||||
@@ -35,7 +35,7 @@ class InsetEverySlice(orca.slicing.SlicingPipelineCapabilityBase):
|
||||
return "Inset Every Slice"
|
||||
|
||||
def execute(self, ctx):
|
||||
if ctx.step != orca.slicing.Step.Slice or ctx.object is None:
|
||||
if ctx.step != orca.slicing.Step.posSlice or ctx.object is None:
|
||||
return orca.ExecutionResult.success()
|
||||
|
||||
# Millimeters -> scaled integer units via the *live* scale (never hardcode 1e6).
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# ///
|
||||
"""Twistify -- twist/taper/wobble any model at slice time.
|
||||
|
||||
At Step.Slice, every layer's sliced surfaces are transformed by a similarity
|
||||
At Step.posSlice, every layer's sliced surfaces are transformed by a similarity
|
||||
about the object's bounding-box center as a function of Z -- edited IN PLACE
|
||||
through the host geometry classes (ExPolygon.rotate/scale/translate). Each
|
||||
surface is rotated about the center, then (if tapering) translated to the
|
||||
@@ -81,7 +81,7 @@ class Twistify(orca.slicing.SlicingPipelineCapabilityBase):
|
||||
return "Twistify"
|
||||
|
||||
def execute(self, ctx):
|
||||
if ctx.step != orca.slicing.Step.Slice or ctx.object is None:
|
||||
if ctx.step != orca.slicing.Step.posSlice or ctx.object is None:
|
||||
return orca.ExecutionResult.success()
|
||||
|
||||
p = _params(ctx)
|
||||
|
||||
@@ -2319,7 +2319,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
|
||||
if (!use_cache) {
|
||||
// Fire the SlicingPipeline hook for `obj` iff it just (re)computed `pstep` this pass.
|
||||
auto hook_after = [this](PrintObject* obj, bool was_done, PrintObjectStep pstep, SlicingPipelineStep sstep) {
|
||||
auto hook_after = [this](PrintObject* obj, bool was_done, PrintObjectStep pstep, SlicingPipelineStepPlugin sstep) {
|
||||
if (m_pipeline_plugin_active && !was_done && obj->is_step_done(pstep))
|
||||
run_pipeline_hook(sstep, obj);
|
||||
};
|
||||
@@ -2329,7 +2329,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
if (need_slicing_objects.count(obj) != 0) {
|
||||
const bool was_done = obj->is_step_done(posSlice);
|
||||
obj->slice();
|
||||
hook_after(obj, was_done, posSlice, SlicingPipelineStep::Slice);
|
||||
hook_after(obj, was_done, posSlice, SlicingPipelineStepPlugin::posSlice);
|
||||
// re-snapshot each layer's raw_slices AFTER the Slice hook ran, so the
|
||||
// plugin's mutation becomes the untyped baseline. Without this, a later
|
||||
// perimeter-only re-run (make_perimeters -> restore_untyped_slices) reverts
|
||||
@@ -2349,7 +2349,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
if (need_slicing_objects.count(obj) != 0) {
|
||||
const bool was_done = obj->is_step_done(posPerimeters);
|
||||
obj->make_perimeters(); // slice() inside is a no-op: posSlice already DONE
|
||||
hook_after(obj, was_done, posPerimeters, SlicingPipelineStep::Perimeters);
|
||||
hook_after(obj, was_done, posPerimeters, SlicingPipelineStepPlugin::posPerimeters);
|
||||
} else {
|
||||
if (obj->set_started(posPerimeters)) obj->set_done(posPerimeters);
|
||||
}
|
||||
@@ -2358,7 +2358,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
if (need_slicing_objects.count(obj) != 0) {
|
||||
const bool was_done = obj->is_step_done(posEstimateCurledExtrusions);
|
||||
obj->estimate_curled_extrusions();
|
||||
hook_after(obj, was_done, posEstimateCurledExtrusions, SlicingPipelineStep::EstimateCurledExtrusions);
|
||||
hook_after(obj, was_done, posEstimateCurledExtrusions, SlicingPipelineStepPlugin::posEstimateCurledExtrusions);
|
||||
}
|
||||
else {
|
||||
if (obj->set_started(posEstimateCurledExtrusions))
|
||||
@@ -2374,10 +2374,10 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
// is DONE, so this is a mechanical split mirroring the slice/perimeters loop.
|
||||
const bool prepare_was_done = obj->is_step_done(posPrepareInfill);
|
||||
obj->prepare_infill();
|
||||
hook_after(obj, prepare_was_done, posPrepareInfill, SlicingPipelineStep::PrepareInfill);
|
||||
hook_after(obj, prepare_was_done, posPrepareInfill, SlicingPipelineStepPlugin::posPrepareInfill);
|
||||
const bool was_done = obj->is_step_done(posInfill);
|
||||
obj->infill();
|
||||
hook_after(obj, was_done, posInfill, SlicingPipelineStep::Infill);
|
||||
hook_after(obj, was_done, posInfill, SlicingPipelineStepPlugin::posInfill);
|
||||
}
|
||||
else {
|
||||
if (obj->set_started(posPrepareInfill))
|
||||
@@ -2390,7 +2390,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
if (need_slicing_objects.count(obj) != 0) {
|
||||
const bool was_done = obj->is_step_done(posIroning);
|
||||
obj->ironing();
|
||||
hook_after(obj, was_done, posIroning, SlicingPipelineStep::Ironing);
|
||||
hook_after(obj, was_done, posIroning, SlicingPipelineStepPlugin::posIroning);
|
||||
}
|
||||
else {
|
||||
if (obj->set_started(posIroning))
|
||||
@@ -2404,7 +2404,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
if (need_contouring) {
|
||||
const bool was_done = obj->is_step_done(posContouring);
|
||||
obj->contour_z();
|
||||
hook_after(obj, was_done, posContouring, SlicingPipelineStep::Contouring);
|
||||
hook_after(obj, was_done, posContouring, SlicingPipelineStepPlugin::posContouring);
|
||||
} else {
|
||||
if (obj->set_started(posContouring))
|
||||
obj->set_done(posContouring);
|
||||
@@ -2437,13 +2437,13 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
for (size_t i = 0; i < m_objects.size(); ++i)
|
||||
if (need_slicing_objects.count(m_objects[i]) != 0 && !sup_was_done[i]
|
||||
&& m_objects[i]->is_step_done(posSupportMaterial))
|
||||
run_pipeline_hook(SlicingPipelineStep::SupportMaterial, m_objects[i]);
|
||||
run_pipeline_hook(SlicingPipelineStepPlugin::posSupportMaterial, m_objects[i]);
|
||||
|
||||
for (PrintObject* obj : m_objects) {
|
||||
if (need_slicing_objects.count(obj) != 0) {
|
||||
const bool was_done = obj->is_step_done(posDetectOverhangsForLift);
|
||||
obj->detect_overhangs_for_lift();
|
||||
hook_after(obj, was_done, posDetectOverhangsForLift, SlicingPipelineStep::DetectOverhangsForLift);
|
||||
hook_after(obj, was_done, posDetectOverhangsForLift, SlicingPipelineStepPlugin::posDetectOverhangsForLift);
|
||||
}
|
||||
else {
|
||||
if (obj->set_started(posDetectOverhangsForLift))
|
||||
@@ -2520,7 +2520,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
|
||||
}
|
||||
this->set_done(psWipeTower);
|
||||
if (m_pipeline_plugin_active) run_pipeline_hook(SlicingPipelineStep::WipeTower, nullptr);
|
||||
if (m_pipeline_plugin_active) run_pipeline_hook(SlicingPipelineStepPlugin::psWipeTower, nullptr);
|
||||
}
|
||||
|
||||
if (this->has_wipe_tower()) {
|
||||
@@ -2646,7 +2646,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
|
||||
this->finalize_first_layer_convex_hull();
|
||||
this->set_done(psSkirtBrim);
|
||||
if (m_pipeline_plugin_active) run_pipeline_hook(SlicingPipelineStep::SkirtBrim, nullptr);
|
||||
if (m_pipeline_plugin_active) run_pipeline_hook(SlicingPipelineStepPlugin::psSkirtBrim, nullptr);
|
||||
|
||||
if (time_cost_with_cache) {
|
||||
end_time = (long long)Slic3r::Utils::get_current_time_utc();
|
||||
@@ -2663,7 +2663,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
// shared with the use_cache path (re_slicing_objects), so `!use_cache` must be checked
|
||||
// explicitly here to keep hooks from ever firing on cache-loaded (plugin-final) objects.
|
||||
if (!use_cache && m_pipeline_plugin_active && !was_done && obj->is_step_done(posSimplifyPath))
|
||||
run_pipeline_hook(SlicingPipelineStep::SimplifyPath, obj);
|
||||
run_pipeline_hook(SlicingPipelineStepPlugin::posSimplifyPath, obj);
|
||||
}
|
||||
else {
|
||||
if (obj->set_started(posSimplifyPath))
|
||||
|
||||
@@ -99,6 +99,11 @@ enum PrintObjectStep {
|
||||
posCount,
|
||||
};
|
||||
|
||||
enum class SlicingPipelineStepPlugin {
|
||||
posSlice, posPerimeters, posEstimateCurledExtrusions, posPrepareInfill, posInfill, posIroning, posContouring,
|
||||
posSupportMaterial, posDetectOverhangsForLift, posSimplifyPath, psWipeTower, psSkirtBrim
|
||||
};
|
||||
|
||||
// A PrintRegion object represents a group of volumes to print
|
||||
// sharing the same config (including the same assigned extruder(s))
|
||||
class PrintRegion
|
||||
@@ -882,11 +887,6 @@ enum FilamentCompatibilityType {
|
||||
InvalidTemperatureRange
|
||||
};
|
||||
|
||||
enum class SlicingPipelineStep {
|
||||
Slice, Perimeters, EstimateCurledExtrusions, PrepareInfill, Infill, Ironing, Contouring,
|
||||
SupportMaterial, DetectOverhangsForLift, SimplifyPath, WipeTower, SkirtBrim
|
||||
};
|
||||
|
||||
// The complete print tray with possibly multiple objects.
|
||||
class Print : public PrintBaseWithState<PrintStep, psCount>
|
||||
{
|
||||
@@ -896,7 +896,7 @@ private: // Prevents erroneous use by other classes.
|
||||
typedef std::pair<PrintObject *, bool> PrintObjectInfo;
|
||||
|
||||
public:
|
||||
using SlicingPipelineHookFn = std::function<void(Print&, const PrintObject*, SlicingPipelineStep)>;
|
||||
using SlicingPipelineHookFn = std::function<void(Print&, const PrintObject*, SlicingPipelineStepPlugin)>;
|
||||
// Cross-layer injection (mirrors ConfigBase::set_resolve_capability_fn): the GUI/plugin
|
||||
// layer registers a dispatcher; libslic3r stays free of any plugin/Python dependency.
|
||||
static void set_slicing_pipeline_hook_fn(SlicingPipelineHookFn fn) { s_slicing_pipeline_hook_fn = std::move(fn); }
|
||||
@@ -1159,7 +1159,7 @@ private:
|
||||
|
||||
static SlicingPipelineHookFn s_slicing_pipeline_hook_fn;
|
||||
bool m_pipeline_plugin_active { false };
|
||||
void run_pipeline_hook(SlicingPipelineStep step, const PrintObject* object) {
|
||||
void run_pipeline_hook(SlicingPipelineStepPlugin step, const PrintObject* object) {
|
||||
if (m_pipeline_plugin_active && s_slicing_pipeline_hook_fn)
|
||||
s_slicing_pipeline_hook_fn(*this, object, step);
|
||||
}
|
||||
|
||||
@@ -3130,7 +3130,7 @@ bool GUI_App::on_init_inner()
|
||||
// cancellation, and convert a plugin failure into a (non-critical) SlicingError so it surfaces as a
|
||||
// slicing-error notification rather than the fatal-crash dialog.
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[](Slic3r::Print& print, const Slic3r::PrintObject* object, Slic3r::SlicingPipelineStep step) {
|
||||
[](Slic3r::Print& print, const Slic3r::PrintObject* object, Slic3r::SlicingPipelineStepPlugin step) {
|
||||
const auto* caps = print.config().option<ConfigOptionStrings>("slicing_pipeline_plugin");
|
||||
// `plugins` is a dynamic-only manifest key (not a static PrintConfig member), so it
|
||||
// must be read from the full/dynamic config -- reading it off print.config() (the
|
||||
@@ -3180,10 +3180,10 @@ bool GUI_App::on_init_inner()
|
||||
// out in Release), so it must NOT be called from a pipeline hook.
|
||||
if (!r.message.empty()) {
|
||||
static const char* const kStepNames[] = {
|
||||
"Slice", "Perimeters", "EstimateCurledExtrusions", "PrepareInfill", "Infill",
|
||||
"Ironing", "Contouring", "SupportMaterial", "DetectOverhangsForLift",
|
||||
"SimplifyPath", "WipeTower", "SkirtBrim"
|
||||
}; // order must match Slic3r::SlicingPipelineStep
|
||||
"posSlice", "posPerimeters", "posEstimateCurledExtrusions", "posPrepareInfill", "posInfill",
|
||||
"posIroning", "posContouring", "posSupportMaterial", "posDetectOverhangsForLift",
|
||||
"posSimplifyPath", "psWipeTower", "psSkirtBrim"
|
||||
}; // order must match Slic3r::SlicingPipelineStepPlugin
|
||||
const char* step_name = static_cast<size_t>(step) < sizeof(kStepNames) / sizeof(kStepNames[0])
|
||||
? kStepNames[static_cast<int>(step)] : "Unknown";
|
||||
BOOST_LOG_TRIVIAL(info) << "Slicing pipeline plugin '" << ref.capability_name
|
||||
|
||||
@@ -1794,7 +1794,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
// always carries resolved "name;uuid;capability" references that full_config() and save_to_json()
|
||||
// then pass downstream as-is -- no separate rebuild anywhere else.
|
||||
if (const ConfigOptionDef* opt_def = m_config->def()->get(opt_key);
|
||||
opt_def && opt_def->gui_type == ConfigOptionDef::GUIType::plugin_picker)
|
||||
opt_def && opt_def->plugin_type != ConfigOptionDef::PluginType::None)
|
||||
m_config->update_plugin_manifest();
|
||||
|
||||
if (opt_key == "gcode_flavor" && m_type == Preset::TYPE_PRINTER) {
|
||||
|
||||
@@ -414,7 +414,7 @@ void PluginHostSlicing::RegisterBindings(py::module_& host)
|
||||
layer_region
|
||||
.def_readonly("slices", &LayerRegion::slices,
|
||||
"Sliced, typed surfaces (SurfaceCollection). Edit in place, or replace with "
|
||||
"slices.set(expolygons, surface_type). At Step.Slice this is the primary mutation "
|
||||
"slices.set(expolygons, surface_type). At Step.posSlice this is the primary mutation "
|
||||
"target; the split slice loop runs make_perimeters() afterward so edits cascade downstream.")
|
||||
.def_readonly("fill_surfaces", &LayerRegion::fill_surfaces,
|
||||
"Surfaces prepared for infill (SurfaceCollection). Edit in place or via fill_surfaces.set(...).")
|
||||
|
||||
@@ -13,19 +13,19 @@ void SlicingPipelinePluginCapability::RegisterBindings(py::module_& module, py::
|
||||
(void) pluginTypes; // matches gcode/script/printerAgent; Step is a fresh enum below.
|
||||
auto slicing = module.def_submodule("slicing", "Slicing pipeline API (research/experimental).");
|
||||
|
||||
py::enum_<SlicingPipelineStep>(slicing, "Step")
|
||||
.value("Slice", SlicingPipelineStep::Slice)
|
||||
.value("Perimeters", SlicingPipelineStep::Perimeters)
|
||||
.value("EstimateCurledExtrusions", SlicingPipelineStep::EstimateCurledExtrusions)
|
||||
.value("PrepareInfill", SlicingPipelineStep::PrepareInfill) // after prepare_infill, before make_fills: editing fill_surfaces here CASCADES
|
||||
.value("Infill", SlicingPipelineStep::Infill) // after make_fills: editing fill_surfaces here does NOT regenerate fills (v1)
|
||||
.value("Ironing", SlicingPipelineStep::Ironing)
|
||||
.value("Contouring", SlicingPipelineStep::Contouring)
|
||||
.value("SupportMaterial", SlicingPipelineStep::SupportMaterial)
|
||||
.value("DetectOverhangsForLift", SlicingPipelineStep::DetectOverhangsForLift)
|
||||
.value("SimplifyPath", SlicingPipelineStep::SimplifyPath) // covers all simplify sub-steps
|
||||
.value("WipeTower", SlicingPipelineStep::WipeTower)
|
||||
.value("SkirtBrim", SlicingPipelineStep::SkirtBrim)
|
||||
py::enum_<SlicingPipelineStepPlugin>(slicing, "Step")
|
||||
.value("posSlice", SlicingPipelineStepPlugin::posSlice)
|
||||
.value("posPerimeters", SlicingPipelineStepPlugin::posPerimeters)
|
||||
.value("posEstimateCurledExtrusions", SlicingPipelineStepPlugin::posEstimateCurledExtrusions)
|
||||
.value("posPrepareInfill", SlicingPipelineStepPlugin::posPrepareInfill) // after prepare_infill, before make_fills: editing fill_surfaces here CASCADES
|
||||
.value("posInfill", SlicingPipelineStepPlugin::posInfill) // after make_fills: editing fill_surfaces here does NOT regenerate fills (v1)
|
||||
.value("posIroning", SlicingPipelineStepPlugin::posIroning)
|
||||
.value("posContouring", SlicingPipelineStepPlugin::posContouring)
|
||||
.value("posSupportMaterial", SlicingPipelineStepPlugin::posSupportMaterial)
|
||||
.value("posDetectOverhangsForLift", SlicingPipelineStepPlugin::posDetectOverhangsForLift)
|
||||
.value("posSimplifyPath", SlicingPipelineStepPlugin::posSimplifyPath) // covers all simplify sub-steps
|
||||
.value("psWipeTower", SlicingPipelineStepPlugin::psWipeTower)
|
||||
.value("psSkirtBrim", SlicingPipelineStepPlugin::psSkirtBrim)
|
||||
.export_values();
|
||||
|
||||
// The read-graph data model (Surface / ExPolygon / the extrusion tree / LayerRegion /
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "slic3r/plugin/PythonPluginInterface.hpp"
|
||||
#include "libslic3r/Print.hpp" // SlicingPipelineStep, Print, PrintObject
|
||||
#include "libslic3r/Print.hpp" // SlicingPipelineStepPlugin, Print, PrintObject
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -15,7 +15,7 @@ namespace Slic3r {
|
||||
// src/slic3r/plugin/PluginHostSlicing.cpp.
|
||||
struct SlicingPipelineContext {
|
||||
std::string orca_version;
|
||||
SlicingPipelineStep step { SlicingPipelineStep::Slice };
|
||||
SlicingPipelineStepPlugin step { SlicingPipelineStepPlugin::posSlice };
|
||||
Print* print { nullptr }; // always present when dispatched
|
||||
const PrintObject* object { nullptr }; // null for print-wide steps
|
||||
// read-only per-plugin settings, populated by the dispatcher from the
|
||||
|
||||
@@ -19,7 +19,7 @@ TEST_CASE("slicing_pipeline_plugin option exists and defaults empty", "[slicing_
|
||||
TEST_CASE("slicing pipeline hook setter is a no-op-safe injection", "[slicing_pipeline]") {
|
||||
int calls = 0;
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStep){ ++calls; });
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStepPlugin){ ++calls; });
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(nullptr); // reset — must be legal
|
||||
CHECK(calls == 0);
|
||||
}
|
||||
@@ -30,10 +30,10 @@ TEST_CASE("slicing pipeline hook setter is a no-op-safe injection", "[slicing_pi
|
||||
using namespace Slic3r::Test;
|
||||
|
||||
TEST_CASE("SlicingPipeline hook fires once per step per object in order", "[slicing_pipeline]") {
|
||||
struct Call { const Slic3r::PrintObject* obj; Slic3r::SlicingPipelineStep step; };
|
||||
struct Call { const Slic3r::PrintObject* obj; Slic3r::SlicingPipelineStepPlugin step; };
|
||||
std::vector<Call> calls;
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStep s){ calls.push_back({o, s}); });
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStepPlugin s){ calls.push_back({o, s}); });
|
||||
|
||||
Slic3r::Print print; Slic3r::Model model;
|
||||
Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
@@ -42,7 +42,7 @@ TEST_CASE("SlicingPipeline hook fires once per step per object in order", "[slic
|
||||
print.process();
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(nullptr);
|
||||
|
||||
using S = Slic3r::SlicingPipelineStep;
|
||||
using S = Slic3r::SlicingPipelineStepPlugin;
|
||||
auto count = [&](S s){ return std::count_if(calls.begin(), calls.end(), [&](const Call& c){ return c.step == s; }); };
|
||||
CHECK(count(S::Slice) == 1);
|
||||
CHECK(count(S::Perimeters) == 1);
|
||||
@@ -97,7 +97,7 @@ TEST_CASE("Inactive hook: process output is byte-identical (no-op hook == unset)
|
||||
if (activate)
|
||||
config.set_key_value("slicing_pipeline_plugin", new Slic3r::ConfigOptionStrings({"probe"}));
|
||||
if (set_noop_hook)
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn([](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStep){});
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn([](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStepPlugin){});
|
||||
else
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(nullptr);
|
||||
init_print({TestMesh::cube_20x20x20}, print, model, config);
|
||||
@@ -120,7 +120,7 @@ TEST_CASE("Inactive hook: process output is byte-identical (no-op hook == unset)
|
||||
TEST_CASE("Empty option: registered hook is gated off and never fires", "[slicing_pipeline]") {
|
||||
int calls = 0;
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStep){ ++calls; });
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStepPlugin){ ++calls; });
|
||||
Slic3r::Print print; Slic3r::Model model;
|
||||
auto config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
// option left EMPTY -> inactive regardless of the registered hook.
|
||||
@@ -138,9 +138,9 @@ TEST_CASE("Empty option: registered hook is gated off and never fires", "[slicin
|
||||
TEST_CASE("Duplicate objects share a slice: Slice hook fires exactly once", "[slicing_pipeline]") {
|
||||
int slice_calls = 0, perim_calls = 0;
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStep s){
|
||||
if (s == Slic3r::SlicingPipelineStep::Slice) ++slice_calls;
|
||||
if (s == Slic3r::SlicingPipelineStep::Perimeters) ++perim_calls;
|
||||
[&](Slic3r::Print&, const Slic3r::PrintObject*, Slic3r::SlicingPipelineStepPlugin s){
|
||||
if (s == Slic3r::SlicingPipelineStepPlugin::posSlice) ++slice_calls;
|
||||
if (s == Slic3r::SlicingPipelineStepPlugin::posPerimeters) ++perim_calls;
|
||||
});
|
||||
|
||||
Slic3r::Print print; Slic3r::Model model;
|
||||
@@ -186,8 +186,8 @@ TEST_CASE("Mutating slices at the Slice boundary cascades downstream", "[slicing
|
||||
auto config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
config.set_key_value("slicing_pipeline_plugin", new Slic3r::ConfigOptionStrings({"probe"}));
|
||||
if (inset) Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStep s){
|
||||
if (s != Slic3r::SlicingPipelineStep::Slice || !o) return;
|
||||
[](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStepPlugin s){
|
||||
if (s != Slic3r::SlicingPipelineStepPlugin::posSlice || !o) return;
|
||||
for (Slic3r::Layer* l : const_cast<Slic3r::PrintObject*>(o)->layers())
|
||||
for (Slic3r::LayerRegion* r : l->regions()) {
|
||||
Slic3r::Surfaces in = r->slices.surfaces;
|
||||
@@ -219,7 +219,7 @@ TEST_CASE("Changing slicing_pipeline_plugin invalidates posSlice", "[slicing_pip
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
|
||||
// §3.6 (Twistify design): Twistify's effect is a similarity transform (rotate + uniform
|
||||
// scale) applied to slices at Step.Slice. This C++ analogue rotates every region's slices a
|
||||
// scale) applied to slices at Step.posSlice. This C++ analogue rotates every region's slices a
|
||||
// fixed 45 deg about the object's base-footprint center -- the same seam and cascade that
|
||||
// Twistify.py drives through the slices.set() + Layer::make_slices() path. Two end-to-end invariants after
|
||||
// process() confirm the approach:
|
||||
@@ -235,8 +235,8 @@ TEST_CASE("Rotating slices at the Slice boundary cascades (area preserved, bbox
|
||||
auto config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
config.set_key_value("slicing_pipeline_plugin", new Slic3r::ConfigOptionStrings({"probe"}));
|
||||
if (rotate) Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStep s){
|
||||
if (s != Slic3r::SlicingPipelineStep::Slice || !o) return;
|
||||
[](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStepPlugin s){
|
||||
if (s != Slic3r::SlicingPipelineStepPlugin::posSlice || !o) return;
|
||||
auto* obj = const_cast<Slic3r::PrintObject*>(o);
|
||||
// Twist axis = center of the first sliced layer's footprint (Twistify's anchor).
|
||||
coord_t nx=0, xx=0, ny=0, xy=0; bool seeded=false;
|
||||
@@ -310,8 +310,8 @@ TEST_CASE("Identity round-trip through set_slices is byte-identical", "[slicing_
|
||||
auto config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
config.set_key_value("slicing_pipeline_plugin", new Slic3r::ConfigOptionStrings({"probe"})); // active in both runs
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[roundtrip](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStep s){
|
||||
if (!roundtrip || s != Slic3r::SlicingPipelineStep::Slice || !o) return;
|
||||
[roundtrip](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStepPlugin s){
|
||||
if (!roundtrip || s != Slic3r::SlicingPipelineStepPlugin::posSlice || !o) return;
|
||||
for (Slic3r::Layer* l : const_cast<Slic3r::PrintObject*>(o)->layers())
|
||||
for (Slic3r::LayerRegion* r : l->regions()) {
|
||||
Slic3r::Surfaces in = r->slices.surfaces; // copy current (already-normalized) geometry
|
||||
@@ -359,8 +359,8 @@ static double outer_slices_width(const Slic3r::Print& print) {
|
||||
TEST_CASE("raw_slices captures post-hook geometry so a perimeter re-run keeps the mutation", "[slicing_pipeline]") {
|
||||
using Catch::Matchers::WithinRel;
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStep s){
|
||||
if (s != Slic3r::SlicingPipelineStep::Slice || !o) return;
|
||||
[](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStepPlugin s){
|
||||
if (s != Slic3r::SlicingPipelineStepPlugin::posSlice || !o) return;
|
||||
for (Slic3r::Layer* l : const_cast<Slic3r::PrintObject*>(o)->layers())
|
||||
for (Slic3r::LayerRegion* r : l->regions()) {
|
||||
Slic3r::Surfaces in = r->slices.surfaces;
|
||||
@@ -391,12 +391,12 @@ TEST_CASE("raw_slices captures post-hook geometry so a perimeter re-run keeps th
|
||||
// them, whereas the pre-existing Infill seam fires after the fills are already built (v1 limit).
|
||||
// All three runs register a hook (active path) so the comparison isolates only the mutation.
|
||||
TEST_CASE("fill_surfaces mutation cascades at PrepareInfill but not at Infill", "[slicing_pipeline]") {
|
||||
auto fill_paths = [](bool shrink, Slic3r::SlicingPipelineStep at) {
|
||||
auto fill_paths = [](bool shrink, Slic3r::SlicingPipelineStepPlugin at) {
|
||||
Slic3r::Print print; Slic3r::Model model;
|
||||
auto config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
config.set_key_value("slicing_pipeline_plugin", new Slic3r::ConfigOptionStrings({"probe"}));
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[shrink, at](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStep s){
|
||||
[shrink, at](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStepPlugin s){
|
||||
if (!shrink || s != at || !o) return;
|
||||
for (Slic3r::Layer* l : const_cast<Slic3r::PrintObject*>(o)->layers())
|
||||
for (Slic3r::LayerRegion* r : l->regions()) {
|
||||
@@ -417,7 +417,7 @@ TEST_CASE("fill_surfaces mutation cascades at PrepareInfill but not at Infill",
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(nullptr);
|
||||
return n;
|
||||
};
|
||||
using S = Slic3r::SlicingPipelineStep;
|
||||
using S = Slic3r::SlicingPipelineStepPlugin;
|
||||
const size_t base = fill_paths(false, S::PrepareInfill); // active hook, no mutation
|
||||
CHECK(base > 0);
|
||||
CHECK(fill_paths(true, S::PrepareInfill) < base); // mutation before make_fills cascades
|
||||
@@ -434,8 +434,8 @@ TEST_CASE("refreshing lslices after a slice mutation makes islands track the geo
|
||||
auto config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
config.set_key_value("slicing_pipeline_plugin", new Slic3r::ConfigOptionStrings({"probe"}));
|
||||
Slic3r::Print::set_slicing_pipeline_hook_fn(
|
||||
[refresh](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStep s){
|
||||
if (s != Slic3r::SlicingPipelineStep::Slice || !o) return;
|
||||
[refresh](Slic3r::Print&, const Slic3r::PrintObject* o, Slic3r::SlicingPipelineStepPlugin s){
|
||||
if (s != Slic3r::SlicingPipelineStepPlugin::posSlice || !o) return;
|
||||
for (Slic3r::Layer* l : const_cast<Slic3r::PrintObject*>(o)->layers()) {
|
||||
for (Slic3r::LayerRegion* r : l->regions()) {
|
||||
Slic3r::Surfaces in = r->slices.surfaces;
|
||||
|
||||
Reference in New Issue
Block a user