mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-07 15:51:08 +00:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d02a945e0 | ||
|
|
01afd3b5b9 | ||
|
|
b805f2ffd6 | ||
|
|
6b2b200f50 | ||
|
|
a38e6c61f2 | ||
|
|
cc3769453f | ||
|
|
bd0ef35b90 | ||
|
|
b0da039eae | ||
|
|
ba5ecc5470 | ||
|
|
82349e1ba4 | ||
|
|
c740ddf0a6 | ||
|
|
d068468bbb | ||
|
|
67e29f69e7 | ||
|
|
919f507cca | ||
|
|
26329e7147 | ||
|
|
e47fdcaef7 | ||
|
|
26be825234 |
@@ -105,11 +105,12 @@ Rules:
|
||||
`single_extruder_multi_material` off, and in the app when the printer tab loads a printer with a
|
||||
different number of extruders, the pair is rebuilt from `extruder_variant_list` (one
|
||||
`Direct Drive Standard` per extruder when the list is absent) and the variant arrays are resized to
|
||||
the rebuilt pair, padded with their first value or cut. The resize skips the `machine_max_*` limits
|
||||
and `hotend_heating_rate` / `hotend_cooling_rate`: they keep their width, and an extruder beyond it
|
||||
reads their first value, so extruder 2 and up of a list-less printer take extruder 1's normal limit
|
||||
as their silent one too. With the three in agreement that changes nothing; a pair written without
|
||||
the list is replaced. A listed variant the pair lacks is a menu choice that reads variant index 0.
|
||||
the rebuilt pair, padded with their first value or cut. The `machine_max_*` limits are padded the
|
||||
same way, so extruder 2 and up of a list-less printer take extruder 1's normal limit as their
|
||||
silent one too. The resize skips `hotend_heating_rate` / `hotend_cooling_rate`: they keep their
|
||||
width, and an extruder beyond it reads their first value. With the three in agreement that changes
|
||||
nothing; a pair written without the list is replaced. A listed variant the pair lacks is a menu
|
||||
choice that reads variant index 0.
|
||||
- The pair without `extruder_variant_list` slices, but the sidebar offers no variant switch and
|
||||
the app cannot add variants to a list-less process: nothing is lost while every extruder
|
||||
has exactly one variant, and every further variant is unreachable.
|
||||
|
||||
@@ -311,7 +311,7 @@ function CreatePrinterBlock(OneModel)
|
||||
|
||||
return '<div class="PrinterBlock" onClick="ChooseModel(\''+vendor+'\',\''+OneModel['model']+'\')">'+
|
||||
' <div class="PImg">'+
|
||||
' <img class="ModelThumbnail" src="' + OneModel['cover'] + '" />'+
|
||||
' <img class="ModelThumbnail" src="' + OneModel['cover'] + '" onerror="this.onerror=null;this.src=\'../img/printer-dummy.png\';"/>'+
|
||||
' </div>'+
|
||||
' <div class="PrinterInfoMark">?</div>'+
|
||||
' <div class="PrinterInfo">'+
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -23,7 +23,13 @@ appimage_is_host_library() {
|
||||
}
|
||||
|
||||
appimage_is_elf_file() {
|
||||
file -b "$1" 2>/dev/null | grep -q '^ELF '
|
||||
# Read the four-byte ELF magic rather than asking file(1): this runs once per candidate, and an
|
||||
# AppDir holds thousands of them (the bundled Python runtime alone is ~5k files, none of them
|
||||
# ELF). Two processes per call made this ~14 s of a ~95 s image build on its own.
|
||||
local magic
|
||||
[[ -f "$1" && -r "$1" ]] || return 1
|
||||
IFS= read -r -n 4 -d '' magic < "$1" 2>/dev/null
|
||||
[[ $magic == $'\177ELF' ]]
|
||||
}
|
||||
|
||||
appimage_list_direct_dependencies() {
|
||||
|
||||
@@ -118,9 +118,13 @@ bundle_dependency_closure() {
|
||||
# (scripts/check_appimage_libs.sh).
|
||||
local -a search_dirs=("$dst_dir")
|
||||
|
||||
while [ ${#queue[@]} -gt 0 ]; do
|
||||
target="${queue[0]}"
|
||||
queue=("${queue[@]:1}")
|
||||
# Walked with a read index rather than by reslicing the array: "${queue[@]:1}" rebuilds the whole
|
||||
# queue on every pop, so draining it costs O(n^2). At the ~5k entries this bundle reaches that was
|
||||
# ~22 s of the image build spent copying an array around.
|
||||
local head=0
|
||||
while [ "$head" -lt ${#queue[@]} ]; do
|
||||
target="${queue[$head]}"
|
||||
head=$((head + 1))
|
||||
|
||||
if [ ! -e "$target" ] || ! appimage_is_elf_file "$target"; then
|
||||
continue
|
||||
|
||||
@@ -148,6 +148,8 @@ struct ConflictComputeResult
|
||||
|
||||
using ConflictComputeOpt = std::optional<ConflictComputeResult>;
|
||||
|
||||
using ConflictObjName = std::optional<std::pair<std::string, std::string>>;
|
||||
|
||||
struct ConflictChecker
|
||||
{
|
||||
static ConflictResultOpt find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, std::optional<const FakeWipeTower *> wtdptr);
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
namespace Slic3r {
|
||||
namespace PreciseSeam {
|
||||
|
||||
// Import EnforcedBlockedSeamPoint from SeamPlacerImpl namespace for convenience
|
||||
using SeamPlacerImpl::EnforcedBlockedSeamPoint;
|
||||
|
||||
// Geometry and its exterior bounds are prepared together, then treated as read-only.
|
||||
struct ModifierRegion {
|
||||
ExPolygon polygon;
|
||||
@@ -134,7 +137,7 @@ SegmentExtraction extract_perimeter_segments(const PreparedPerimeter &prepared,
|
||||
|
||||
// Result of weak modifier segment processing
|
||||
struct WeakModifierSegment {
|
||||
SeamPlacerImpl::EnforcedBlockedSeamPoint type; // Enforced/Blocked/Neutral
|
||||
EnforcedBlockedSeamPoint type; // Enforced/Blocked/Neutral
|
||||
Point left_point; // Coordinates of left (first) point of segment
|
||||
PerimeterPosition left_position; // Position on the source perimeter before insertion/refinement.
|
||||
Point right_point; // Coordinates of right (last) point of segment
|
||||
|
||||
@@ -40,7 +40,8 @@ std::string get_error_string(const ThumbnailErrors& errors);
|
||||
|
||||
|
||||
typedef std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> GCodeThumbnailDefinitionsList;
|
||||
std::pair<GCodeThumbnailDefinitionsList, ThumbnailErrors> make_and_check_thumbnail_list(const std::string& thumbnails_string, const std::string_view def_ext = "PNG");
|
||||
using namespace std::literals;
|
||||
std::pair<GCodeThumbnailDefinitionsList, ThumbnailErrors> make_and_check_thumbnail_list(const std::string& thumbnails_string, const std::string_view def_ext = "PNG"sv);
|
||||
std::pair<GCodeThumbnailDefinitionsList, ThumbnailErrors> make_and_check_thumbnail_list(const ConfigBase &config);
|
||||
|
||||
|
||||
|
||||
@@ -94,6 +94,8 @@ struct Circle {
|
||||
|
||||
using Circlef = Circle<Vec2f>;
|
||||
using Circled = Circle<Vec2d>;
|
||||
using CircleSqf = CircleSq<Vec2f>;
|
||||
using CircleSqd = CircleSq<Vec2d>;
|
||||
|
||||
/// Find the center of the circle corresponding to the vector of Points as an arc.
|
||||
Point circle_center_taubin_newton(const Points::const_iterator& input_start, const Points::const_iterator& input_end, size_t cycles = 20);
|
||||
|
||||
@@ -154,12 +154,13 @@ template<class ExecutionPolicy, class Enable = void> struct _Loop
|
||||
};
|
||||
|
||||
// Add Specialization for using ExecutionTBB for parallel loops.
|
||||
template<> struct _Loop<Slic3r::ExecutionTBB>
|
||||
using namespace Slic3r;
|
||||
template<> struct _Loop<ExecutionTBB>
|
||||
{
|
||||
template<class It, class Fn> static void for_each_idx(It from, It to, Fn&& fn)
|
||||
{
|
||||
Slic3r::execution::for_each(
|
||||
Slic3r::ex_tbb, size_t(0), size_t(to - from), [&from, &fn](size_t i) { fn(from[i], i); }, Slic3r::execution::max_concurrency(Slic3r::ex_tbb));
|
||||
execution::for_each(
|
||||
ex_tbb, size_t(0), size_t(to - from), [&from, &fn](size_t i) { fn(from[i], i); }, execution::max_concurrency(ex_tbb));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10030,6 +10030,13 @@ static void extend_extruder_variant(DynamicPrintConfig& config, const unsigned i
|
||||
printer_extruder_variant_opt->values.insert(printer_extruder_variant_opt->values.end(), variants_list.begin(), variants_list.end());
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Size the machine limits to the rebuilt variants, padded with their first value like the other variant keys.
|
||||
// They are not extruder option keys, so the resize loop in set_num_extruders skips them.
|
||||
const auto &defaults = FullPrintConfig::defaults();
|
||||
for (const std::string &key : printer_options_with_variant_2)
|
||||
if (auto *opt = config.option<ConfigOptionFloats>(key))
|
||||
opt->resize(config.get_parameter_size(key, num_extruders), defaults.option(key));
|
||||
}
|
||||
|
||||
void DynamicPrintConfig::set_num_extruders(unsigned int num_extruders)
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
using TColor = typename PixelRenderer::color_type;
|
||||
using TValue = typename TColor::value_type;
|
||||
using TPixel = typename PixelRenderer::pixel_type;
|
||||
using TRawBuffer = agg::rendering_buffer;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ typedef std::vector<Color> ColorList;
|
||||
typedef std::array<double, 3> ColorDouble;
|
||||
typedef std::array<std::size_t, 3> RGB;
|
||||
|
||||
// Function pointer type that points to a specific color-difference function based on the chosen method.
|
||||
using DistanceFunction = double (*)(const Color&, const Color&);
|
||||
|
||||
// Color space used for computing color differences.
|
||||
enum struct ColorDifferenceMethod : std::size_t {
|
||||
RGB = 0, // Simplest and fastest
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
namespace Slic3r { namespace tex2color {
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
// Default upper bound on the number of half-edges in any single boundary cycle
|
||||
// that CloseBoundariesAndRepairManifoldness will attempt to triangulate. The
|
||||
// cost of triangulate_hole grows non-linearly with cycle length, so this caps
|
||||
@@ -58,7 +60,6 @@ struct BoundaryEdgeStats
|
||||
// any pre-processing (e.g. stitch_borders) needed for the count to be meaningful.
|
||||
inline BoundaryEdgeStats ComputeBoundaryEdgeStats(const cgalutils::CGALMesh& cgal_mesh)
|
||||
{
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
using CGALMesh = cgalutils::CGALMesh;
|
||||
using HalfedgeDescriptor = boost::graph_traits<CGALMesh>::halfedge_descriptor;
|
||||
|
||||
@@ -85,7 +86,6 @@ inline BoundaryEdgeStats ComputeBoundaryEdgeStats(const cgalutils::CGALMesh& cga
|
||||
// boundary statistics; entering this function always triggers triangulation.
|
||||
inline void CloseBoundariesAndRepairManifoldness(cgalutils::CGALMesh& cgal_mesh)
|
||||
{
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
using CGALMesh = cgalutils::CGALMesh;
|
||||
using HalfedgeDescriptor = boost::graph_traits<CGALMesh>::halfedge_descriptor;
|
||||
using FaceDescriptor = boost::graph_traits<CGALMesh>::face_descriptor;
|
||||
@@ -111,7 +111,6 @@ inline bool RepairMesh(const TriMesh& mesh,
|
||||
AlgoCancelCallback cancel_callback = nullptr,
|
||||
const RepairSetting& setting = RepairSetting{})
|
||||
{
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
using Clock = std::chrono::steady_clock;
|
||||
auto elapsed_ms = [](Clock::time_point t0) {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - t0).count();
|
||||
|
||||
@@ -432,6 +432,8 @@ inline IntegerOnly<I, I> fast_round_up(double a)
|
||||
return a == 0.49999999999999994 ? I(0) : I(floor(a + 0.5));
|
||||
}
|
||||
|
||||
template<class T> using SamePair = std::pair<T, T>;
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
||||
|
||||
@@ -198,3 +198,6 @@ template<> struct std::hash<NozzleDef>
|
||||
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
|
||||
};
|
||||
};
|
||||
|
||||
// key(extruder_id) -> { key1(nozzle type info), val1( number of the nozzle type)}
|
||||
using ExtruderNozzleInfos = std::unordered_map<int, std::unordered_map<NozzleDef, int>>;
|
||||
@@ -183,10 +183,13 @@ wxDECLARE_EVENT(EVT_GLCANVAS_PLATE_NAME_CHANGE, SimpleEvent);
|
||||
//BBS: declare EVT_GLCANVAS_PLATE_SELECT
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_PLATE_SELECT, SimpleEvent);
|
||||
|
||||
using Vec2dEvent = Event<Vec2d>;
|
||||
// _bool_ value is used as a indicator of selection in the 3DScene
|
||||
using RBtnEvent = Event<std::pair<Vec2d, bool>>;
|
||||
using RBtnPlateEvent = Event<std::pair<Vec2d, int>>;
|
||||
template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;
|
||||
|
||||
using Vec3dEvent = Event<Vec3d>;
|
||||
template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
|
||||
|
||||
using HeightProfileSmoothEvent = Event<HeightProfileSmoothingParams>;
|
||||
|
||||
@@ -54,6 +54,7 @@ struct Option {
|
||||
Option(const ConfigOptionDef& _opt, t_config_option_key id) :
|
||||
opt(_opt), opt_id(id) {}
|
||||
};
|
||||
using t_option = std::unique_ptr<Option>; //!
|
||||
|
||||
/// Represents option lines
|
||||
class Line : public UndoValueUIManager
|
||||
|
||||
@@ -108,6 +108,7 @@ class PlaterPresetComboBox;
|
||||
class PartPlateList;
|
||||
class SyncNozzleAndAmsDialog;
|
||||
class FinishSyncAmsDialog;
|
||||
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
|
||||
|
||||
class Plater;
|
||||
enum class ActionButtonType : int;
|
||||
@@ -324,6 +325,7 @@ private:
|
||||
class Plater: public wxPanel
|
||||
{
|
||||
public:
|
||||
using fs_path = boost::filesystem::path;
|
||||
|
||||
Plater(wxWindow *parent, MainFrame *main_frame);
|
||||
Plater(Plater &&) = delete;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Widgets/DialogButtons.hpp"
|
||||
#include "Widgets/StaticLine.hpp"
|
||||
#include "Widgets/StateColor.hpp"
|
||||
#include "Widgets/SwitchButton.hpp"
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
@@ -864,34 +865,25 @@ void PublishSettingsDialog::build_option_model()
|
||||
};
|
||||
|
||||
// --- Phase 1: printer per-extruder retraction settings (first, mirroring the sidebar's
|
||||
// Printer group), from the printer tab's "Extruder"/"Extruder N" pages. One inner tab per
|
||||
// extruder (e.g. "Left Extruder"/"Right Extruder" via Tab::translate_category), each holding
|
||||
// that extruder's Retraction and Z-Hop rows with per-extruder "#N" values.
|
||||
// Printer group), from the printer tab's "Extruder" page. One inner tab per extruder (named
|
||||
// as on the printer tab's switch, e.g. "Left Extruder"/"Right Extruder" via
|
||||
// Tab::translate_category), each holding that extruder's Retraction and Z-Hop rows with
|
||||
// per-extruder "#N" values.
|
||||
{
|
||||
size_t g = section_group_for(Section::Printer);
|
||||
std::set<std::string> printer_added;
|
||||
for (Tab* tab : wxGetApp().tabs_list) {
|
||||
if (tab->m_type != Preset::TYPE_PRINTER)
|
||||
// The page's controls edit the extruder chosen on the printer tab's switch, so its
|
||||
// option list is read once per extruder.
|
||||
auto* printer_tab = dynamic_cast<TabPrinter*>(tab);
|
||||
const Page* page = printer_tab ? printer_tab->extruder_page() : nullptr;
|
||||
if (page == nullptr)
|
||||
continue;
|
||||
for (const PageShp& page : tab->m_pages) {
|
||||
if (!page->title().StartsWith("Extruder"))
|
||||
continue;
|
||||
// The extruder index of this page: its options are appended with the same
|
||||
// "#N" opt_index (opt.second.second), so derive the tab's index from the first
|
||||
// allowlisted option; skip the page when none is found (defensive).
|
||||
int extruder_idx = -1;
|
||||
for (const ConfigOptionsGroupShp& optgroup : page->m_optgroups) {
|
||||
if (optgroup->title != "Retraction" && optgroup->title != "Z-Hop")
|
||||
continue;
|
||||
for (const auto& opt : optgroup->opt_map())
|
||||
if (extruder_idx < 0)
|
||||
extruder_idx = opt.second.second;
|
||||
if (extruder_idx >= 0)
|
||||
break;
|
||||
}
|
||||
if (extruder_idx < 0)
|
||||
continue;
|
||||
const wxString page_title = Tab::translate_category(page->title(), tab->m_type);
|
||||
const size_t extruders_count = printer_tab->m_extruders_count;
|
||||
for (size_t extruder_idx = 0; extruder_idx < extruders_count; ++extruder_idx) {
|
||||
const wxString page_title = Tab::translate_category(extruders_count > 1 ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString("Extruder"), tab->m_type);
|
||||
// Retraction and Z-Hop values are stored per variant column, not per extruder.
|
||||
const int variant_index = printer_tab->extruder_variant_index(int(extruder_idx));
|
||||
for (const ConfigOptionsGroupShp& optgroup : page->m_optgroups) {
|
||||
// Allowlist on the untranslated optgroup title; the "Retraction when
|
||||
// switching material" group is intentionally skipped.
|
||||
@@ -899,17 +891,17 @@ void PublishSettingsDialog::build_option_model()
|
||||
continue;
|
||||
const wxString subcategory = _(optgroup->title);
|
||||
for (const auto& opt : optgroup->opt_map()) {
|
||||
const std::string& opt_id = opt.first;
|
||||
const std::string& pure_key = opt.second.first;
|
||||
// Rows are keyed by the full per-extruder "#N" opt_id so each extruder
|
||||
// tab publishes its own value; GetPublishedKeys() emits the checked rows
|
||||
// as-is.
|
||||
const std::string opt_id = pure_key + "#" + std::to_string(variant_index);
|
||||
if (!printer_added.insert(opt_id).second)
|
||||
continue;
|
||||
wxString label, value, unit;
|
||||
if (!option_text(opt_id, pure_key, label, value, unit))
|
||||
continue;
|
||||
size_t cat_index = category_index_for(page_title, Section::Printer, g, size_t(extruder_idx));
|
||||
size_t cat_index = category_index_for(page_title, Section::Printer, g, extruder_idx);
|
||||
size_t sub_index = subcategory_index_for(cat_index, subcategory, optgroup->icon);
|
||||
add_row_ui(opt_id, label, value, unit, cat_index, sub_index);
|
||||
}
|
||||
@@ -1098,6 +1090,10 @@ void PublishSettingsDialog::build_option_model()
|
||||
for (SectionGroup& section : m_sections)
|
||||
if (!section.categories.empty())
|
||||
section.tabs->SelectItem(0);
|
||||
// Orca: the Printer section shows its extruders on the same switch as the printer tab's Extruder page.
|
||||
for (size_t s = 0; s < m_sections.size(); ++s)
|
||||
if (m_sections[s].kind == Section::Printer && m_sections[s].categories.size() > 1)
|
||||
setup_variant_switch(s);
|
||||
if (!m_sections.empty()) {
|
||||
m_outer_tabs->SelectItem(0);
|
||||
show_outer_page(0);
|
||||
@@ -1630,6 +1626,8 @@ void PublishSettingsDialog::show_inner_page(size_t section_index, int inner_inde
|
||||
section.selected_mixed = -1;
|
||||
}
|
||||
section.selected_inner = inner_index;
|
||||
if (section.variant_switch != nullptr)
|
||||
section.variant_switch->SetSelection(inner_index); // fires its event, which ignores the shown page
|
||||
Category& category = m_categories[section.categories[inner_index]];
|
||||
category.page->Show();
|
||||
category.scroll->FitInside();
|
||||
@@ -1639,6 +1637,32 @@ void PublishSettingsDialog::show_inner_page(size_t section_index, int inner_inde
|
||||
section.page_host_sizer->Layout();
|
||||
}
|
||||
|
||||
void PublishSettingsDialog::setup_variant_switch(size_t section_index)
|
||||
{
|
||||
SectionGroup& section = m_sections[section_index];
|
||||
std::vector<wxString> titles;
|
||||
for (size_t category : section.categories)
|
||||
titles.push_back(m_categories[category].title);
|
||||
|
||||
section.variant_switch = new MultiSwitchButton(section.page);
|
||||
section.variant_switch->SetFitToOptions();
|
||||
section.variant_switch->SetOptions(titles);
|
||||
section.variant_switch->SetSelection(section.selected_inner);
|
||||
section.variant_switch->Bind(wxCUSTOMEVT_MULTISWITCH_SELECTION, [this, section_index](wxCommandEvent& evt) {
|
||||
evt.Skip();
|
||||
// The hidden tab strip stays the selection model; its event shows the page.
|
||||
SectionGroup& sec = m_sections[section_index];
|
||||
if (evt.GetInt() != sec.selected_inner)
|
||||
sec.tabs->SelectItem(evt.GetInt());
|
||||
});
|
||||
|
||||
// The switch takes the place of the tab strip, centered like on the printer tab.
|
||||
wxSizer* page_sizer = section.page->GetSizer();
|
||||
page_sizer->Insert(1, section.variant_switch, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(4));
|
||||
section.tabs->Hide();
|
||||
section.page->Layout();
|
||||
}
|
||||
|
||||
void PublishSettingsDialog::show_mixed_page(size_t section_index, int mixed_index)
|
||||
{
|
||||
if (section_index >= m_sections.size())
|
||||
@@ -2184,6 +2208,13 @@ void PublishSettingsDialog::refresh_tab_indicators()
|
||||
for (size_t i = 0; i < section.categories.size(); ++i) {
|
||||
const bool on = category_has_selection(m_categories[section.categories[i]]);
|
||||
section.tabs->SetItemIndicator(static_cast<unsigned int>(i), on);
|
||||
// The switch has no indicator dot; mark its option text instead.
|
||||
if (section.variant_switch != nullptr) {
|
||||
const wxString& title = m_categories[section.categories[i]].title;
|
||||
const wxString text = on ? title + wxString(" ") + wxString(wxUniChar(0x2022)) : title;
|
||||
if (section.variant_switch->GetOptionText(static_cast<unsigned int>(i)) != text)
|
||||
section.variant_switch->SetOptionText(static_cast<unsigned int>(i), text);
|
||||
}
|
||||
any = any || on;
|
||||
}
|
||||
if (section.mixed_tabs != nullptr)
|
||||
@@ -2248,6 +2279,8 @@ void PublishSettingsDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
section.tabs->Rescale();
|
||||
if (section.mixed_tabs != nullptr)
|
||||
section.mixed_tabs->Rescale();
|
||||
if (section.variant_switch != nullptr)
|
||||
section.variant_switch->Rescale();
|
||||
}
|
||||
|
||||
// Refresh the per-row Color chips at the new DPI (they carry the slot number too).
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace Slic3r { class DynamicPrintConfig; }
|
||||
class TextInput;
|
||||
class StaticLine;
|
||||
class CheckBox;
|
||||
class MultiSwitchButton;
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@@ -195,6 +196,10 @@ private:
|
||||
ScalableBitmap icon_bmp; // tab icon next to the title; rescaled on DPI change
|
||||
wxPanel* page{nullptr};
|
||||
TabCtrl* tabs{nullptr};
|
||||
// Printer section with several extruders: the extruder switch shown instead of `tabs`, the
|
||||
// same MultiSwitchButton (and option names) as the printer tab's Extruder page. One option
|
||||
// per entry of `categories`, named by its title; `tabs` stays as the hidden selection model.
|
||||
MultiSwitchButton* variant_switch{nullptr};
|
||||
// Second tab strip, below the main one, listing only the mixed-color filament slots.
|
||||
// Present on the Material section only (null elsewhere).
|
||||
TabCtrl* mixed_tabs{nullptr};
|
||||
@@ -277,6 +282,8 @@ private:
|
||||
bool row_is_visible(const Row& row) const;
|
||||
void apply_visibility();
|
||||
void bind_tab_events();
|
||||
// Replaces a section's inner tab strip with a variant switch (see SectionGroup::variant_switch).
|
||||
void setup_variant_switch(size_t section_index);
|
||||
|
||||
TabCtrl* m_outer_tabs{nullptr};
|
||||
wxPanel* m_outer_host{nullptr};
|
||||
|
||||
+241
-104
@@ -811,6 +811,12 @@ wxString Tab::translate_category(const wxString& title, Preset::Type preset_type
|
||||
}
|
||||
return _("Extruder") + title.SubString(8, title.Last());
|
||||
}
|
||||
// Orca: one "Extruder" page serves all extruders; name it "Extruders" when there are several.
|
||||
if (preset_type == Preset::TYPE_PRINTER && title == "Extruder") {
|
||||
auto preset = wxGetApp().preset_bundle;
|
||||
if (preset && preset->get_printer_extruder_count() > 1)
|
||||
return _("Extruders");
|
||||
}
|
||||
return _(title);
|
||||
}
|
||||
|
||||
@@ -1153,6 +1159,38 @@ std::string Tab::options_list_storage_key(const std::string& opt_key) const
|
||||
return (serialized || is_plugin_field) ? opt_key : opt_key + "#0";
|
||||
}
|
||||
|
||||
// Orca: deep_diff() flags every vector entry at or past the reference vector's length as changed,
|
||||
// whatever its value (e.g. the values of an extruder added by raising the extruder count). A vector
|
||||
// grows by copying its first entry (ConfigOptionVector::resize), so such an entry only counts as
|
||||
// changed when it differs from the reference's first entry, as before Orca's deep_diff() change.
|
||||
// The change of the count itself shows on "extruders_count".
|
||||
static void drop_unchanged_added_entries(std::vector<std::string> &options, const DynamicPrintConfig ¤t, const Preset *reference)
|
||||
{
|
||||
if (reference == nullptr)
|
||||
return;
|
||||
// deep_diff() lists a key's entries one after another, so serialize each key's vectors once.
|
||||
std::string serialized_key;
|
||||
std::vector<std::string> cur_values;
|
||||
std::string ref_first;
|
||||
options.erase(std::remove_if(options.begin(), options.end(), [&](const std::string &opt) {
|
||||
const auto pos = opt.find('#');
|
||||
if (pos == std::string::npos)
|
||||
return false;
|
||||
const std::string key = opt.substr(0, pos);
|
||||
const size_t idx = size_t(std::atoi(opt.c_str() + pos + 1));
|
||||
auto ref = dynamic_cast<const ConfigOptionVectorBase *>(reference->config.option(key));
|
||||
auto cur = dynamic_cast<const ConfigOptionVectorBase *>(current.option(key));
|
||||
if (ref == nullptr || cur == nullptr || idx < ref->size() || ref->size() == 0 || idx >= cur->size())
|
||||
return false;
|
||||
if (key != serialized_key) {
|
||||
serialized_key = key;
|
||||
cur_values = cur->vserialize();
|
||||
ref_first = ref->vserialize().front();
|
||||
}
|
||||
return cur_values[idx] == ref_first;
|
||||
}), options.end());
|
||||
}
|
||||
|
||||
void Tab::update_all_extruder_options_status()
|
||||
{
|
||||
if (!m_extruder_switch && !m_variant_combo) {
|
||||
@@ -1183,6 +1221,8 @@ void Tab::update_all_extruder_options_status()
|
||||
|
||||
auto dirty_options = m_presets->current_dirty_options(true);
|
||||
auto nonsys_options = m_presets->current_different_from_parent_options(true);
|
||||
if (m_type == Preset::TYPE_PRINTER)
|
||||
update_custom_dirty(dirty_options, nonsys_options);
|
||||
auto filter_extruder_options = [](const std::vector<std::string>& options) {
|
||||
std::vector<std::string> filtered_options;
|
||||
for (const auto& opt : options) {
|
||||
@@ -1231,7 +1271,7 @@ void Tab::update_extruder_switch_colors()
|
||||
|
||||
if (m_active_page) {
|
||||
if (m_active_page->title() == "Speed" || m_active_page->title() == "Motion ability" || m_active_page->title() == "Filament" ||
|
||||
m_active_page->title() == "Setting Overrides" || m_active_page->title() == "Multimaterial") {
|
||||
m_active_page->title() == "Setting Overrides" || m_active_page->title() == "Multimaterial" || is_printer_extruder_page(m_active_page)) {
|
||||
for (auto page_ptr : m_pages) {
|
||||
if (page_ptr.get() == m_active_page) {
|
||||
pages_to_check.push_back(page_ptr);
|
||||
@@ -1262,8 +1302,8 @@ void Tab::update_extruder_switch_colors()
|
||||
void Tab::check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector<PageShp>& pages_to_check)
|
||||
{
|
||||
int config_index = index;
|
||||
int extruder_id = index;
|
||||
if (m_type == Preset::TYPE_PRINT || m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_MODEL) {
|
||||
int extruder_id;
|
||||
NozzleVolumeType nozzle_type;
|
||||
parse_extruder_selection(index, extruder_id, nozzle_type);
|
||||
|
||||
@@ -1296,6 +1336,10 @@ void Tab::check_extruder_options_status(int index, bool &sys_extruder, bool &mod
|
||||
}
|
||||
|
||||
std::string target_opt_key = base_opt_key + "#" + std::to_string(config_index * stride);
|
||||
// Orca: on the printer's Extruder page only per-variant options use the variant column,
|
||||
// the others (nozzle_diameter, extruder_offset, ...) are indexed by the extruder.
|
||||
if (is_printer_extruder_page(page.get()) && printer_options_with_variant_1.count(base_opt_key) == 0)
|
||||
target_opt_key = base_opt_key + "#" + std::to_string(extruder_id);
|
||||
|
||||
auto status_iter = m_all_extruder_options_status.find(target_opt_key);
|
||||
if (status_iter != m_all_extruder_options_status.end()) {
|
||||
@@ -1336,18 +1380,6 @@ void TabPrinter::init_options_list()
|
||||
Tab::init_options_list();
|
||||
if (m_printer_technology == ptFFF)
|
||||
m_options_list.emplace("extruders_count", m_opt_status_value);
|
||||
for (size_t i = 1; i < m_extruders_count; ++i) {
|
||||
wxString target_title = wxString::Format("Extruder %d", int(i + 1));
|
||||
for (auto &page : m_pages) {
|
||||
if (page->title() == target_title) {
|
||||
for (auto group : page->m_optgroups) {
|
||||
for (auto &opt : group->opt_map())
|
||||
m_options_list.emplace(opt.first, m_opt_status_value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabPrinter::msw_rescale()
|
||||
@@ -1437,7 +1469,7 @@ void Tab::update_changed_tree_ui()
|
||||
get_sys_and_mod_flags("compatible_printers", sys_page, modified_page);
|
||||
}
|
||||
}
|
||||
if (page->title() == "Speed" || page->title() == "Motion ability" || page->title() == "Filament" || page->title() == "Setting Overrides" || page->title() == "Multimaterial") {
|
||||
if (page->title() == "Speed" || page->title() == "Motion ability" || page->title() == "Filament" || page->title() == "Setting Overrides" || page->title() == "Multimaterial" || is_printer_extruder_page(page.get())) {
|
||||
auto options = generate_extruder_options();
|
||||
for (size_t switch_index = 0; switch_index < options.size(); ++switch_index) {
|
||||
std::vector<PageShp> pages_to_check = { page };
|
||||
@@ -1540,6 +1572,10 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/)
|
||||
|
||||
m_postpone_update_ui = false;
|
||||
|
||||
// Orca: the restored config may have another extruder count than the tab shows.
|
||||
if (auto printer_tab = dynamic_cast<TabPrinter *>(this))
|
||||
printer_tab->sync_extruders_count();
|
||||
|
||||
// When all values are rolled, then we have to update whole tab in respect to the reverted values
|
||||
update();
|
||||
if (m_active_page)
|
||||
@@ -1877,6 +1913,17 @@ static wxString pad_combo_value_for_config(const DynamicPrintConfig &config)
|
||||
return config.opt_bool("pad_enable") ? (config.opt_bool("pad_around_object") ? _("Around object") : _("Below object")) : _("None");
|
||||
}
|
||||
|
||||
// Rebuilds the variant switch of every tab that has one, e.g. after the extruder count or a nozzle volume type changed.
|
||||
static void update_all_extruder_variants(int extruder_idx = -1)
|
||||
{
|
||||
for (auto tab : wxGetApp().tabs_list)
|
||||
tab->update_extruder_variants(extruder_idx);
|
||||
if (auto tab = wxGetApp().plate_tab)
|
||||
tab->update_extruder_variants(extruder_idx);
|
||||
for (auto tab : wxGetApp().model_tabs_list)
|
||||
tab->update_extruder_variants(extruder_idx);
|
||||
}
|
||||
|
||||
void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
{
|
||||
// Orca:
|
||||
@@ -2319,15 +2366,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
|
||||
if (opt_key.find("nozzle_volume_type") != std::string::npos) {
|
||||
int extruder_idx = std::atoi(opt_key.substr(opt_key.find_last_of('#') + 1).c_str());
|
||||
for (auto tab : wxGetApp().tabs_list) {
|
||||
tab->update_extruder_variants(extruder_idx);
|
||||
}
|
||||
if (auto tab = wxGetApp().plate_tab) {
|
||||
tab->update_extruder_variants(extruder_idx);
|
||||
}
|
||||
for (auto tab : wxGetApp().model_tabs_list) {
|
||||
tab->update_extruder_variants(extruder_idx);
|
||||
}
|
||||
update_all_extruder_variants(extruder_idx);
|
||||
if (wxGetApp().app_config->get("auto_calculate_flush") == "all") {
|
||||
wxGetApp().plater()->sidebar().auto_calc_flushing_volumes(-1,extruder_idx);
|
||||
}
|
||||
@@ -5685,9 +5724,13 @@ if (is_marlin_flavor)
|
||||
size_t extruders_count = size_t(boost::any_cast<int>(v));
|
||||
wxTheApp->CallAfter([this, opt_key, value, extruders_count]() {
|
||||
if (opt_key == "extruders_count" || opt_key == "single_extruder_multi_material") {
|
||||
const size_t old_extruders_count = m_extruders_count;
|
||||
extruders_count_changed(extruders_count);
|
||||
init_options_list(); // m_options_list should be updated before UI updating
|
||||
update_dirty();
|
||||
// Orca: the variant switches (here, Process in the sidebar, ...) list one option per extruder.
|
||||
if (m_extruders_count != old_extruders_count)
|
||||
update_all_extruder_variants();
|
||||
if (opt_key == "single_extruder_multi_material") { // the single_extruder_multimaterial was added to force pages
|
||||
on_value_change(opt_key, value); // rebuild - let's make sure the on_value_change is not skipped
|
||||
|
||||
@@ -5697,6 +5740,7 @@ if (is_marlin_flavor)
|
||||
// Orca: we use a different logic here. If SEMM is enabled, we set extruder count to 1.
|
||||
#if 1
|
||||
extruders_count_changed(1);
|
||||
update_all_extruder_variants();
|
||||
#else
|
||||
|
||||
std::vector<double> nozzle_diameters =
|
||||
@@ -5768,14 +5812,13 @@ if (is_marlin_flavor)
|
||||
m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page);
|
||||
}
|
||||
|
||||
// Orca: build missed extruder pages
|
||||
for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) {
|
||||
const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder");
|
||||
|
||||
//# build page
|
||||
//const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1));
|
||||
auto page = add_options_page(page_name, "custom-gcode_extruder", true); // ORCA: icon only visible on placeholders
|
||||
m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page);
|
||||
// Orca: a single "Extruder" page serves all extruders. Its controls are created once for extruder 0;
|
||||
// switch_excluder() re-targets them to the extruder selected on the variant switch (m_extruder_switch),
|
||||
// which the printer tab shows on this page too.
|
||||
if (extruder_page() == nullptr && m_extruders_count > 0) {
|
||||
const size_t extruder_idx = 0;
|
||||
auto page = add_options_page(L("Extruder"), "custom-gcode_extruder", true); // ORCA: icon only visible on placeholders
|
||||
m_pages.insert(m_pages.begin() + n_before_extruders, page);
|
||||
|
||||
auto optgroup = page->new_optgroup(L("Basic information"), L"param_information", -1, true);
|
||||
optgroup->append_single_option_line("nozzle_diameter", "printer_extruder_basic_information#nozzle-diameter", extruder_idx);
|
||||
@@ -5788,8 +5831,10 @@ if (is_marlin_flavor)
|
||||
option.opt.full_width = true;
|
||||
optgroup->append_single_option_line(option, "printer_extruder_basic_information#extruder-offset-position");
|
||||
|
||||
optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
|
||||
optgroup->m_on_change = [this](const t_config_option_key& opt_key, boost::any value)
|
||||
{
|
||||
// The page edits the extruder selected on the variant switch.
|
||||
const size_t extruder_idx = size_t(get_current_active_extruder());
|
||||
bool is_SEMM = m_config->opt_bool("single_extruder_multi_material");
|
||||
if (is_SEMM && m_extruders_count > 1 && boost::starts_with(opt_key, "nozzle_diameter"))
|
||||
{
|
||||
@@ -5884,22 +5929,22 @@ if (is_marlin_flavor)
|
||||
//optgroup->append_line(line);
|
||||
#endif
|
||||
}
|
||||
// BBS. No extra extruder page for single physical extruder machine
|
||||
// # remove extra pages
|
||||
auto &first_extruder_title = const_cast<wxString &>(m_pages[n_before_extruders]->title());
|
||||
if (m_extruders_count < m_extruders_count_old) {
|
||||
m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count,
|
||||
m_pages.begin() + n_before_extruders + m_extruders_count_old);
|
||||
if (m_extruders_count == 1)
|
||||
first_extruder_title = wxString::Format("Extruder");
|
||||
} else if (m_extruders_count_old == 1) {
|
||||
first_extruder_title = wxString::Format("Extruder %d", 1);
|
||||
}
|
||||
auto & index = wxGetApp().sidebar().settings_index();
|
||||
for (auto &group : m_pages[n_before_extruders]->m_optgroups) {
|
||||
group->set_config_category_and_type(first_extruder_title, m_type);
|
||||
for (auto &opt : group->opt_map())
|
||||
index.add_key(opt.first + "#0", m_type, group->title, first_extruder_title, group->icon);
|
||||
|
||||
// The page holds only the "#0" controls, so register every extruder's options with the search
|
||||
// index under "Extruder N"; a search hit selects that extruder (TabPrinter::activate_option()).
|
||||
if (Page *page = extruder_page()) {
|
||||
auto &index = wxGetApp().sidebar().settings_index();
|
||||
for (auto &group : page->m_optgroups) {
|
||||
group->set_config_category_and_type(page->title(), m_type);
|
||||
for (auto &opt : group->opt_map()) {
|
||||
if (opt.second.second < 0)
|
||||
continue;
|
||||
for (size_t i = 0; i < m_extruders_count; ++i) {
|
||||
const wxString category = m_extruders_count > 1 ? wxString::Format("Extruder %d", int(i + 1)) : wxString("Extruder");
|
||||
index.add_key(opt.second.first + "#" + std::to_string(i), m_type, group->title, category, group->icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Thaw();
|
||||
@@ -6180,12 +6225,6 @@ void TabPrinter::toggle_options()
|
||||
return;
|
||||
|
||||
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
|
||||
auto extruders = m_config->option<ConfigOptionEnumsGeneric>("extruder_type");
|
||||
auto get_index_for_extruder =
|
||||
[this, &extruders](int extruder_id, int stride = 1) {
|
||||
return m_config->get_index_for_extruder(extruder_id + 1, "printer_extruder_id",
|
||||
ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), "printer_extruder_variant", stride);
|
||||
};
|
||||
|
||||
//BBS: whether the preset is Bambu Lab printer
|
||||
bool is_BBL_printer = false;
|
||||
@@ -6260,14 +6299,13 @@ void TabPrinter::toggle_options()
|
||||
toggle_option("tool_change_on_wipe_tower", !bSEMM && supports_wipe_tower_2 && extruders_count > 1);
|
||||
toggle_option("wait_for_temp_on_wipe_tower", !bSEMM && supports_wipe_tower_2 && extruders_count > 1);
|
||||
}
|
||||
wxString extruder_number;
|
||||
long val = 1;
|
||||
if ( m_active_page->title().IsSameAs(L("Extruder")) ||
|
||||
(m_active_page->title().StartsWith("Extruder ", &extruder_number) && extruder_number.ToLong(&val) &&
|
||||
val > 0 && (size_t)val <= m_extruders_count))
|
||||
if (m_active_page->title() == L("Extruder") && m_extruders_count > 0)
|
||||
{
|
||||
size_t i = size_t(val - 1);
|
||||
int variant_index = get_index_for_extruder(i);
|
||||
// Orca: the single Extruder page edits the extruder selected on the variant switch; its
|
||||
// controls carry field index 0 (i), the values are read for `extruder`.
|
||||
const size_t i = 0;
|
||||
const size_t extruder = std::min<size_t>(size_t(get_current_active_extruder()), m_extruders_count - 1);
|
||||
const int variant_index = extruder_variant_index(int(extruder));
|
||||
bool have_retract_length = m_config->opt_float("retraction_length", variant_index) > 0;
|
||||
|
||||
toggle_option("extruder_printable_area", false, i); // disable
|
||||
@@ -6294,7 +6332,7 @@ void TabPrinter::toggle_options()
|
||||
vec.resize(0);
|
||||
vec = {"retract_lift_above", "retract_lift_below", "retract_lift_enforce"};
|
||||
for (auto el : vec)
|
||||
toggle_option(el, retraction && (m_config->opt_float("z_hop", i) > 0), i);
|
||||
toggle_option(el, retraction && (m_config->opt_float("z_hop", variant_index) > 0), i);
|
||||
|
||||
// some options only apply when not using firmware retraction
|
||||
vec.resize(0);
|
||||
@@ -6347,7 +6385,7 @@ void TabPrinter::toggle_options()
|
||||
toggle_option("long_retractions_when_cut", !use_firmware_retraction && m_config->opt_int("enable_long_retraction_when_cut"), i);
|
||||
toggle_line("retraction_distances_when_cut", m_config->opt_bool("long_retractions_when_cut", variant_index), i);
|
||||
|
||||
toggle_option("travel_slope", m_config->opt_enum("z_hop_types", i) != ZHopType::zhtNormal, i);
|
||||
toggle_option("travel_slope", m_config->opt_enum("z_hop_types", variant_index) != ZHopType::zhtNormal, i);
|
||||
}
|
||||
|
||||
if (m_active_page->title() == L("Motion ability")) {
|
||||
@@ -6421,12 +6459,16 @@ void TabPrinter::on_value_change(const std::string& opt_key, const boost::any& v
|
||||
return;
|
||||
|
||||
const int pos = opt_key.find("#");
|
||||
// Orca: fields of the single Extruder page keep index 0 but edit the selected extruder.
|
||||
const int data_idx = pos > 0 ? extruder_page_data_index(opt_key) : -1;
|
||||
|
||||
if (pos > 0) {
|
||||
std::string temp_str = opt_key;
|
||||
boost::erase_head(temp_str, pos + 1);
|
||||
int orig_opt_idx = static_cast<size_t>(atoi(temp_str.c_str()));
|
||||
int opt_idx = orig_opt_idx >= 0 ? orig_opt_idx : 0;
|
||||
if (data_idx >= 0)
|
||||
opt_idx = data_idx;
|
||||
|
||||
std::string opt_key_pure = opt_key;
|
||||
boost::erase_tail(opt_key_pure, opt_key_pure.size() - pos);
|
||||
@@ -6461,7 +6503,12 @@ void TabPrinter::on_value_change(const std::string& opt_key, const boost::any& v
|
||||
}
|
||||
}
|
||||
|
||||
Tab::on_value_change(opt_key, value);
|
||||
// Orca: report Extruder page changes as "key#<extruder>", as the former "Extruder N" pages did,
|
||||
// so per-extruder handling in Tab::on_value_change() sees the extruder that was edited.
|
||||
if (data_idx >= 0)
|
||||
Tab::on_value_change(opt_key.substr(0, pos) + "#" + std::to_string(get_current_active_extruder()), value);
|
||||
else
|
||||
Tab::on_value_change(opt_key, value);
|
||||
}
|
||||
|
||||
void TabPrinter::update()
|
||||
@@ -7393,12 +7440,7 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
|
||||
// update_undo_buttons();
|
||||
this->OnActivate();
|
||||
m_parent->set_active_tab(this);
|
||||
if (m_variant_sizer) {
|
||||
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
|
||||
m_main_sizer->Show(m_variant_sizer, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder "));
|
||||
if (m_extruder_sync) m_extruder_sync->Show(variant_ctrl->IsShown());
|
||||
GetParent()->Layout();
|
||||
}
|
||||
update_variant_sizer_visibility();
|
||||
|
||||
m_page_view->Thaw();
|
||||
return false;
|
||||
@@ -7409,12 +7451,7 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
|
||||
return false;
|
||||
|
||||
m_active_page = page;
|
||||
if (m_variant_sizer) {
|
||||
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
|
||||
m_main_sizer->Show(m_variant_sizer, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder"));
|
||||
if (m_extruder_sync) m_extruder_sync->Show(variant_ctrl->IsShown());
|
||||
GetParent()->Layout();
|
||||
}
|
||||
update_variant_sizer_visibility();
|
||||
|
||||
auto throw_if_canceled = std::function<void()>([this](){
|
||||
#ifdef WIN32
|
||||
@@ -8240,9 +8277,11 @@ void Tab::update_extruder_variants(int extruder_id, bool reload)
|
||||
m_actual_nozzle_volumes.resize(extruder_nums, NozzleVolumeType::nvtStandard);
|
||||
for (int i = 0; i < extruder_nums; i++) m_actual_nozzle_volumes[i] = (NozzleVolumeType)nozzle_volumes->values[i];
|
||||
|
||||
// Orca: a non-Bambu dual-nozzle printer has two extruders but a single variant column, so
|
||||
// the nozzle switch and sync button have nothing to act on. Only enable with real variants.
|
||||
if (extruder_nums >= 2 && m_preset_bundle->support_different_extruders()) {
|
||||
// Orca: when every extruder uses the same variant (e.g. a non-Bambu dual-nozzle printer), the
|
||||
// switch has no nozzle variants to select and nothing to sync. The printer tab still enables it
|
||||
// to choose the extruder its Extruder and Motion ability pages edit.
|
||||
m_extruder_switch_variants = extruder_nums >= 2 && m_preset_bundle->support_different_extruders();
|
||||
if (m_extruder_switch_variants || (m_type == Preset::TYPE_PRINTER && extruder_nums >= 2)) {
|
||||
auto options = generate_extruder_options();
|
||||
m_extruder_switch->SetOptions(options);
|
||||
|
||||
@@ -8281,12 +8320,8 @@ void Tab::update_extruder_variants(int extruder_id, bool reload)
|
||||
if (m_type == Preset::TYPE_PRINT) {
|
||||
update_pages_with_multi_variant();
|
||||
}
|
||||
if (m_variant_sizer) {
|
||||
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
|
||||
m_main_sizer->Show(m_variant_sizer, variant_ctrl->IsThisEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder "));
|
||||
if (m_extruder_sync) m_extruder_sync->Show(variant_ctrl->IsShown());
|
||||
GetParent()->Layout();
|
||||
}
|
||||
update_extruder_switch_colors();
|
||||
update_variant_sizer_visibility();
|
||||
}
|
||||
|
||||
// The variant switch tags are the narrowest place a volume type is named, so they abbreviate it;
|
||||
@@ -8361,12 +8396,21 @@ std::vector<wxString> Tab::generate_extruder_options()
|
||||
return options;
|
||||
}
|
||||
|
||||
// Orca: the printer tab has one tag per extruder, named as its former "Extruder N" pages were.
|
||||
// parse_extruder_selection() counts a hybrid extruder as two tags; that still lines up because
|
||||
// only the last extruder can be hybrid.
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
for (int i = 0; i < extruder_nums; ++i)
|
||||
options.push_back(translate_category(wxString::Format("Extruder %d", i + 1), m_type));
|
||||
return options;
|
||||
}
|
||||
|
||||
std::string pt = m_preset_bundle->printers.get_edited_preset().get_printer_type(m_preset_bundle);
|
||||
// Orca: the main/deputy toolhead names describe a dual-nozzle printer, where extruder 0 is the
|
||||
// left (deputy) and extruder 1 the right (main) nozzle. From three extruders on the tools are
|
||||
// interchangeable, so name them by index instead of repeating one side.
|
||||
// Orca: the main/deputy toolhead names describe a Bambu dual-nozzle printer, where extruder 0 is
|
||||
// the left (deputy) and extruder 1 the right (main) nozzle. Other printers number their tools.
|
||||
const bool toolhead_names = extruder_nums == 2 && m_preset_bundle->is_bbl_vendor();
|
||||
for (int i = 0; i < extruder_nums; ++i) {
|
||||
wxString extruder_name = extruder_nums > 2 ? wxString::Format("T%d", i + 1) :
|
||||
wxString extruder_name = !toolhead_names ? wxString::Format("T%d", i + 1) :
|
||||
_L(DevPrinterConfigUtil::get_toolhead_display_name(
|
||||
pt, (i == 0) ? DEPUTY_EXTRUDER_ID : MAIN_EXTRUDER_ID,
|
||||
ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase, true));
|
||||
@@ -8383,6 +8427,71 @@ std::vector<wxString> Tab::generate_extruder_options()
|
||||
return options;
|
||||
}
|
||||
|
||||
Page *TabPrinter::extruder_page() const
|
||||
{
|
||||
for (const PageShp &page : m_pages)
|
||||
if (page->title() == "Extruder")
|
||||
return page.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int TabPrinter::extruder_page_data_index(const std::string &field_id) const
|
||||
{
|
||||
if (Page *page = extruder_page())
|
||||
for (const auto &group : page->m_optgroups)
|
||||
if (auto it = group->opt_map().find(field_id); it != group->opt_map().end())
|
||||
return it->second.second;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int TabPrinter::extruder_variant_index(int extruder)
|
||||
{
|
||||
const auto *extruders = m_config->option<ConfigOptionEnumsGeneric>("extruder_type");
|
||||
const int index = extruder < int(extruders->size()) ?
|
||||
m_config->get_index_for_extruder(extruder + 1, "printer_extruder_id", ExtruderType(extruders->values[extruder]),
|
||||
get_actual_nozzle_volume_type(extruder), "printer_extruder_variant") :
|
||||
-1;
|
||||
return index < 0 ? extruder : index;
|
||||
}
|
||||
|
||||
void TabPrinter::update_custom_dirty(std::vector<std::string> &dirty_options, std::vector<std::string> &nonsys_options)
|
||||
{
|
||||
drop_unchanged_added_entries(dirty_options, *m_config, &m_presets->get_selected_preset());
|
||||
drop_unchanged_added_entries(nonsys_options, *m_config, m_presets->get_selected_preset_parent());
|
||||
}
|
||||
|
||||
void TabPrinter::sync_extruders_count()
|
||||
{
|
||||
if (m_printer_technology != ptFFF)
|
||||
return;
|
||||
const auto *nozzle_diameter = m_config->option<ConfigOptionFloats>("nozzle_diameter");
|
||||
if (nozzle_diameter == nullptr || nozzle_diameter->size() == m_extruders_count)
|
||||
return;
|
||||
extruders_count_changed(nozzle_diameter->size());
|
||||
init_options_list();
|
||||
update_all_extruder_variants();
|
||||
}
|
||||
|
||||
void TabPrinter::activate_option(const std::string &opt_key, const wxString &category)
|
||||
{
|
||||
wxString number;
|
||||
long n = 0;
|
||||
const bool numbered = category.StartsWith("Extruder ", &number) && number.ToLong(&n);
|
||||
if (extruder_page() == nullptr || (!numbered && category != "Extruder")) {
|
||||
Tab::activate_option(opt_key, category);
|
||||
return;
|
||||
}
|
||||
|
||||
// Selecting fires the switch's event, which re-targets the page (switch_excluder()).
|
||||
const int extruder_idx = (n >= 1 && n <= long(m_extruders_count)) ? int(n - 1) : 0;
|
||||
if (m_extruder_switch && m_extruder_switch->IsThisEnabled() && extruder_idx != get_current_active_extruder())
|
||||
m_extruder_switch->SetSelection(calculate_selection_index_for_extruder(extruder_idx, get_actual_nozzle_volume_type(extruder_idx)));
|
||||
|
||||
// The page's controls are created for index 0.
|
||||
const auto pos = opt_key.find('#');
|
||||
Tab::activate_option(pos == std::string::npos ? opt_key : opt_key.substr(0, pos) + "#0", "Extruder");
|
||||
}
|
||||
|
||||
NozzleVolumeType Tab::get_actual_nozzle_volume_type(int extruder_id)
|
||||
{
|
||||
int extruder_count = m_preset_bundle->get_printer_extruder_count();
|
||||
@@ -8459,18 +8568,44 @@ bool Tab::get_extruder_sync_enable_state(int extruder_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Tab::variant_switch_active() const
|
||||
{
|
||||
if (m_extruder_switch)
|
||||
return m_extruder_switch->IsThisEnabled();
|
||||
return m_variant_combo && m_variant_combo->IsThisEnabled();
|
||||
}
|
||||
|
||||
void Tab::update_variant_sizer_visibility()
|
||||
{
|
||||
if (!m_variant_sizer)
|
||||
return;
|
||||
const bool show = variant_switch_active() && m_active_page && !m_active_page->m_opt_id_map.empty();
|
||||
m_main_sizer->Show(m_variant_sizer, show);
|
||||
if (m_extruder_sync) {
|
||||
m_extruder_sync->Show(show);
|
||||
// Orca: copying between extruders is offered only between nozzle variants, and not on the Extruder page.
|
||||
m_extruder_sync->Enable(m_extruder_switch_variants && !is_printer_extruder_page(m_active_page) &&
|
||||
get_extruder_sync_enable_state(get_current_active_extruder()));
|
||||
}
|
||||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
void Tab::switch_excluder(int extruder_id, bool reload)
|
||||
{
|
||||
Preset & printer_preset = m_preset_bundle->printers.get_edited_preset();
|
||||
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
|
||||
auto extruders = printer_preset.config.option<ConfigOptionEnumsGeneric>("extruder_type");
|
||||
|
||||
// Orca: the printer tab re-targets its pages to the extruder selected on the switch. Resolved before
|
||||
// the range check below, which keeps the extruder_type read in get_index_for_extruder in range.
|
||||
if (m_type == Preset::TYPE_PRINTER && extruder_id == -1)
|
||||
extruder_id = get_current_active_extruder();
|
||||
if (!m_variant_combo && (extruder_id >= (int)nozzle_volumes->size() || extruder_id >= (int)extruders->size()))
|
||||
extruder_id = 0;
|
||||
if (m_extruder_switch) {
|
||||
int current_extruder = get_current_active_extruder();
|
||||
bool sync_enable = get_extruder_sync_enable_state(current_extruder);
|
||||
m_extruder_sync->Enable(m_extruder_switch->IsThisEnabled() && sync_enable);
|
||||
m_extruder_sync->Enable(m_extruder_switch_variants && sync_enable && !is_printer_extruder_page(m_active_page));
|
||||
m_extruder_sync->Show();
|
||||
if (m_type != Preset::TYPE_PRINTER) {
|
||||
if (extruder_id == -1)
|
||||
@@ -8497,24 +8632,26 @@ void Tab::switch_excluder(int extruder_id, bool reload)
|
||||
return;
|
||||
if (m_extruder_switch) m_extruder_switch->SetClientData(reinterpret_cast<void*>(static_cast<std::uintptr_t>(index)));
|
||||
if (m_variant_combo) m_variant_combo->SetClientData(reinterpret_cast<void *>(static_cast<std::uintptr_t>(index)));
|
||||
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
|
||||
for (auto page : m_pages) {
|
||||
bool is_extruder = false;
|
||||
int page_index = index;
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
if (page->title().StartsWith("Extruder")) {
|
||||
int extruder_id2 = std::atoi(page->title().Mid(9).ToUTF8()) - 1;
|
||||
if (extruder_id >= 0 && extruder_id2 != extruder_id)
|
||||
continue;
|
||||
if (extruder_id2 > 0)
|
||||
index = get_index_for_extruder(extruder_id2);
|
||||
if (page->title() == "Extruder")
|
||||
is_extruder = true;
|
||||
} else if (page->title().StartsWith("Motion ability")) {
|
||||
index = get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id, 2);
|
||||
}
|
||||
else if (page->title().StartsWith("Motion ability"))
|
||||
page_index = get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id, 2);
|
||||
}
|
||||
page->m_opt_id_map.clear();
|
||||
for (auto group : page->m_optgroups) {
|
||||
for (auto &opt : group->opt_map()) {
|
||||
if (is_extruder && opt.second.second >= 0) {
|
||||
// Per-variant options use the variant column, the others (nozzle_diameter,
|
||||
// extruder_offset, ...) are sized by the extruder count and use the extruder.
|
||||
const int idx = printer_options_with_variant_1.count(opt.second.first) > 0 ? page_index : extruder_id;
|
||||
const_cast<int &>(opt.second.second) = idx;
|
||||
page->m_opt_id_map.insert({opt.second.first + "#" + std::to_string(idx), opt.first});
|
||||
continue;
|
||||
}
|
||||
auto iter = std::find(printer_extruder_options.begin(), printer_extruder_options.end(), opt.second.first);
|
||||
if (iter != printer_extruder_options.end()) {
|
||||
page->m_opt_id_map.insert({opt.first, opt.first});
|
||||
@@ -8522,9 +8659,9 @@ void Tab::switch_excluder(int extruder_id, bool reload)
|
||||
}
|
||||
|
||||
if (opt.second.second >= 0) {
|
||||
const_cast<int &>(opt.second.second) = index;
|
||||
page->m_opt_id_map.insert({opt.second.first + "#" + std::to_string(index), opt.first});
|
||||
group->draw_multi_extruder = !is_extruder && variant_ctrl->IsThisEnabled();
|
||||
const_cast<int &>(opt.second.second) = page_index;
|
||||
page->m_opt_id_map.insert({opt.second.first + "#" + std::to_string(page_index), opt.first});
|
||||
group->draw_multi_extruder = variant_switch_active();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-1
@@ -331,6 +331,10 @@ public:
|
||||
MultiSwitchButton * m_variant_combo = nullptr;
|
||||
ScalableButton *m_extruder_sync = nullptr;
|
||||
wxPanel * m_extruder_sync_box = nullptr;
|
||||
// Orca: whether m_extruder_switch switches nozzle variants (it then offers sync between them).
|
||||
// The printer tab also enables the switch for printers without variants, to choose the extruder
|
||||
// its Extruder and Motion ability pages edit.
|
||||
bool m_extruder_switch_variants = false;
|
||||
std::vector<NozzleVolumeType> m_actual_nozzle_volumes;
|
||||
|
||||
public:
|
||||
@@ -387,6 +391,13 @@ public:
|
||||
void update_changed_tree_ui();
|
||||
void update_undo_buttons();
|
||||
void update_extruder_switch_colors();
|
||||
// Whether the variant switch (m_extruder_switch / m_variant_combo) is enabled: on the printer tab for
|
||||
// any multi-extruder printer, on the other tabs when it switches nozzle variants.
|
||||
bool variant_switch_active() const;
|
||||
// Orca: whether `page` is the printer tab's single "Extruder" page, which edits the extruder selected on the switch.
|
||||
bool is_printer_extruder_page(const Page* page) const { return m_type == Preset::TYPE_PRINTER && page && page->title() == "Extruder"; }
|
||||
// Shows the variant switch row on pages with options that follow it.
|
||||
void update_variant_sizer_visibility();
|
||||
void update_all_extruder_options_status();
|
||||
void check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector<PageShp>& pages_to_check);
|
||||
|
||||
@@ -444,7 +455,7 @@ public:
|
||||
virtual void on_value_change(const std::string& opt_key, const boost::any& value);
|
||||
|
||||
void update_wiping_button_visibility();
|
||||
void activate_option(const std::string& opt_key, const wxString& category);
|
||||
virtual void activate_option(const std::string& opt_key, const wxString& category);
|
||||
void apply_searcher();
|
||||
void cache_config_diff(const std::vector<std::string>& selected_options, const DynamicPrintConfig* config = nullptr);
|
||||
void apply_config_from_cache();
|
||||
@@ -710,6 +721,25 @@ public:
|
||||
void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr);
|
||||
bool apply_extruder_cnt_from_cache();
|
||||
void refresh_printer_agent_dropdown() const;
|
||||
|
||||
// Orca: a single "Extruder" page for all extruders. Its controls are created once (index 0) and
|
||||
// switch_excluder() re-targets them to the extruder selected on m_extruder_switch.
|
||||
Page* extruder_page() const;
|
||||
// Config index an "Extruder" page field (e.g. "retraction_length#0") currently edits, -1 if not on that page.
|
||||
int extruder_page_data_index(const std::string& field_id) const;
|
||||
// Config index of an extruder's per-variant options (Retraction, Z-Hop, ...): its variant column
|
||||
// for the nozzle selected on the switch, or the extruder index on a printer without variants.
|
||||
int extruder_variant_index(int extruder);
|
||||
// After the config was restored (roll back): follow its extruder count, if it differs.
|
||||
void sync_extruders_count();
|
||||
// Search jump to "Extruder N" / "key#N": selects extruder N on the switch, then activates the
|
||||
// page's own field on the "Extruder" page.
|
||||
void activate_option(const std::string& opt_key, const wxString& category) override;
|
||||
|
||||
protected:
|
||||
// Orca: values of extruders added by raising the extruder count have no saved / system value to
|
||||
// revert to; the change is shown on "extruders_count", not on each of their parameters.
|
||||
void update_custom_dirty(std::vector<std::string> &dirty_options, std::vector<std::string> &nonsys_options) override;
|
||||
};
|
||||
|
||||
class TabSLAMaterial : public Tab
|
||||
|
||||
@@ -89,6 +89,7 @@ using fn_ft_job_get_result = ft_err(FT_CALL *)(FT_JobHandle *, uint32_t timeo
|
||||
using fn_ft_tunnel_start_job = ft_err(FT_CALL *)(FT_TunnelHandle *, FT_JobHandle *);
|
||||
using fn_ft_job_cancel = ft_err(FT_CALL *)(FT_JobHandle *);
|
||||
|
||||
using fn_ft_job_msg_destroy = void(FT_CALL *)(ft_job_msg *);
|
||||
using fn_ft_job_set_msg_cb = ft_err(FT_CALL *)(FT_JobHandle *, void(FT_CALL *)(void *user, ft_job_msg msg), void *user);
|
||||
using fn_ft_job_try_get_msg = ft_err(FT_CALL *)(FT_JobHandle *, ft_job_msg *out_msg);
|
||||
using fn_ft_job_get_msg = ft_err(FT_CALL *)(FT_JobHandle *, uint32_t timeout_ms, ft_job_msg *out_msg);
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
namespace Slic3r {
|
||||
namespace Utils {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
// Generic command / response TCP telnet like console class.
|
||||
// Used by the MKS host to send G-code commands to test connection ("M105") and to start printing ("M23 filename", "M24").
|
||||
class TCPConsole
|
||||
{
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
|
||||
public:
|
||||
TCPConsole() : m_resolver(m_io_context), m_socket(m_io_context) { set_defaults(); }
|
||||
TCPConsole(const std::string& host_name, const std::string& port_name) : m_resolver(m_io_context), m_socket(m_io_context)
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
namespace beast = boost::beast; // from <boost/beast.hpp>
|
||||
namespace http = beast::http; // from <boost/beast/http.hpp>
|
||||
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
|
||||
namespace net = boost::asio; // from <boost/asio.hpp>
|
||||
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
|
||||
|
||||
class WebSocketClient {
|
||||
public:
|
||||
@@ -31,7 +36,7 @@ public:
|
||||
}
|
||||
try {
|
||||
// Close the WebSocket connection
|
||||
ws_.close(boost::beast::websocket::close_code::normal);
|
||||
ws_.close(websocket::close_code::normal);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
}
|
||||
@@ -44,7 +49,7 @@ public:
|
||||
auto const results = resolver_.resolve(host, port);
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
auto ep = boost::asio::connect(ws_.next_layer(), results);
|
||||
auto ep = net::connect(ws_.next_layer(), results);
|
||||
std::string _host = host;
|
||||
//if _host last char is '/', remove it
|
||||
if(_host.size()>0&&_host[host.size()-1] == '/'){
|
||||
@@ -53,10 +58,10 @@ public:
|
||||
|
||||
// _host += ':' + std::to_string(ep.port());
|
||||
// Set a decorator to change the User-Agent of the handshake
|
||||
ws_.set_option(boost::beast::websocket::stream_base::decorator(
|
||||
[](boost::beast::websocket::request_type& req)
|
||||
ws_.set_option(websocket::stream_base::decorator(
|
||||
[](websocket::request_type& req)
|
||||
{
|
||||
req.set(boost::beast::http::field::user_agent,"ElegooSlicer");
|
||||
req.set(http::field::user_agent,"ElegooSlicer");
|
||||
}));
|
||||
// Perform the WebSocket handshake
|
||||
ws_.handshake(_host, path);
|
||||
@@ -65,25 +70,25 @@ public:
|
||||
|
||||
void send(const std::string& message){
|
||||
// Send a message
|
||||
ws_.write(boost::asio::buffer(message));
|
||||
ws_.write(net::buffer(message));
|
||||
}
|
||||
|
||||
std::string receive(int timeout = 0){
|
||||
// This buffer will hold the incoming message
|
||||
boost::beast::flat_buffer buffer;
|
||||
beast::flat_buffer buffer;
|
||||
|
||||
// Read a message into our buffer
|
||||
ws_.read(buffer);
|
||||
|
||||
// Return the message as a string
|
||||
return boost::beast::buffers_to_string(buffer.data());
|
||||
return beast::buffers_to_string(buffer.data());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
boost::asio::io_context ioc_;
|
||||
boost::asio::ip::tcp::resolver resolver_;
|
||||
boost::beast::websocket::stream<boost::asio::ip::tcp::socket> ws_;
|
||||
net::io_context ioc_;
|
||||
tcp::resolver resolver_;
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
bool is_connect;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,18 +17,20 @@
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// Put serializers in correct ADL namespaces for each type
|
||||
|
||||
namespace Slic3r {
|
||||
namespace FilamentGroupUtils {
|
||||
|
||||
inline void to_json(nlohmann::json& j, const Color& c) {
|
||||
inline void to_json(json& j, const Color& c) {
|
||||
char buf[10];
|
||||
snprintf(buf, sizeof(buf), "#%02X%02X%02X%02X", c.r, c.g, c.b, c.a);
|
||||
j = std::string(buf);
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, Color& c) {
|
||||
inline void from_json(const json& j, Color& c) {
|
||||
std::string s = j.get<std::string>();
|
||||
if (s.size() >= 7 && s[0] == '#') {
|
||||
c.r = (unsigned char)std::stoi(s.substr(1, 2), nullptr, 16);
|
||||
@@ -38,8 +40,8 @@ inline void from_json(const nlohmann::json& j, Color& c) {
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json& j, const FilamentInfo& fi) {
|
||||
j = nlohmann::json{
|
||||
inline void to_json(json& j, const FilamentInfo& fi) {
|
||||
j = json{
|
||||
{"color", fi.color},
|
||||
{"type", fi.type},
|
||||
{"is_support", fi.is_support},
|
||||
@@ -47,15 +49,15 @@ inline void to_json(nlohmann::json& j, const FilamentInfo& fi) {
|
||||
};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentInfo& fi) {
|
||||
inline void from_json(const json& j, FilamentInfo& fi) {
|
||||
fi.color = j.at("color").get<Color>();
|
||||
j.at("type").get_to(fi.type);
|
||||
j.at("is_support").get_to(fi.is_support);
|
||||
fi.usage_type = (FilamentUsageType)j.at("usage_type").get<int>();
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json& j, const MachineFilamentInfo& mfi) {
|
||||
j = nlohmann::json{
|
||||
inline void to_json(json& j, const MachineFilamentInfo& mfi) {
|
||||
j = json{
|
||||
{"color", mfi.color},
|
||||
{"type", mfi.type},
|
||||
{"is_support", mfi.is_support},
|
||||
@@ -65,7 +67,7 @@ inline void to_json(nlohmann::json& j, const MachineFilamentInfo& mfi) {
|
||||
};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, MachineFilamentInfo& mfi) {
|
||||
inline void from_json(const json& j, MachineFilamentInfo& mfi) {
|
||||
mfi.color = j.at("color").get<Color>();
|
||||
j.at("type").get_to(mfi.type);
|
||||
j.at("is_support").get_to(mfi.is_support);
|
||||
@@ -78,8 +80,8 @@ inline void from_json(const nlohmann::json& j, MachineFilamentInfo& mfi) {
|
||||
|
||||
namespace MultiNozzleUtils {
|
||||
|
||||
inline void to_json(nlohmann::json& j, const NozzleInfo& ni) {
|
||||
j = nlohmann::json{
|
||||
inline void to_json(json& j, const NozzleInfo& ni) {
|
||||
j = json{
|
||||
{"diameter", ni.diameter},
|
||||
{"volume_type", (int)ni.volume_type},
|
||||
{"extruder_id", ni.extruder_id},
|
||||
@@ -87,15 +89,15 @@ inline void to_json(nlohmann::json& j, const NozzleInfo& ni) {
|
||||
};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, NozzleInfo& ni) {
|
||||
inline void from_json(const json& j, NozzleInfo& ni) {
|
||||
j.at("diameter").get_to(ni.diameter);
|
||||
ni.volume_type = (NozzleVolumeType)j.at("volume_type").get<int>();
|
||||
j.at("extruder_id").get_to(ni.extruder_id);
|
||||
j.at("group_id").get_to(ni.group_id);
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json& j, const FilamentChangeTimeParams& p) {
|
||||
j = nlohmann::json{
|
||||
inline void to_json(json& j, const FilamentChangeTimeParams& p) {
|
||||
j = json{
|
||||
{"selector_load_time", p.selector_load_time},
|
||||
{"selector_unload_time", p.selector_unload_time},
|
||||
{"standard_load_time", p.standard_load_time},
|
||||
@@ -103,7 +105,7 @@ inline void to_json(nlohmann::json& j, const FilamentChangeTimeParams& p) {
|
||||
};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentChangeTimeParams& p) {
|
||||
inline void from_json(const json& j, FilamentChangeTimeParams& p) {
|
||||
j.at("selector_load_time").get_to(p.selector_load_time);
|
||||
j.at("selector_unload_time").get_to(p.selector_unload_time);
|
||||
j.at("standard_load_time").get_to(p.standard_load_time);
|
||||
@@ -114,22 +116,22 @@ inline void from_json(const nlohmann::json& j, FilamentChangeTimeParams& p) {
|
||||
|
||||
// ============ Helper: set<int> as JSON array ============
|
||||
namespace FGTestDetail {
|
||||
inline nlohmann::json set_to_json(const std::set<int>& s) {
|
||||
return nlohmann::json(std::vector<int>(s.begin(), s.end()));
|
||||
inline json set_to_json(const std::set<int>& s) {
|
||||
return json(std::vector<int>(s.begin(), s.end()));
|
||||
}
|
||||
|
||||
inline std::set<int> json_to_set(const nlohmann::json& j) {
|
||||
inline std::set<int> json_to_set(const json& j) {
|
||||
auto v = j.get<std::vector<int>>();
|
||||
return std::set<int>(v.begin(), v.end());
|
||||
}
|
||||
|
||||
inline nlohmann::json nvt_set_to_json(const std::set<NozzleVolumeType>& s) {
|
||||
inline json nvt_set_to_json(const std::set<NozzleVolumeType>& s) {
|
||||
std::vector<int> v;
|
||||
for (auto t : s) v.push_back((int)t);
|
||||
return nlohmann::json(v);
|
||||
return json(v);
|
||||
}
|
||||
|
||||
inline std::set<NozzleVolumeType> json_to_nvt_set(const nlohmann::json& j) {
|
||||
inline std::set<NozzleVolumeType> json_to_nvt_set(const json& j) {
|
||||
std::set<NozzleVolumeType> s;
|
||||
for (auto& item : j) s.insert((NozzleVolumeType)item.get<int>());
|
||||
return s;
|
||||
@@ -137,28 +139,28 @@ inline std::set<NozzleVolumeType> json_to_nvt_set(const nlohmann::json& j) {
|
||||
} // namespace FGTestDetail
|
||||
|
||||
// ============ FilamentGroupContext::ModelInfo ============
|
||||
inline void to_json(nlohmann::json& j, const FilamentGroupContext::ModelInfo& mi) {
|
||||
inline void to_json(json& j, const FilamentGroupContext::ModelInfo& mi) {
|
||||
using namespace FGTestDetail;
|
||||
j["flush_matrix"] = mi.flush_matrix;
|
||||
j["layer_filaments"] = mi.layer_filaments;
|
||||
|
||||
j["filament_info"] = nlohmann::json::array();
|
||||
j["filament_info"] = json::array();
|
||||
for (auto& fi : mi.filament_info)
|
||||
j["filament_info"].push_back(fi);
|
||||
|
||||
j["filament_ids"] = mi.filament_ids;
|
||||
|
||||
j["unprintable_filaments"] = nlohmann::json::array();
|
||||
j["unprintable_filaments"] = json::array();
|
||||
for (auto& s : mi.unprintable_filaments)
|
||||
j["unprintable_filaments"].push_back(set_to_json(s));
|
||||
|
||||
nlohmann::json uv = nlohmann::json::object();
|
||||
json uv = json::object();
|
||||
for (auto& [fil, types] : mi.unprintable_volumes)
|
||||
uv[std::to_string(fil)] = nvt_set_to_json(types);
|
||||
j["unprintable_volumes"] = uv;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentGroupContext::ModelInfo& mi) {
|
||||
inline void from_json(const json& j, FilamentGroupContext::ModelInfo& mi) {
|
||||
using namespace FGTestDetail;
|
||||
j.at("flush_matrix").get_to(mi.flush_matrix);
|
||||
j.at("layer_filaments").get_to(mi.layer_filaments);
|
||||
@@ -181,8 +183,8 @@ inline void from_json(const nlohmann::json& j, FilamentGroupContext::ModelInfo&
|
||||
}
|
||||
|
||||
// ============ FilamentGroupContext::GroupInfo ============
|
||||
inline void to_json(nlohmann::json& j, const FilamentGroupContext::GroupInfo& gi) {
|
||||
j = nlohmann::json{
|
||||
inline void to_json(json& j, const FilamentGroupContext::GroupInfo& gi) {
|
||||
j = json{
|
||||
{"total_filament_num", gi.total_filament_num},
|
||||
{"max_gap_threshold", gi.max_gap_threshold},
|
||||
{"mode", (int)gi.mode},
|
||||
@@ -193,7 +195,7 @@ inline void to_json(nlohmann::json& j, const FilamentGroupContext::GroupInfo& gi
|
||||
};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentGroupContext::GroupInfo& gi) {
|
||||
inline void from_json(const json& j, FilamentGroupContext::GroupInfo& gi) {
|
||||
j.at("total_filament_num").get_to(gi.total_filament_num);
|
||||
j.at("max_gap_threshold").get_to(gi.max_gap_threshold);
|
||||
gi.mode = (FGMode)j.at("mode").get<int>();
|
||||
@@ -204,12 +206,12 @@ inline void from_json(const nlohmann::json& j, FilamentGroupContext::GroupInfo&
|
||||
}
|
||||
|
||||
// ============ FilamentGroupContext::MachineInfo ============
|
||||
inline void to_json(nlohmann::json& j, const FilamentGroupContext::MachineInfo& mi) {
|
||||
inline void to_json(json& j, const FilamentGroupContext::MachineInfo& mi) {
|
||||
j["max_group_size"] = mi.max_group_size;
|
||||
|
||||
j["machine_filament_info"] = nlohmann::json::array();
|
||||
j["machine_filament_info"] = json::array();
|
||||
for (auto& vec : mi.machine_filament_info) {
|
||||
nlohmann::json arr = nlohmann::json::array();
|
||||
json arr = json::array();
|
||||
for (auto& mfi : vec) arr.push_back(mfi);
|
||||
j["machine_filament_info"].push_back(arr);
|
||||
}
|
||||
@@ -218,7 +220,7 @@ inline void to_json(nlohmann::json& j, const FilamentGroupContext::MachineInfo&
|
||||
j["master_extruder_id"] = mi.master_extruder_id;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentGroupContext::MachineInfo& mi) {
|
||||
inline void from_json(const json& j, FilamentGroupContext::MachineInfo& mi) {
|
||||
j.at("max_group_size").get_to(mi.max_group_size);
|
||||
|
||||
mi.machine_filament_info.clear();
|
||||
@@ -234,10 +236,10 @@ inline void from_json(const nlohmann::json& j, FilamentGroupContext::MachineInfo
|
||||
}
|
||||
|
||||
// ============ FilamentGroupContext::SpeedInfo ============
|
||||
inline void to_json(nlohmann::json& j, const FilamentGroupContext::SpeedInfo& si) {
|
||||
nlohmann::json fpt = nlohmann::json::object();
|
||||
inline void to_json(json& j, const FilamentGroupContext::SpeedInfo& si) {
|
||||
json fpt = json::object();
|
||||
for (auto& [fil, inner] : si.filament_print_time) {
|
||||
nlohmann::json inner_j = nlohmann::json::object();
|
||||
json inner_j = json::object();
|
||||
for (auto& [layer, time] : inner)
|
||||
inner_j[std::to_string(layer)] = time;
|
||||
fpt[std::to_string(fil)] = inner_j;
|
||||
@@ -250,7 +252,7 @@ inline void to_json(nlohmann::json& j, const FilamentGroupContext::SpeedInfo& si
|
||||
j["ams_preload_enabled"] = si.ams_preload_enabled;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentGroupContext::SpeedInfo& si) {
|
||||
inline void from_json(const json& j, FilamentGroupContext::SpeedInfo& si) {
|
||||
si.filament_print_time.clear();
|
||||
if (j.contains("filament_print_time")) {
|
||||
for (auto& [k, v] : j.at("filament_print_time").items()) {
|
||||
@@ -267,23 +269,23 @@ inline void from_json(const nlohmann::json& j, FilamentGroupContext::SpeedInfo&
|
||||
}
|
||||
|
||||
// ============ FilamentGroupContext::NozzleInfo ============
|
||||
inline void to_json(nlohmann::json& j, const FilamentGroupContext::NozzleInfo& ni) {
|
||||
nlohmann::json enl = nlohmann::json::object();
|
||||
inline void to_json(json& j, const FilamentGroupContext::NozzleInfo& ni) {
|
||||
json enl = json::object();
|
||||
for (auto& [ext, nozzles] : ni.extruder_nozzle_list)
|
||||
enl[std::to_string(ext)] = nozzles;
|
||||
j["extruder_nozzle_list"] = enl;
|
||||
|
||||
j["nozzle_list"] = nlohmann::json::array();
|
||||
j["nozzle_list"] = json::array();
|
||||
for (auto& n : ni.nozzle_list)
|
||||
j["nozzle_list"].push_back(n);
|
||||
|
||||
nlohmann::json ns = nlohmann::json::object();
|
||||
json ns = json::object();
|
||||
for (auto& [noz, fil] : ni.nozzle_status)
|
||||
ns[std::to_string(noz)] = fil;
|
||||
j["nozzle_status"] = ns;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentGroupContext::NozzleInfo& ni) {
|
||||
inline void from_json(const json& j, FilamentGroupContext::NozzleInfo& ni) {
|
||||
ni.extruder_nozzle_list.clear();
|
||||
for (auto& [k, v] : j.at("extruder_nozzle_list").items())
|
||||
ni.extruder_nozzle_list[std::stoi(k)] = v.get<std::vector<int>>();
|
||||
@@ -300,8 +302,8 @@ inline void from_json(const nlohmann::json& j, FilamentGroupContext::NozzleInfo&
|
||||
}
|
||||
|
||||
// ============ Full FilamentGroupContext ============
|
||||
inline void to_json(nlohmann::json& j, const FilamentGroupContext& ctx) {
|
||||
nlohmann::json mi, gi, mai, si, ni;
|
||||
inline void to_json(json& j, const FilamentGroupContext& ctx) {
|
||||
json mi, gi, mai, si, ni;
|
||||
to_json(mi, ctx.model_info);
|
||||
to_json(gi, ctx.group_info);
|
||||
to_json(mai, ctx.machine_info);
|
||||
@@ -314,7 +316,7 @@ inline void to_json(nlohmann::json& j, const FilamentGroupContext& ctx) {
|
||||
j["nozzle_info"] = ni;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FilamentGroupContext& ctx) {
|
||||
inline void from_json(const json& j, FilamentGroupContext& ctx) {
|
||||
from_json(j.at("model_info"), ctx.model_info);
|
||||
from_json(j.at("group_info"), ctx.group_info);
|
||||
from_json(j.at("machine_info"), ctx.machine_info);
|
||||
@@ -334,11 +336,11 @@ struct TestMetadata {
|
||||
int seed = 0;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& j, const TestMetadata& m) {
|
||||
j = nlohmann::json{{"id", m.id}, {"config_type", m.config_type}, {"seed", m.seed}};
|
||||
inline void to_json(json& j, const TestMetadata& m) {
|
||||
j = json{{"id", m.id}, {"config_type", m.config_type}, {"seed", m.seed}};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, TestMetadata& m) {
|
||||
inline void from_json(const json& j, TestMetadata& m) {
|
||||
j.at("id").get_to(m.id);
|
||||
j.at("config_type").get_to(m.config_type);
|
||||
j.at("seed").get_to(m.seed);
|
||||
@@ -352,8 +354,8 @@ struct TestResult {
|
||||
std::vector<std::string> violations;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& j, const TestResult& r) {
|
||||
j = nlohmann::json{
|
||||
inline void to_json(json& j, const TestResult& r) {
|
||||
j = json{
|
||||
{"filament_map", r.filament_map},
|
||||
{"flush_cost", r.flush_cost},
|
||||
{"elapsed_ms", r.elapsed_ms},
|
||||
@@ -362,7 +364,7 @@ inline void to_json(nlohmann::json& j, const TestResult& r) {
|
||||
};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, TestResult& r) {
|
||||
inline void from_json(const json& j, TestResult& r) {
|
||||
j.at("filament_map").get_to(r.filament_map);
|
||||
j.at("flush_cost").get_to(r.flush_cost);
|
||||
j.at("elapsed_ms").get_to(r.elapsed_ms);
|
||||
@@ -378,15 +380,15 @@ struct BaseResult {
|
||||
bool constraints_ok = true;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& j, const BaseResult& g) {
|
||||
j = nlohmann::json{
|
||||
inline void to_json(json& j, const BaseResult& g) {
|
||||
j = json{
|
||||
{"full_score", g.full_score},
|
||||
{"flush_cost", g.flush_cost},
|
||||
{"constraints_ok", g.constraints_ok}
|
||||
};
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& j, BaseResult& g) {
|
||||
inline void from_json(const json& j, BaseResult& g) {
|
||||
j.at("full_score").get_to(g.full_score);
|
||||
j.at("flush_cost").get_to(g.flush_cost);
|
||||
j.at("constraints_ok").get_to(g.constraints_ok);
|
||||
@@ -401,7 +403,7 @@ struct TestCase {
|
||||
|
||||
inline TestCase load_test_case(const std::string& path) {
|
||||
std::ifstream f(path);
|
||||
nlohmann::json j = nlohmann::json::parse(f);
|
||||
json j = json::parse(f);
|
||||
TestCase tc;
|
||||
tc.metadata = j.at("metadata").get<TestMetadata>();
|
||||
Slic3r::from_json(j.at("context"), tc.context);
|
||||
@@ -411,9 +413,9 @@ inline TestCase load_test_case(const std::string& path) {
|
||||
}
|
||||
|
||||
inline void save_test_case(const std::string& path, const TestCase& tc) {
|
||||
nlohmann::json j;
|
||||
json j;
|
||||
j["metadata"] = tc.metadata;
|
||||
nlohmann::json ctx_j;
|
||||
json ctx_j;
|
||||
Slic3r::to_json(ctx_j, tc.context);
|
||||
j["context"] = ctx_j;
|
||||
if (tc.base_result)
|
||||
@@ -430,14 +432,14 @@ inline void save_result(const std::string& case_path, const TestResult& result)
|
||||
else
|
||||
result_path += ".result.json";
|
||||
|
||||
nlohmann::json j = result;
|
||||
json j = result;
|
||||
std::ofstream f(result_path);
|
||||
f << j.dump(2);
|
||||
}
|
||||
|
||||
inline TestResult load_result(const std::string& result_path) {
|
||||
std::ifstream f(result_path);
|
||||
nlohmann::json j = nlohmann::json::parse(f);
|
||||
json j = json::parse(f);
|
||||
return j.get<TestResult>();
|
||||
}
|
||||
|
||||
|
||||
@@ -800,6 +800,43 @@ TEST_CASE("A per-variant filament option read with a single value gives it to ev
|
||||
REQUIRE(config.option<ConfigOptionFloats>("pressure_advance")->values == std::vector<double>({0.021, 0.021, 0.021}));
|
||||
}
|
||||
|
||||
// Machine limits (printer_options_with_variant_2) hold a (normal, silent) pair per printer variant, so the
|
||||
// printer Tab's Motion ability page can edit each extruder's own limits.
|
||||
TEST_CASE("set_num_extruders gives every printer variant its own pair of machine limits", "[Config]")
|
||||
{
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
auto speed_x = [&config]() { return config.option<ConfigOptionFloats>("machine_max_speed_x")->values; };
|
||||
|
||||
SECTION("a new extruder's pair is padded with the first value, like the other variant keys") {
|
||||
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200.};
|
||||
config.set_num_extruders(3);
|
||||
REQUIRE(config.option<ConfigOptionStrings>("printer_extruder_variant")->size() == 3);
|
||||
REQUIRE(speed_x() == std::vector<double>({500., 200., 500., 500., 500., 500.}));
|
||||
}
|
||||
|
||||
SECTION("per-extruder pairs are kept, and removing an extruder removes its pair") {
|
||||
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200., 400., 150., 300., 100.};
|
||||
config.set_num_extruders(3);
|
||||
REQUIRE(speed_x() == std::vector<double>({500., 200., 400., 150., 300., 100.}));
|
||||
config.set_num_extruders(2);
|
||||
REQUIRE(speed_x() == std::vector<double>({500., 200., 400., 150.}));
|
||||
}
|
||||
|
||||
SECTION("a printer with nozzle variants gets a pair per variant") {
|
||||
// 2 extruders x 2 variants each = 4 variants
|
||||
config.option<ConfigOptionStrings>("extruder_variant_list", true)->values = {"Direct Drive Standard,Direct Drive High Flow",
|
||||
"Direct Drive Standard,Direct Drive High Flow"};
|
||||
const std::vector<double> per_variant = {500., 200., 510., 210., 520., 220., 530., 230.};
|
||||
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = per_variant;
|
||||
config.set_num_extruders(2);
|
||||
REQUIRE(speed_x() == per_variant);
|
||||
|
||||
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200.};
|
||||
config.set_num_extruders(2);
|
||||
REQUIRE(speed_x() == std::vector<double>({500., 200., 500., 500., 500., 500., 500., 500.}));
|
||||
}
|
||||
}
|
||||
|
||||
// The device drying options hold several values per filament, as many as each filament preset gives.
|
||||
TEST_CASE("The device drying options are rebuilt as each filament's values in slot order", "[Config]")
|
||||
{
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
namespace {
|
||||
|
||||
const char *const BELOW_PAD_TEST_OBJECTS[] = {
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Line.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
void test_support_model_collision(const std::string &obj_filename,
|
||||
const sla::SupportTreeConfig &input_supportcfg,
|
||||
const sla::HollowingConfig &hollowingcfg,
|
||||
|
||||
@@ -33,31 +33,33 @@ namespace Slic3r::sla { struct PadConfig; }
|
||||
namespace Slic3r::sla { struct SupportTreeConfig; }
|
||||
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
enum e_validity {
|
||||
ASSUME_NO_EMPTY = 1,
|
||||
ASSUME_MANIFOLD = 2,
|
||||
ASSUME_NO_REPAIR = 4
|
||||
};
|
||||
|
||||
void check_validity(const Slic3r::TriangleMesh &input_mesh,
|
||||
void check_validity(const TriangleMesh &input_mesh,
|
||||
int flags = ASSUME_NO_EMPTY | ASSUME_MANIFOLD |
|
||||
ASSUME_NO_REPAIR);
|
||||
|
||||
struct PadByproducts
|
||||
{
|
||||
Slic3r::ExPolygons model_contours;
|
||||
Slic3r::ExPolygons support_contours;
|
||||
Slic3r::TriangleMesh mesh;
|
||||
ExPolygons model_contours;
|
||||
ExPolygons support_contours;
|
||||
TriangleMesh mesh;
|
||||
};
|
||||
|
||||
void test_concave_hull(const Slic3r::ExPolygons &polys);
|
||||
void test_concave_hull(const ExPolygons &polys);
|
||||
|
||||
void test_pad(const std::string & obj_filename,
|
||||
const Slic3r::sla::PadConfig &padcfg,
|
||||
const sla::PadConfig &padcfg,
|
||||
PadByproducts & out);
|
||||
|
||||
inline void test_pad(const std::string & obj_filename,
|
||||
const Slic3r::sla::PadConfig &padcfg = {})
|
||||
const sla::PadConfig &padcfg = {})
|
||||
{
|
||||
PadByproducts byproducts;
|
||||
test_pad(obj_filename, padcfg, byproducts);
|
||||
@@ -67,53 +69,53 @@ struct SupportByproducts
|
||||
{
|
||||
std::string obj_fname;
|
||||
std::vector<float> slicegrid;
|
||||
std::vector<Slic3r::ExPolygons> model_slices;
|
||||
Slic3r::sla::SupportTreeBuilder supporttree;
|
||||
Slic3r::TriangleMesh input_mesh;
|
||||
std::vector<ExPolygons> model_slices;
|
||||
sla::SupportTreeBuilder supporttree;
|
||||
TriangleMesh input_mesh;
|
||||
};
|
||||
|
||||
const constexpr float CLOSING_RADIUS = 0.005f;
|
||||
|
||||
void check_support_tree_integrity(const Slic3r::sla::SupportTreeBuilder &stree,
|
||||
const Slic3r::sla::SupportTreeConfig &cfg);
|
||||
void check_support_tree_integrity(const sla::SupportTreeBuilder &stree,
|
||||
const sla::SupportTreeConfig &cfg);
|
||||
|
||||
void test_supports(const std::string &obj_filename,
|
||||
const Slic3r::sla::SupportTreeConfig &supportcfg,
|
||||
const Slic3r::sla::HollowingConfig &hollowingcfg,
|
||||
const Slic3r::sla::DrainHoles &drainholes,
|
||||
const sla::SupportTreeConfig &supportcfg,
|
||||
const sla::HollowingConfig &hollowingcfg,
|
||||
const sla::DrainHoles &drainholes,
|
||||
SupportByproducts &out);
|
||||
|
||||
inline void test_supports(const std::string &obj_filename,
|
||||
const Slic3r::sla::SupportTreeConfig &supportcfg,
|
||||
const sla::SupportTreeConfig &supportcfg,
|
||||
SupportByproducts &out)
|
||||
{
|
||||
Slic3r::sla::HollowingConfig hcfg;
|
||||
sla::HollowingConfig hcfg;
|
||||
hcfg.enabled = false;
|
||||
test_supports(obj_filename, supportcfg, hcfg, {}, out);
|
||||
}
|
||||
|
||||
inline void test_supports(const std::string &obj_filename,
|
||||
const Slic3r::sla::SupportTreeConfig &supportcfg = {})
|
||||
const sla::SupportTreeConfig &supportcfg = {})
|
||||
{
|
||||
SupportByproducts byproducts;
|
||||
test_supports(obj_filename, supportcfg, byproducts);
|
||||
}
|
||||
|
||||
void export_failed_case(const std::vector<Slic3r::ExPolygons> &support_slices,
|
||||
void export_failed_case(const std::vector<ExPolygons> &support_slices,
|
||||
const SupportByproducts &byproducts);
|
||||
|
||||
|
||||
void test_support_model_collision(
|
||||
const std::string &obj_filename,
|
||||
const Slic3r::sla::SupportTreeConfig &input_supportcfg,
|
||||
const Slic3r::sla::HollowingConfig &hollowingcfg,
|
||||
const Slic3r::sla::DrainHoles &drainholes);
|
||||
const sla::SupportTreeConfig &input_supportcfg,
|
||||
const sla::HollowingConfig &hollowingcfg,
|
||||
const sla::DrainHoles &drainholes);
|
||||
|
||||
inline void test_support_model_collision(
|
||||
const std::string &obj_filename,
|
||||
const Slic3r::sla::SupportTreeConfig &input_supportcfg = {})
|
||||
const sla::SupportTreeConfig &input_supportcfg = {})
|
||||
{
|
||||
Slic3r::sla::HollowingConfig hcfg;
|
||||
sla::HollowingConfig hcfg;
|
||||
hcfg.enabled = false;
|
||||
test_support_model_collision(obj_filename, input_supportcfg, hcfg, {});
|
||||
}
|
||||
@@ -154,8 +156,8 @@ template <class I, class II> void test_pairhash()
|
||||
|
||||
REQUIRE(a != b);
|
||||
|
||||
II hash_ab = Slic3r::sla::pairhash<I, II>(a, b);
|
||||
II hash_ba = Slic3r::sla::pairhash<I, II>(b, a);
|
||||
II hash_ab = sla::pairhash<I, II>(a, b);
|
||||
II hash_ba = sla::pairhash<I, II>(b, a);
|
||||
REQUIRE(hash_ab == hash_ba);
|
||||
|
||||
auto it = ints.find(hash_ab);
|
||||
@@ -178,23 +180,23 @@ static constexpr const TPixel FullBlack = 0;
|
||||
|
||||
template <class A, int N> constexpr int arraysize(const A (&)[N]) { return N; }
|
||||
|
||||
void check_raster_transformations(Slic3r::sla::RasterBase::Orientation o,
|
||||
Slic3r::sla::RasterBase::TMirroring mirroring);
|
||||
void check_raster_transformations(sla::RasterBase::Orientation o,
|
||||
sla::RasterBase::TMirroring mirroring);
|
||||
|
||||
Slic3r::ExPolygon square_with_hole(double v);
|
||||
ExPolygon square_with_hole(double v);
|
||||
|
||||
inline double pixel_area(TPixel px, const Slic3r::sla::PixelDim &pxdim)
|
||||
inline double pixel_area(TPixel px, const sla::PixelDim &pxdim)
|
||||
{
|
||||
return (pxdim.h_mm * pxdim.w_mm) * px * 1. / (FullWhite - FullBlack);
|
||||
}
|
||||
|
||||
double raster_white_area(const Slic3r::sla::RasterGrayscaleAA &raster);
|
||||
long raster_pxsum(const Slic3r::sla::RasterGrayscaleAA &raster);
|
||||
double raster_white_area(const sla::RasterGrayscaleAA &raster);
|
||||
long raster_pxsum(const sla::RasterGrayscaleAA &raster);
|
||||
|
||||
double predict_error(const Slic3r::ExPolygon &p, const Slic3r::sla::PixelDim &pd);
|
||||
double predict_error(const ExPolygon &p, const sla::PixelDim &pd);
|
||||
|
||||
Slic3r::sla::SupportPoints calc_support_pts(
|
||||
const Slic3r::TriangleMesh & mesh,
|
||||
const Slic3r::sla::SupportPointGenerator::Config &cfg = {});
|
||||
sla::SupportPoints calc_support_pts(
|
||||
const TriangleMesh & mesh,
|
||||
const sla::SupportPointGenerator::Config &cfg = {});
|
||||
|
||||
#endif // SLA_TEST_UTILS_HPP
|
||||
|
||||
Reference in New Issue
Block a user