mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 10:21:00 +00:00
Merge branch 'main' into enh-update-wxwidgets
# Conflicts: # src/slic3r/GUI/AmsMappingPopup.cpp # src/slic3r/GUI/BitmapCache.cpp # src/slic3r/GUI/BitmapCache.hpp # src/slic3r/GUI/ImageGrid.cpp # src/slic3r/GUI/SelectMachine.cpp # src/slic3r/GUI/WipeTowerDialog.cpp # src/slic3r/GUI/WipeTowerDialog.hpp
This commit is contained in:
+2945
-440
File diff suppressed because it is too large
Load Diff
+40
-1
@@ -17,6 +17,44 @@ namespace IO {
|
||||
};
|
||||
}
|
||||
|
||||
#define JSON_ASSEMPLE_PLATES "plates"
|
||||
#define JSON_ASSEMPLE_PLATE_PARAMS "plate_params"
|
||||
#define JSON_ASSEMPLE_PLATE_NAME "plate_name"
|
||||
#define JSON_ASSEMPLE_PLATE_NEED_ARRANGE "need_arrange"
|
||||
#define JSON_ASSEMPLE_OBJECTS "objects"
|
||||
#define JSON_ASSEMPLE_OBJECT_PATH "path"
|
||||
#define JSON_ASSEMPLE_OBJECT_COUNT "count"
|
||||
#define JSON_ASSEMPLE_OBJECT_FILAMENTS "filaments"
|
||||
#define JSON_ASSEMPLE_OBJECT_POS_X "pos_x"
|
||||
#define JSON_ASSEMPLE_OBJECT_POS_Y "pos_y"
|
||||
#define JSON_ASSEMPLE_OBJECT_POS_Z "pos_z"
|
||||
#define JSON_ASSEMPLE_OBJECT_ASSEMBLE_INDEX "assemble_index"
|
||||
#define JSON_ASSEMPLE_OBJECT_PRINT_PARAMS "print_params"
|
||||
|
||||
|
||||
typedef struct _assemble_object_info {
|
||||
std::string path;
|
||||
int count;
|
||||
|
||||
std::vector<int> filaments;
|
||||
std::vector<int> assemble_index;
|
||||
std::vector<float> pos_x;
|
||||
std::vector<float> pos_y;
|
||||
std::vector<float> pos_z;
|
||||
std::map<std::string, std::string> print_params;
|
||||
}assemble_object_info_t;
|
||||
|
||||
typedef struct _assemble_plate_info {
|
||||
std::string plate_name;
|
||||
bool need_arrange {false};
|
||||
int filaments_count {0};
|
||||
|
||||
std::map<std::string, std::string> plate_params;
|
||||
std::vector<assemble_object_info_t> assemble_obj_list;
|
||||
std::vector<ModelObject *> loaded_obj_list;
|
||||
}assemble_plate_info_t;
|
||||
|
||||
|
||||
class CLI {
|
||||
public:
|
||||
int run(int argc, char **argv);
|
||||
@@ -41,11 +79,12 @@ private:
|
||||
bool export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, std::vector<Preset*>& project_presets,
|
||||
std::vector<ThumbnailData*>& thumbnails, std::vector<ThumbnailData*>& top_thumbnails, std::vector<ThumbnailData*>& pick_thumbnails,
|
||||
std::vector<ThumbnailData*>& calibration_thumbnails,
|
||||
std::vector<PlateBBoxData*>& plate_bboxes, const DynamicPrintConfig* config);
|
||||
std::vector<PlateBBoxData*>& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save, int plate_to_export = -1);
|
||||
|
||||
bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); }
|
||||
|
||||
std::string output_filepath(const Model &model, IO::ExportFormat format) const;
|
||||
std::string output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ typedef Eigen::Matrix<int, 3, 1, Eigen::DontAlign> stl_triangle_vertex_indices
|
||||
static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
|
||||
static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
|
||||
|
||||
typedef std::function<void(int current, int total, bool& cancel)> ImportstlProgressFn;
|
||||
typedef std::function<void(int current, int total, bool& cancel, std::string& model_id)> ImportstlProgressFn;
|
||||
|
||||
typedef enum {
|
||||
eNormal, // normal face
|
||||
@@ -157,6 +157,7 @@ struct stl_file {
|
||||
return sizeof(*this) + sizeof(stl_facet) * facet_start.size() + sizeof(stl_neighbors) * neighbors_start.size();
|
||||
}
|
||||
|
||||
char mw_data[256];
|
||||
std::vector<stl_facet> facet_start;
|
||||
std::vector<stl_neighbors> neighbors_start;
|
||||
// Statistics
|
||||
@@ -275,7 +276,6 @@ extern void stl_mirror_yz(stl_file *stl);
|
||||
extern void stl_mirror_xz(stl_file *stl);
|
||||
|
||||
extern float get_area(stl_facet* facet);
|
||||
|
||||
extern void stl_get_size(stl_file *stl);
|
||||
|
||||
// the following function is not used
|
||||
|
||||
+60
-14
@@ -44,6 +44,7 @@ extern void stl_internal_reverse_quads(char *buf, size_t cnt);
|
||||
#endif /* BOOST_ENDIAN_BIG_BYTE */
|
||||
|
||||
const int LOAD_STL_UNIT_NUM = 5;
|
||||
static std::string model_id = "";
|
||||
|
||||
static FILE* stl_open_count_facets(stl_file *stl, const char *file)
|
||||
{
|
||||
@@ -150,31 +151,66 @@ static FILE* stl_open_count_facets(stl_file *stl, const char *file)
|
||||
time running this for the stl and therefore we should reset our max and min stats. */
|
||||
static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, ImportstlProgressFn stlFn)
|
||||
{
|
||||
if (stl->stats.type == binary)
|
||||
fseek(fp, HEADER_SIZE, SEEK_SET);
|
||||
else
|
||||
rewind(fp);
|
||||
if (stl->stats.type == binary) {
|
||||
fseek(fp, HEADER_SIZE, SEEK_SET);
|
||||
}
|
||||
else {
|
||||
rewind(fp);
|
||||
try{
|
||||
char solid_name[256];
|
||||
int res_solid = fscanf(fp, " solid %[^\n]", solid_name);
|
||||
if (res_solid == 1) {
|
||||
char* mw_position = strstr(solid_name, "MW");
|
||||
if (mw_position != NULL) {
|
||||
// Extract the value after "MW"
|
||||
char version_str[16];
|
||||
char model_id_str[128];
|
||||
int num_values = sscanf(mw_position + 3, "%s %s", version_str, model_id_str);
|
||||
if (num_values == 2) {
|
||||
if (strcmp(version_str, "1.0") == 0) {
|
||||
model_id = model_id_str;
|
||||
}
|
||||
}
|
||||
else {
|
||||
model_id = "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
model_id = ""; // No MW format found
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...){
|
||||
}
|
||||
|
||||
rewind(fp);
|
||||
}
|
||||
|
||||
|
||||
char normal_buf[3][32];
|
||||
|
||||
uint32_t facets_num = stl->stats.number_of_facets;
|
||||
uint32_t unit = facets_num / LOAD_STL_UNIT_NUM + 1;
|
||||
for (uint32_t i = first_facet; i < facets_num; ++ i) {
|
||||
if ((i % unit) == 0) {
|
||||
bool cb_cancel = false;
|
||||
if (stlFn) {
|
||||
stlFn(i, facets_num, cb_cancel);
|
||||
if (cb_cancel)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((i % unit) == 0) {
|
||||
bool cb_cancel = false;
|
||||
if (stlFn) {
|
||||
stlFn(i, facets_num, cb_cancel, model_id);
|
||||
if (cb_cancel)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stl_facet facet;
|
||||
|
||||
if (stl->stats.type == binary) {
|
||||
|
||||
|
||||
// Read a single facet from a binary .STL file. We assume little-endian architecture!
|
||||
if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET)
|
||||
return false;
|
||||
|
||||
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
// Convert the loaded little endian data to big endian.
|
||||
stl_internal_reverse_quads((char*)&facet, 48);
|
||||
@@ -237,11 +273,21 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, Impor
|
||||
}
|
||||
#endif
|
||||
|
||||
// Write the facet into memory.
|
||||
// Write the facet into memory if none of facet vertices is NAN.
|
||||
bool someone_is_nan = false;
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
if (isnan(facet.vertex[j](0)) || isnan(facet.vertex[j](1)) || isnan(facet.vertex[j](2))) {
|
||||
someone_is_nan = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(someone_is_nan)
|
||||
continue;
|
||||
|
||||
stl->facet_start[i] = facet;
|
||||
stl_facet_stats(stl, facet, first);
|
||||
}
|
||||
|
||||
|
||||
stl->stats.size = stl->stats.max - stl->stats.min;
|
||||
stl->stats.bounding_diameter = stl->stats.size.norm();
|
||||
return true;
|
||||
|
||||
@@ -172,6 +172,7 @@ namespace ImGui
|
||||
const wchar_t UnfoldButtonIcon = 0x0815;
|
||||
const wchar_t SphereButtonIcon = 0x0816;
|
||||
const wchar_t GapFillIcon = 0x0817;
|
||||
const wchar_t ConfirmIcon = 0x0818;
|
||||
|
||||
const wchar_t MinimalizeDarkButton = 0x081C;
|
||||
const wchar_t MinimalizeHoverDarkButton = 0x081D;
|
||||
@@ -186,6 +187,7 @@ namespace ImGui
|
||||
const wchar_t HeightRangeDarkIcon = 0x0825;
|
||||
const wchar_t SphereButtonDarkIcon = 0x0826;
|
||||
const wchar_t GapFillDarkIcon = 0x0827;
|
||||
const wchar_t ConfirmDarkIcon = 0x0828;
|
||||
|
||||
const wchar_t TextSearchIcon = 0x0828;
|
||||
const wchar_t TextSearchCloseIcon = 0x0829;
|
||||
@@ -199,6 +201,15 @@ namespace ImGui
|
||||
const wchar_t BlockNotifErrorIcon = 0x0835;
|
||||
const wchar_t ClipboardBtnDarkIcon = 0x0836;
|
||||
|
||||
const wchar_t PrevArrowBtnIcon = 0x0836;
|
||||
const wchar_t PrevArrowHoverBtnIcon = 0x0837;
|
||||
const wchar_t NextArrowBtnIcon = 0x0838;
|
||||
const wchar_t NextArrowHoverBtnIcon = 0x0839;
|
||||
const wchar_t OpenArrowIcon = 0x0840;
|
||||
const wchar_t CollapseArrowIcon = 0x0841;
|
||||
const wchar_t ExpandArrowIcon = 0x0842;
|
||||
const wchar_t CompleteIcon = 0x0843;
|
||||
|
||||
// void MyFunction(const char* name, const MyMatrix44& v);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Index of this file:
|
||||
#include "imgui_internal.h"
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include <algorithm>
|
||||
// System includes
|
||||
#include <ctype.h> // toupper
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
@@ -3070,6 +3070,9 @@ bool ImGui::BBLDragFloat(const char *label, float *v, float v_speed, float v_min
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.00f, 0.59f, 0.53f, 0.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.00f, 0.59f, 0.53f, 0.00f));
|
||||
bool bbl_drag_scalar = BBLDragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags);
|
||||
if (v_max > v_min + 0.001) {
|
||||
*v = std::clamp(*v, v_min, v_max);
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
return bbl_drag_scalar;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
#ifndef ASTAR_HPP
|
||||
#define ASTAR_HPP
|
||||
|
||||
#include <cmath> // std::isinf() is here
|
||||
#include <unordered_map>
|
||||
|
||||
#include "libslic3r/MutablePriorityQueue.hpp"
|
||||
|
||||
namespace Slic3r { namespace astar {
|
||||
|
||||
// Borrowed from C++20
|
||||
template<class T> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
// Input interface for the Astar algorithm. Specialize this struct for a
|
||||
// particular type and implement all the 4 methods and specify the Node type
|
||||
// to register the new type for the astar implementation.
|
||||
template<class T> struct TracerTraits_
|
||||
{
|
||||
// The type of a node used by this tracer. Usually a point in space.
|
||||
using Node = typename T::Node;
|
||||
|
||||
// Call fn for every new node reachable from node 'src'. fn should have the
|
||||
// candidate node as its only argument.
|
||||
template<class Fn> static void foreach_reachable(const T &tracer, const Node &src, Fn &&fn) { tracer.foreach_reachable(src, fn); }
|
||||
|
||||
// Get the distance from node 'a' to node 'b'. This is sometimes referred
|
||||
// to as the g value of a node in AStar context.
|
||||
static float distance(const T &tracer, const Node &a, const Node &b) { return tracer.distance(a, b); }
|
||||
|
||||
// Get the estimated distance heuristic from node 'n' to the destination.
|
||||
// This is referred to as the h value in AStar context.
|
||||
// If node 'n' is the goal, this function should return a negative value.
|
||||
// Note that this heuristic should be admissible (never bigger than the real
|
||||
// cost) in order for Astar to work.
|
||||
static float goal_heuristic(const T &tracer, const Node &n) { return tracer.goal_heuristic(n); }
|
||||
|
||||
// Return a unique identifier (hash) for node 'n'.
|
||||
static size_t unique_id(const T &tracer, const Node &n) { return tracer.unique_id(n); }
|
||||
};
|
||||
|
||||
// Helper definition to get the node type of a tracer
|
||||
template<class T> using TracerNodeT = typename TracerTraits_<remove_cvref_t<T>>::Node;
|
||||
|
||||
constexpr auto Unassigned = std::numeric_limits<size_t>::max();
|
||||
|
||||
template<class Tracer> struct QNode // Queue node. Keeps track of scores g, and h
|
||||
{
|
||||
TracerNodeT<Tracer> node; // The actual node itself
|
||||
size_t queue_id; // Position in the open queue or Unassigned if closed
|
||||
size_t parent; // unique id of the parent or Unassigned
|
||||
|
||||
float g, h;
|
||||
float f() const { return g + h; }
|
||||
|
||||
QNode(TracerNodeT<Tracer> n = {}, size_t p = Unassigned, float gval = std::numeric_limits<float>::infinity(), float hval = 0.f)
|
||||
: node{std::move(n)}, parent{p}, queue_id{InvalidQueueID}, g{gval}, h{hval}
|
||||
{}
|
||||
};
|
||||
|
||||
// Run the AStar algorithm on a tracer implementation.
|
||||
// The 'tracer' argument encapsulates the domain (grid, point cloud, etc...)
|
||||
// The 'source' argument is the starting node.
|
||||
// The 'out' argument is the output iterator into which the output nodes are
|
||||
// written. For performance reasons, the order is reverse, from the destination
|
||||
// to the source -- (destination included, source is not).
|
||||
// The 'cached_nodes' argument is an optional associative container to hold a
|
||||
// QNode entry for each visited node. Any compatible container can be used
|
||||
// (like std::map or maps with different allocators, even a sufficiently large
|
||||
// std::vector).
|
||||
//
|
||||
// Note that no destination node is given in the signature. The tracer's
|
||||
// goal_heuristic() method should return a negative value if a node is a
|
||||
// destination node.
|
||||
template<class Tracer, class It, class NodeMap = std::unordered_map<size_t, QNode<Tracer>>>
|
||||
bool search_route(const Tracer &tracer, const TracerNodeT<Tracer> &source, It out, NodeMap &&cached_nodes = {})
|
||||
{
|
||||
using Node = TracerNodeT<Tracer>;
|
||||
using QNode = QNode<Tracer>;
|
||||
using TracerTraits = TracerTraits_<remove_cvref_t<Tracer>>;
|
||||
|
||||
struct LessPred
|
||||
{ // Comparison functor needed by the priority queue
|
||||
NodeMap &m;
|
||||
bool operator()(size_t node_a, size_t node_b) { return m[node_a].f() < m[node_b].f(); }
|
||||
};
|
||||
|
||||
auto qopen = make_mutable_priority_queue<size_t, true>([&cached_nodes](size_t el, size_t qidx) { cached_nodes[el].queue_id = qidx; }, LessPred{cached_nodes});
|
||||
|
||||
QNode initial{source, /*parent = */ Unassigned, /*g = */ 0.f};
|
||||
size_t source_id = TracerTraits::unique_id(tracer, source);
|
||||
cached_nodes[source_id] = initial;
|
||||
qopen.push(source_id);
|
||||
|
||||
size_t goal_id = TracerTraits::goal_heuristic(tracer, source) < 0.f ? source_id : Unassigned;
|
||||
|
||||
while (goal_id == Unassigned && !qopen.empty()) {
|
||||
size_t q_id = qopen.top();
|
||||
qopen.pop();
|
||||
QNode &q = cached_nodes[q_id];
|
||||
|
||||
// This should absolutely be initialized in the cache already
|
||||
assert(!std::isinf(q.g));
|
||||
|
||||
TracerTraits::foreach_reachable(tracer, q.node, [&](const Node &succ_nd) {
|
||||
if (goal_id != Unassigned) return true;
|
||||
|
||||
float h = TracerTraits::goal_heuristic(tracer, succ_nd);
|
||||
float dst = TracerTraits::distance(tracer, q.node, succ_nd);
|
||||
size_t succ_id = TracerTraits::unique_id(tracer, succ_nd);
|
||||
QNode qsucc_nd{succ_nd, q_id, q.g + dst, h};
|
||||
|
||||
if (h < 0.f) {
|
||||
goal_id = succ_id;
|
||||
cached_nodes[succ_id] = qsucc_nd;
|
||||
} else {
|
||||
// If succ_id is not in cache, it gets created with g = infinity
|
||||
QNode &prev_nd = cached_nodes[succ_id];
|
||||
|
||||
if (qsucc_nd.g < prev_nd.g) {
|
||||
// new route is better, apply it:
|
||||
|
||||
// Save the old queue id, it would be lost after the next line
|
||||
size_t queue_id = prev_nd.queue_id;
|
||||
|
||||
// The cache needs to be updated either way
|
||||
prev_nd = qsucc_nd;
|
||||
|
||||
if (queue_id == InvalidQueueID)
|
||||
// was in closed or unqueued, rescheduling
|
||||
qopen.push(succ_id);
|
||||
else // was in open, updating
|
||||
qopen.update(queue_id);
|
||||
}
|
||||
}
|
||||
|
||||
return goal_id != Unassigned;
|
||||
});
|
||||
}
|
||||
|
||||
// Write the output, do not reverse. Clients can do so if they need to.
|
||||
if (goal_id != Unassigned) {
|
||||
const QNode *q = &cached_nodes[goal_id];
|
||||
while (q->parent != Unassigned) {
|
||||
assert(!std::isinf(q->g)); // Uninitialized nodes are NOT allowed
|
||||
|
||||
*out = q->node;
|
||||
++out;
|
||||
q = &cached_nodes[q->parent];
|
||||
}
|
||||
}
|
||||
|
||||
return goal_id != Unassigned;
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::astar
|
||||
|
||||
#endif // ASTAR_HPP
|
||||
@@ -255,6 +255,10 @@ void AppConfig::set_defaults()
|
||||
if (get("show_daily_tips").empty()) {
|
||||
set_bool("show_daily_tips", true);
|
||||
}
|
||||
//true is auto calculate
|
||||
if (get("auto_calculate").empty()) {
|
||||
set_bool("auto_calculate", true);
|
||||
}
|
||||
|
||||
if (get("show_home_page").empty()) {
|
||||
set_bool("show_home_page", true);
|
||||
@@ -998,7 +1002,7 @@ void AppConfig::set_vendors(const AppConfig &from)
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void AppConfig::save_printer_cali_infos(const PrinterCaliInfo &cali_info)
|
||||
void AppConfig::save_printer_cali_infos(const PrinterCaliInfo &cali_info, bool need_change_status)
|
||||
{
|
||||
auto iter = std::find_if(m_printer_cali_infos.begin(), m_printer_cali_infos.end(), [&cali_info](const PrinterCaliInfo &cali_info_item) {
|
||||
return cali_info_item.dev_id == cali_info.dev_id;
|
||||
@@ -1007,7 +1011,9 @@ void AppConfig::save_printer_cali_infos(const PrinterCaliInfo &cali_info)
|
||||
if (iter == m_printer_cali_infos.end()) {
|
||||
m_printer_cali_infos.emplace_back(cali_info);
|
||||
} else {
|
||||
(*iter).cali_finished = cali_info.cali_finished;
|
||||
if (need_change_status) {
|
||||
(*iter).cali_finished = cali_info.cali_finished;
|
||||
}
|
||||
(*iter).cache_flow_ratio = cali_info.cache_flow_ratio;
|
||||
(*iter).selected_presets = cali_info.selected_presets;
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ public:
|
||||
}
|
||||
|
||||
const std::vector<PrinterCaliInfo> &get_printer_cali_infos() const { return m_printer_cali_infos; }
|
||||
void save_printer_cali_infos(const PrinterCaliInfo& cali_info);
|
||||
void save_printer_cali_infos(const PrinterCaliInfo& cali_info, bool need_change_status = true);
|
||||
|
||||
// return recent/last_opened_folder or recent/settings_folder or empty string.
|
||||
std::string get_last_dir() const;
|
||||
|
||||
@@ -228,16 +228,23 @@ void update_selected_items_axis_align(ArrangePolygons& selected, const DynamicPr
|
||||
double c = m02 / m00 - cy * cy;
|
||||
|
||||
//if a and c are close, there is no dominant axis, then do not rotate
|
||||
if (std::abs(a) < 1.5*std::abs(c) && std::abs(c) < 1.5*std::abs(a)) {
|
||||
// ratio is always no more than 1
|
||||
double ratio = std::abs(a) > std::abs(c) ? std::abs(c / a) :
|
||||
std::abs(c) > 0 ? std::abs(a / c) : 0;
|
||||
if (ratio>0.66) {
|
||||
validResult = false;
|
||||
}
|
||||
else {
|
||||
angle = std::atan2(2 * b, (a - c)) / 2;
|
||||
angle = PI / 2 - angle;
|
||||
// if the angle is close to PI or -PI, it means the object is vertical, then do not rotate
|
||||
if (std::abs(std::abs(angle) - PI) < 0.01)
|
||||
angle = 0;
|
||||
validResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (validResult) { ap.rotation += (PI / 2 - angle); }
|
||||
if (validResult) { ap.rotation += angle; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +413,18 @@ protected:
|
||||
return bindist;
|
||||
}
|
||||
|
||||
double dist_to_bin(const Box& ibb, const ClipperLib::IntPoint& origin_pack, typename Packer::PlacementConfig::Alignment starting_point_alignment)
|
||||
{
|
||||
double bindist = 0;
|
||||
if (starting_point_alignment == PConfig::Alignment::BOTTOM_LEFT)
|
||||
bindist = norm(pl::distance(ibb.minCorner(), origin_pack));
|
||||
else if (starting_point_alignment == PConfig::Alignment::TOP_RIGHT)
|
||||
bindist = norm(pl::distance(ibb.maxCorner(), origin_pack));
|
||||
else
|
||||
bindist = norm(pl::distance(ibb.center(), origin_pack));
|
||||
return bindist;
|
||||
}
|
||||
|
||||
// This is "the" object function which is evaluated many times for each
|
||||
// vertex (decimated with the accuracy parameter) of each object.
|
||||
// Therefore it is upmost crucial for this function to be as efficient
|
||||
@@ -488,7 +507,7 @@ protected:
|
||||
score = 0.2 * dist + 0.8 * bindist;
|
||||
}
|
||||
else {
|
||||
double bindist = norm(pl::distance(ibb.center(), origin_pack));
|
||||
double bindist = dist_to_bin(ibb, origin_pack, m_pconf.starting_point);
|
||||
dist = 0.8 * dist + 0.2 * bindist;
|
||||
|
||||
|
||||
@@ -520,11 +539,13 @@ protected:
|
||||
auto ascore = 1.0 - (item.area() + parea) / bbarea;
|
||||
|
||||
if (ascore < alignment_score) alignment_score = ascore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
density = std::sqrt(norm(fullbb.width()) * norm(fullbb.height()));
|
||||
double R = double(m_remaining.size()) / m_item_count;
|
||||
// alighment score is more important for rectangle items
|
||||
double alignment_weight = std::max(0.3, 0.6 * item.area() / ibb.area());
|
||||
|
||||
// The final mix of the score is the balance between the
|
||||
// distance from the full pile center, the pack density and
|
||||
@@ -533,8 +554,8 @@ protected:
|
||||
score = 0.50 * dist + 0.50 * density;
|
||||
else
|
||||
// Let the density matter more when fewer objects remain
|
||||
score = 0.50 * dist + (1.0 - R) * 0.20 * density +
|
||||
0.30 * alignment_score;
|
||||
score = (1 - 0.2 - alignment_weight) * dist + (1.0 - R) * 0.20 * density +
|
||||
alignment_weight * alignment_score;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -814,7 +835,8 @@ public:
|
||||
|
||||
template<> std::function<double(const Item&, const ItemGroup&)> AutoArranger<Box>::get_objfn()
|
||||
{
|
||||
auto origin_pack = m_pconf.starting_point == PConfig::Alignment::CENTER ? m_bin.center() : m_bin.minCorner();
|
||||
auto origin_pack = m_pconf.starting_point == PConfig::Alignment::CENTER ? m_bin.center() :
|
||||
m_pconf.starting_point == PConfig::Alignment::TOP_RIGHT ? m_bin.maxCorner() : m_bin.minCorner();
|
||||
|
||||
return [this, origin_pack](const Item &itm, const ItemGroup&) {
|
||||
auto result = objfunc(itm, origin_pack);
|
||||
|
||||
@@ -419,4 +419,15 @@ std::string_view BuildVolume::type_name(BuildVolume_Type type)
|
||||
return {};
|
||||
}
|
||||
|
||||
indexed_triangle_set BuildVolume::bounding_mesh(bool scale) const
|
||||
{
|
||||
auto max_pt3 = m_bboxf.max;
|
||||
if (scale) {
|
||||
return its_make_cube(scale_(max_pt3.x()), scale_(max_pt3.y()), scale_(max_pt3.z()));
|
||||
}
|
||||
else {
|
||||
return its_make_cube(max_pt3.x(), max_pt3.y(), max_pt3.z());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -52,6 +52,7 @@ public:
|
||||
// Bounding volume of printable_area(), printable_height(), unscaled.
|
||||
const BoundingBoxf3& bounding_volume() const { return m_bboxf; }
|
||||
BoundingBoxf bounding_volume2d() const { return { to_2d(m_bboxf.min), to_2d(m_bboxf.max) }; }
|
||||
indexed_triangle_set bounding_mesh(bool scale=true) const;
|
||||
|
||||
// Center of the print bed, unscaled.
|
||||
Vec2d bed_center() const { return to_2d(m_bboxf.center()); }
|
||||
|
||||
@@ -304,7 +304,7 @@ set(lisbslic3r_sources
|
||||
PrincipalComponents2D.hpp
|
||||
SupportSpotsGenerator.cpp
|
||||
SupportSpotsGenerator.hpp
|
||||
TreeSupport.hpp
|
||||
TreeSupport.hpp
|
||||
TreeSupport.cpp
|
||||
MinimumSpanningTree.hpp
|
||||
MinimumSpanningTree.cpp
|
||||
|
||||
@@ -308,6 +308,7 @@ ConfigOption* ConfigOptionDef::create_default_option() const
|
||||
opt->keys_map = this->enum_keys_map;
|
||||
return opt;
|
||||
}
|
||||
delete dft;
|
||||
}
|
||||
|
||||
return this->default_value->clone();
|
||||
@@ -782,6 +783,8 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
|
||||
json j;
|
||||
std::list<std::string> different_settings_append;
|
||||
std::string new_support_style;
|
||||
std::string is_infill_first;
|
||||
std::string get_wall_sequence;
|
||||
bool is_project_settings = false;
|
||||
|
||||
CNumericLocalesSetter locales_setter;
|
||||
@@ -845,6 +848,16 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
|
||||
different_settings_append.push_back("support_style");
|
||||
new_support_style = "tree_hybrid";
|
||||
}
|
||||
} else if (opt_key == "wall_infill_order") {
|
||||
//BBS: check wall_infill order to decide if it be different and append to diff_setting_append
|
||||
if (it.value() == "outer wall/inner wall/infill" || it.value() == "infill/outer wall/inner wall" || it.value() == "inner-outer-inner wall/infill") {
|
||||
get_wall_sequence = "wall_seq_diff_to_system";
|
||||
}
|
||||
|
||||
if (it.value() == "infill/outer wall/inner wall" || it.value() == "infill/inner wall/outer wall") {
|
||||
different_settings_append.push_back("is_infill_first");
|
||||
is_infill_first = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (it.value().is_array()) {
|
||||
@@ -916,6 +929,12 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
|
||||
ConfigOptionEnum<SupportMaterialStyle>* opt = this->option<ConfigOptionEnum<SupportMaterialStyle>>("support_style", true);
|
||||
opt->value = smsTreeHybrid;
|
||||
}
|
||||
|
||||
if (!is_infill_first.empty()) {
|
||||
ConfigOptionBool *opt = this->option<ConfigOptionBool>("is_infill_first", true);
|
||||
opt->value = true;
|
||||
}
|
||||
|
||||
if (is_project_settings) {
|
||||
std::vector<std::string>& different_settings = this->option<ConfigOptionStrings>("different_settings_to_system", true)->values;
|
||||
size_t size = different_settings.size();
|
||||
@@ -932,6 +951,25 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
|
||||
is_first[index] = true;
|
||||
}
|
||||
else {
|
||||
// remove unneeded key
|
||||
if (get_wall_sequence.empty()) {
|
||||
std::string wall_sqe_string = "wall_sequence";
|
||||
int pos=different_settings[index].find(wall_sqe_string);
|
||||
|
||||
if (pos != different_settings[index].npos) {
|
||||
int erase_len = wall_sqe_string.size();
|
||||
if (pos + erase_len < different_settings[index].size() && different_settings[index][pos + erase_len] == ';')
|
||||
erase_len++;
|
||||
different_settings[index].erase(pos, erase_len);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (different_settings[index].empty()) {
|
||||
is_first[index] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
Slic3r::unescape_strings_cstyle(different_settings[index], original_diffs[index]);
|
||||
}
|
||||
}
|
||||
@@ -945,6 +983,8 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
|
||||
index = 0;
|
||||
else if (diff_key == "support_style")
|
||||
index = 0;
|
||||
else if (diff_key == "is_infill_first")
|
||||
index = 0;
|
||||
|
||||
//check whether exist firstly
|
||||
if (!original_diffs[index].empty()) {
|
||||
|
||||
@@ -445,6 +445,11 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
|
||||
ModelObject* lower{ nullptr };
|
||||
if (m_attributes.has(ModelObjectCutAttribute::KeepLower)) cut_mo->clone_for_cut(&lower);
|
||||
|
||||
if (upper && lower) {
|
||||
upper->name = upper->name + "_A";
|
||||
lower->name = lower->name + "_B";
|
||||
}
|
||||
|
||||
const size_t cut_parts_cnt = parts.size();
|
||||
bool has_modifiers = false;
|
||||
|
||||
@@ -527,6 +532,10 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
|
||||
ModelObject* lower{ nullptr };
|
||||
cut_mo->clone_for_cut(&lower);
|
||||
|
||||
if (upper && lower) {
|
||||
upper->name = upper->name + "_A";
|
||||
lower->name = lower->name + "_B";
|
||||
}
|
||||
const double groove_half_depth = 0.5 * double(groove.depth);
|
||||
|
||||
Model tmp_model_for_cut = Model();
|
||||
|
||||
@@ -26,6 +26,7 @@ ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths
|
||||
|
||||
ExtrusionEntityCollection& ExtrusionEntityCollection::operator=(const ExtrusionEntityCollection &other)
|
||||
{
|
||||
clear();
|
||||
this->entities = other.entities;
|
||||
for (size_t i = 0; i < this->entities.size(); ++i)
|
||||
this->entities[i] = this->entities[i]->clone();
|
||||
|
||||
@@ -1095,7 +1095,7 @@ void Layer::make_ironing()
|
||||
|
||||
// Create the filler object.
|
||||
f->spacing = ironing_params.line_spacing;
|
||||
f->angle = float(ironing_params.angle + 0.25 * M_PI);
|
||||
f->angle = float(ironing_params.angle);
|
||||
f->link_max_length = (coord_t) scale_(3. * f->spacing);
|
||||
double extrusion_height = ironing_params.height * f->spacing / nozzle_dmr;
|
||||
float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height));
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Slic3r {
|
||||
bool load_stl(const char *path, Model *model, const char *object_name_in, ImportstlProgressFn stlFn)
|
||||
{
|
||||
TriangleMesh mesh;
|
||||
std::string design_id;
|
||||
|
||||
if (! mesh.ReadSTLFile(path, true, stlFn)) {
|
||||
// die "Failed to open $file\n" if !-e $path;
|
||||
return false;
|
||||
@@ -59,4 +61,4 @@ bool store_stl(const char *path, Model *model, bool binary)
|
||||
return store_stl(path, &mesh, binary);
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
}; // namespace Slic3r
|
||||
@@ -276,6 +276,7 @@ static constexpr const char* LOCK_ATTR = "locked";
|
||||
static constexpr const char* BED_TYPE_ATTR = "bed_type";
|
||||
static constexpr const char* PRINT_SEQUENCE_ATTR = "print_sequence";
|
||||
static constexpr const char* FIRST_LAYER_PRINT_SEQUENCE_ATTR = "first_layer_print_sequence";
|
||||
static constexpr const char* SPIRAL_VASE_MODE = "spiral_mode";
|
||||
static constexpr const char* GCODE_FILE_ATTR = "gcode_file";
|
||||
static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file";
|
||||
static constexpr const char* TOP_FILE_ATTR = "top_file";
|
||||
@@ -288,6 +289,8 @@ static constexpr const char* IDENTIFYID_ATTR = "identify_id";
|
||||
static constexpr const char* PLATERID_ATTR = "plater_id";
|
||||
static constexpr const char* PLATER_NAME_ATTR = "plater_name";
|
||||
static constexpr const char* PLATE_IDX_ATTR = "index";
|
||||
static constexpr const char* PRINTER_MODEL_ID_ATTR = "printer_model_id";
|
||||
static constexpr const char* NOZZLE_DIAMETERS_ATTR = "nozzle_diameters";
|
||||
static constexpr const char* SLICE_PREDICTION_ATTR = "prediction";
|
||||
static constexpr const char* SLICE_WEIGHT_ATTR = "weight";
|
||||
static constexpr const char* TIMELAPSE_TYPE_ATTR = "timelapse_type";
|
||||
@@ -1282,9 +1285,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
// BBS: load relationships
|
||||
if (!_extract_xml_from_archive(archive, RELATIONSHIPS_FILE, _handle_start_relationships_element, _handle_end_relationships_element))
|
||||
return false;
|
||||
if (m_thumbnail_small.empty()) m_thumbnail_small = m_thumbnail_path;
|
||||
if (!m_thumbnail_small.empty()) {
|
||||
return _extract_from_archive(archive, m_thumbnail_small, [&data](auto &archive, auto const &stat) -> bool {
|
||||
if (m_thumbnail_middle.empty()) m_thumbnail_middle = m_thumbnail_path;
|
||||
if (!m_thumbnail_middle.empty()) {
|
||||
return _extract_from_archive(archive, m_thumbnail_middle, [&data](auto &archive, auto const &stat) -> bool {
|
||||
data.resize(stat.m_uncomp_size);
|
||||
return mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, data.data(), data.size(), 0);
|
||||
});
|
||||
@@ -1368,7 +1371,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
m_thumbnail_small.erase(m_thumbnail_small.begin());
|
||||
if (!m_thumbnail_middle.empty() && m_thumbnail_middle.front() == '/')
|
||||
m_thumbnail_middle.erase(m_thumbnail_middle.begin());
|
||||
m_model->model_info->metadata_items.emplace("Thumbnail", m_thumbnail_small);
|
||||
m_model->model_info->metadata_items.emplace("Thumbnail", m_thumbnail_middle);
|
||||
m_model->model_info->metadata_items.emplace("Poster", m_thumbnail_middle);
|
||||
|
||||
// we then loop again the entries to read other files stored in the archive
|
||||
@@ -3900,6 +3903,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
};
|
||||
m_curr_plater->config.set_key_value("first_layer_print_sequence", new ConfigOptionInts(get_vector_from_string(value)));
|
||||
}
|
||||
else if (key == SPIRAL_VASE_MODE) {
|
||||
bool spiral_mode = false;
|
||||
std::istringstream(value) >> std::boolalpha >> spiral_mode;
|
||||
m_curr_plater->config.set_key_value("spiral_mode", new ConfigOptionBool(spiral_mode));
|
||||
}
|
||||
else if (key == GCODE_FILE_ATTR)
|
||||
{
|
||||
m_curr_plater->gcode_file = value;
|
||||
@@ -5375,7 +5383,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
~close_lock() {
|
||||
if (filename) {
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(*filename);
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(*filename, ec);
|
||||
}
|
||||
}
|
||||
} lock{archive, &filepath_tmp};
|
||||
@@ -5439,8 +5448,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
std::string const * filename;
|
||||
~close_lock() {
|
||||
close_zip_writer(&archive);
|
||||
if (filename)
|
||||
boost::filesystem::remove(*filename);
|
||||
if (filename) {
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(*filename, ec);
|
||||
}
|
||||
}
|
||||
} lock{ archive, &filename};
|
||||
|
||||
@@ -5588,7 +5599,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
{
|
||||
if (!_add_calibration_file_to_archive(archive, *calibration_data[index], index)) {
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -5604,7 +5614,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
if (id_bboxes[index]->is_valid()) {
|
||||
if (!_add_bbox_file_to_archive(archive, *id_bboxes[index], index)) {
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -5631,7 +5640,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
||||
if (!_add_layer_height_profile_file_to_archive(archive, model)) {
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5648,7 +5656,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
||||
if (!_add_layer_config_ranges_file_to_archive(archive, model)) {
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6417,7 +6424,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
stream << " <" << COMPONENT_TAG << " objectid=\"" << volume_id;
|
||||
else
|
||||
stream << " <" << COMPONENT_TAG << " p:path=\"" << xml_escape(*ppath) << "\" objectid=\"" << volume_id; // << "\"/>\n";
|
||||
stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) object_data.backup_id} << COMPONENT_UUID_SUFFIX;
|
||||
if (m_production_ext)
|
||||
stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) (index + (object_data.backup_id << 16))} << COMPONENT_UUID_SUFFIX;
|
||||
const Transform3d &transf = volume->get_matrix();
|
||||
stream << "\" " << TRANSFORM_ATTR << "=\"";
|
||||
for (unsigned c = 0; c < 4; ++c) {
|
||||
@@ -6515,7 +6523,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
char buf[256];
|
||||
unsigned int vertices_count = 0;
|
||||
//unsigned int triangles_count = 0;
|
||||
for (ModelVolume* volume : object.volumes) {
|
||||
for (unsigned int index = 0; index < object.volumes.size(); index++) {
|
||||
ModelVolume *volume = object.volumes[index];
|
||||
if (volume == nullptr)
|
||||
continue;
|
||||
|
||||
@@ -6542,7 +6551,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
if (m_production_ext) {
|
||||
std::stringstream stream;
|
||||
reset_stream(stream);
|
||||
stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) object_data.backup_id} << SUB_OBJECT_UUID_SUFFIX;
|
||||
stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) (index + (object_data.backup_id << 16))} << SUB_OBJECT_UUID_SUFFIX;
|
||||
//output_buffer += "\" ";
|
||||
//output_buffer += PUUID_ATTR;
|
||||
//output_buffer += "=\"";
|
||||
@@ -7218,6 +7227,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
stream << "\"/>\n";
|
||||
}
|
||||
|
||||
ConfigOption* spiral_mode_opt = plate_data->config.option("spiral_mode");
|
||||
if (spiral_mode_opt)
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SPIRAL_VASE_MODE << "\" " << VALUE_ATTR << "=\"" << spiral_mode_opt->getBool() << "\"/>\n";
|
||||
|
||||
if (save_gcode)
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << GCODE_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << xml_escape(plate_data->gcode_file) << "\"/>\n";
|
||||
if (!plate_data->gcode_file.empty()) {
|
||||
@@ -7371,6 +7384,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PRINTER_MODEL_ID_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->printer_model_id << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << NOZZLE_DIAMETERS_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->nozzle_diameters << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_TYPE_ATTR << "\" " << VALUE_ATTR << "=\"" << timelapse_type << "\"/>\n";
|
||||
//stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_ERROR_CODE_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->timelapse_warning_code << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_PREDICTION_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_prediction_str() << "\"/>\n";
|
||||
@@ -7714,10 +7729,12 @@ public:
|
||||
|
||||
void set_interval(long n) {
|
||||
boost::lock_guard lock(m_mutex);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry, and last interval is: " << m_interval;
|
||||
m_next_backup -= boost::posix_time::seconds(m_interval);
|
||||
m_interval = n;
|
||||
m_next_backup += boost::posix_time::seconds(m_interval);
|
||||
m_cond.notify_all();
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " exit, and new interval is: " << m_interval;
|
||||
}
|
||||
|
||||
void put_other_changes()
|
||||
@@ -7795,6 +7812,7 @@ private:
|
||||
};
|
||||
private:
|
||||
_BBS_Backup_Manager() {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " inital and interval = " << m_interval;
|
||||
m_next_backup = boost::get_system_time() + boost::posix_time::seconds(m_interval);
|
||||
boost::unique_lock lock(m_mutex);
|
||||
m_thread = std::move(boost::thread(boost::ref(*this)));
|
||||
@@ -7823,7 +7841,7 @@ private:
|
||||
}
|
||||
|
||||
void process_ui_task(Task& t, bool canceled = false) {
|
||||
BOOST_LOG_TRIVIAL(info) << "process_ui_task" << t.to_string();
|
||||
BOOST_LOG_TRIVIAL(info) << "process_ui_task" << t.to_string() << " and interval = " << m_interval;
|
||||
switch (t.type) {
|
||||
case Backup: {
|
||||
if (canceled)
|
||||
@@ -7867,7 +7885,7 @@ private:
|
||||
}
|
||||
|
||||
void process_task(Task& t) {
|
||||
BOOST_LOG_TRIVIAL(info) << "process_task" << t.to_string();
|
||||
BOOST_LOG_TRIVIAL(info) << "process_task" << t.to_string() << " and interval = " << m_interval;
|
||||
switch (t.type) {
|
||||
case Backup:
|
||||
// do it in response
|
||||
@@ -7882,13 +7900,15 @@ private:
|
||||
break;
|
||||
}
|
||||
case RemoveObject: {
|
||||
boost::filesystem::remove(t.path + "/mesh_" + boost::lexical_cast<std::string>(t.id) + ".xml");
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(t.path + "/mesh_" + boost::lexical_cast<std::string>(t.id) + ".xml", ec);
|
||||
t.type = None;
|
||||
break;
|
||||
}
|
||||
case RemoveBackup: {
|
||||
try {
|
||||
boost::filesystem::remove(t.path + "/.3mf");
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(t.path + "/.3mf", ec);
|
||||
// We Saved with SplitModel now, so we can safe delete these sub models.
|
||||
boost::filesystem::remove_all(t.path + "/3D/Objects");
|
||||
boost::filesystem::create_directory(t.path + "/3D/Objects");
|
||||
|
||||
@@ -69,6 +69,8 @@ struct PlateData
|
||||
int plate_index;
|
||||
std::vector<std::pair<int, int>> objects_and_instances;
|
||||
std::map<int, std::pair<int, int>> obj_inst_map;
|
||||
std::string printer_model_id;
|
||||
std::string nozzle_diameters;
|
||||
std::string gcode_file;
|
||||
std::string gcode_file_md5;
|
||||
std::string thumbnail_file;
|
||||
@@ -231,7 +233,7 @@ extern bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSub
|
||||
|
||||
extern std::string bbs_3mf_get_thumbnail(const char * path);
|
||||
|
||||
extern bool load_gcode_3mf_from_stream(std::istream & data, DynamicPrintConfig* config, Model* model, PlateDataPtrs* plate_data_list,
|
||||
extern bool load_gcode_3mf_from_stream(std::istream & data, DynamicPrintConfig* config, Model* model, PlateDataPtrs* plate_data_list,
|
||||
Semver* file_version);
|
||||
|
||||
|
||||
|
||||
+147
-16
@@ -1357,7 +1357,22 @@ namespace DoExport {
|
||||
total_weight += weight;
|
||||
total_cost += weight * extruder->filament_cost() * 0.001;
|
||||
}
|
||||
|
||||
|
||||
for (auto volume : result.print_statistics.wipe_tower_volumes_per_extruder) {
|
||||
total_extruded_volume += volume.second;
|
||||
|
||||
size_t extruder_id = volume.first;
|
||||
auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) {return extr.id() == extruder_id; });
|
||||
if (extruder == extruders.end())
|
||||
continue;
|
||||
|
||||
double s = PI * sqr(0.5* extruder->filament_diameter());
|
||||
double weight = volume.second * extruder->filament_density() * 0.001;
|
||||
total_used_filament += volume.second/s;
|
||||
total_weight += weight;
|
||||
total_cost += weight * extruder->filament_cost() * 0.001;
|
||||
}
|
||||
|
||||
total_cost += config.time_cost.getFloat() * (normal_print_time/3600.0);
|
||||
|
||||
print_statistics.total_extruded_volume = total_extruded_volume;
|
||||
@@ -1398,8 +1413,7 @@ namespace DoExport {
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Layer change G-code")), config.layer_change_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Time lapse G-code")), config.time_lapse_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change filament G-code")), config.change_filament_gcode.value);
|
||||
//BBS
|
||||
//if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value);
|
||||
//if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
|
||||
//Orca
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change extrusion role G-code")), config.change_extrusion_role_gcode.value);
|
||||
@@ -1531,6 +1545,27 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
}
|
||||
m_processor.result().timelapse_warning_code = m_timelapse_warning_code;
|
||||
m_processor.result().support_traditional_timelapse = m_support_traditional_timelapse;
|
||||
|
||||
{ //BBS:check bed and filament compatible
|
||||
const ConfigOptionDef *bed_type_def = print_config_def.get("curr_bed_type");
|
||||
assert(bed_type_def != nullptr);
|
||||
const t_config_enum_values *bed_type_keys_map = bed_type_def->enum_keys_map;
|
||||
const ConfigOptionInts *bed_temp_opt = m_config.option<ConfigOptionInts>(get_bed_temp_key(m_config.curr_bed_type));
|
||||
for(auto extruder_id : m_initial_layer_extruders){
|
||||
int cur_bed_temp = bed_temp_opt->get_at(extruder_id);
|
||||
if (cur_bed_temp == 0 && bed_type_keys_map != nullptr) {
|
||||
for (auto item : *bed_type_keys_map) {
|
||||
if (item.second == m_config.curr_bed_type) {
|
||||
m_processor.result().bed_match_result = BedMatchResult(false, item.first, extruder_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_processor.result().bed_match_result.match == false)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_processor.finalize(true);
|
||||
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
|
||||
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics, print->config());
|
||||
@@ -1919,6 +1954,24 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::string filament_density_list = "; filament_density: ";
|
||||
(filament_density_list+=m_config.filament_density.serialize()) +='\n';
|
||||
file.writeln(filament_density_list);
|
||||
|
||||
std::string filament_diameter_list = "; filament_diameter: ";
|
||||
(filament_diameter_list += m_config.filament_diameter.serialize()) += '\n';
|
||||
file.writeln(filament_diameter_list);
|
||||
|
||||
coordf_t max_height_z = -1;
|
||||
for (const auto& object : print.objects())
|
||||
max_height_z = std::max(object->layers().back()->print_z, max_height_z);
|
||||
|
||||
std::ostringstream max_height_z_tip;
|
||||
max_height_z_tip<<"; max_z_height: " << std::fixed << std::setprecision(2) << max_height_z << '\n';
|
||||
file.writeln(max_height_z_tip.str());
|
||||
}
|
||||
|
||||
file.write_format("; HEADER_BLOCK_END\n\n");
|
||||
|
||||
|
||||
@@ -3545,6 +3598,27 @@ LayerResult GCode::process_layer(
|
||||
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) :
|
||||
Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done);
|
||||
|
||||
// BBS: get next extruder according to flush and soluble
|
||||
auto get_next_extruder = [&](int current_extruder,const std::vector<unsigned int>&extruders) {
|
||||
std::vector<float> flush_matrix(cast<float>(m_config.flush_volumes_matrix.values));
|
||||
const unsigned int number_of_extruders = (unsigned int)(sqrt(flush_matrix.size()) + EPSILON);
|
||||
// Extract purging volumes for each extruder pair:
|
||||
std::vector<std::vector<float>> wipe_volumes;
|
||||
for (unsigned int i = 0; i < number_of_extruders; ++i)
|
||||
wipe_volumes.push_back(std::vector<float>(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders));
|
||||
unsigned int next_extruder = current_extruder;
|
||||
float min_flush = std::numeric_limits<float>::max();
|
||||
for (auto extruder_id : extruders) {
|
||||
if (print.config().filament_soluble.get_at(extruder_id) || extruder_id == current_extruder)
|
||||
continue;
|
||||
if (wipe_volumes[current_extruder][extruder_id] < min_flush) {
|
||||
next_extruder = extruder_id;
|
||||
min_flush = wipe_volumes[current_extruder][extruder_id];
|
||||
}
|
||||
}
|
||||
return next_extruder;
|
||||
};
|
||||
|
||||
if (m_config.enable_overhang_speed && !m_config.overhang_speed_classic) {
|
||||
for (const auto &layer_to_print : layers) {
|
||||
m_extrusion_quality_estimator.prepare_for_new_layer(layer_to_print.original_object,
|
||||
@@ -3597,12 +3671,21 @@ LayerResult GCode::process_layer(
|
||||
if (print.config().filament_soluble.get_at(extruder_id))
|
||||
continue;
|
||||
|
||||
//BBS: now we don't consider interface filament used in other object
|
||||
if (extruder_id == interface_extruder)
|
||||
continue;
|
||||
|
||||
dontcare_extruder = extruder_id;
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
//BBS: not found a suitable extruder in current layer ,dontcare_extruider==first_extruder_id==interface_extruder
|
||||
if (dontcare_extruder == interface_extruder && (object.config().support_interface_not_for_body && object.config().support_interface_filament.value!=0)) {
|
||||
// BBS : get a suitable extruder from other layer
|
||||
auto all_extruders = print.extruders();
|
||||
dontcare_extruder = get_next_extruder(dontcare_extruder, all_extruders);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (support_dontcare)
|
||||
support_extruder = dontcare_extruder;
|
||||
@@ -3964,16 +4047,56 @@ LayerResult GCode::process_layer(
|
||||
m_last_obj_copy = this_object_copy;
|
||||
this->set_origin(unscale(offset));
|
||||
//FIXME the following code prints regions in the order they are defined, the path is not optimized in any way.
|
||||
bool is_infill_first = print.default_region_config().wall_infill_order == WallInfillOrder::InfillInnerOuter ||
|
||||
print.default_region_config().wall_infill_order == WallInfillOrder::InfillOuterInner;
|
||||
bool is_infill_first =print.config().is_infill_first;
|
||||
|
||||
auto has_infill = [](const std::vector<ObjectByExtruder::Island::Region> &by_region) {
|
||||
for (auto region : by_region) {
|
||||
if (!region.infills.empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
//BBS: for first layer, we always print wall firstly to get better bed adhesive force
|
||||
//This behaviour is same with cura
|
||||
if (is_infill_first && !first_layer) {
|
||||
gcode += this->extrude_infill(print, by_region_specific, false);
|
||||
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) {
|
||||
gcode += this->retract(false, false, LiftType::NormalLift);
|
||||
|
||||
std::string timepals_gcode = insert_timelapse_gcode();
|
||||
gcode += timepals_gcode;
|
||||
m_writer.set_current_position_clear(false);
|
||||
//BBS: check whether custom gcode changes the z position. Update if changed
|
||||
double temp_z_after_timepals_gcode;
|
||||
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) {
|
||||
Vec3d pos = m_writer.get_position();
|
||||
pos(2) = temp_z_after_timepals_gcode;
|
||||
m_writer.set_position(pos);
|
||||
}
|
||||
|
||||
has_insert_timelapse_gcode = true;
|
||||
}
|
||||
gcode += this->extrude_infill(print, by_region_specific, false);
|
||||
gcode += this->extrude_perimeters(print, by_region_specific);
|
||||
} else {
|
||||
gcode += this->extrude_perimeters(print, by_region_specific);
|
||||
gcode += this->extrude_infill(print,by_region_specific, false);
|
||||
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) {
|
||||
gcode += this->retract(false, false, LiftType::NormalLift);
|
||||
|
||||
std::string timepals_gcode = insert_timelapse_gcode();
|
||||
gcode += timepals_gcode;
|
||||
m_writer.set_current_position_clear(false);
|
||||
//BBS: check whether custom gcode changes the z position. Update if changed
|
||||
double temp_z_after_timepals_gcode;
|
||||
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) {
|
||||
Vec3d pos = m_writer.get_position();
|
||||
pos(2) = temp_z_after_timepals_gcode;
|
||||
m_writer.set_position(pos);
|
||||
}
|
||||
|
||||
has_insert_timelapse_gcode = true;
|
||||
}
|
||||
gcode += this->extrude_infill(print,by_region_specific, false);
|
||||
}
|
||||
// ironing
|
||||
gcode += this->extrude_infill(print,by_region_specific, true);
|
||||
@@ -4002,6 +4125,12 @@ LayerResult GCode::process_layer(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (first_layer) {
|
||||
for (auto iter = by_extruder.begin(); iter != by_extruder.end(); ++iter) {
|
||||
if (!iter->second.empty())
|
||||
m_initial_layer_extruders.insert(iter->first);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Apply spiral vase post-processing if this layer contains suitable geometry
|
||||
@@ -4197,9 +4326,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
Point last_pos = this->last_pos();
|
||||
if (!m_config.spiral_mode && description == "perimeter") {
|
||||
assert(m_layer != nullptr);
|
||||
bool is_outer_wall_first = m_config.wall_infill_order == WallInfillOrder::OuterInnerInfill
|
||||
|| m_config.wall_infill_order == WallInfillOrder::InfillOuterInner
|
||||
|| m_config.wall_infill_order == WallInfillOrder::InnerOuterInnerInfill;
|
||||
bool is_outer_wall_first = m_config.wall_sequence == WallSequence::OuterInner;
|
||||
m_seam_placer.place_seam(m_layer, loop, is_outer_wall_first, this->last_pos());
|
||||
} else
|
||||
loop.split_at(last_pos, false);
|
||||
@@ -5207,10 +5334,11 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role, LiftTyp
|
||||
travel_bbox.inflated(1);
|
||||
travel_bbox.defined = true;
|
||||
|
||||
const float protect_z_scaled = scale_(0.4);
|
||||
// do not scale for z
|
||||
const float protect_z = 0.4;
|
||||
std::pair<float, float> z_range;
|
||||
z_range.second = m_layer ? m_layer->print_z : 0.f;
|
||||
z_range.first = std::max(0.f, z_range.second - protect_z_scaled);
|
||||
z_range.first = std::max(0.f, z_range.second - protect_z);
|
||||
std::vector<LayerPtrs> layers_of_objects;
|
||||
std::vector<BoundingBox> boundingBox_for_objects;
|
||||
std::vector<Points> objects_instances_shift;
|
||||
@@ -5261,7 +5389,7 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role, LiftTyp
|
||||
float max_z_hop = 0.f;
|
||||
for (int i = 0; i < m_config.z_hop.size(); i++)
|
||||
max_z_hop = std::max(max_z_hop, (float)m_config.z_hop.get_at(i));
|
||||
float travel_len_thresh = max_z_hop / tan(GCodeWriter::slope_threshold);
|
||||
float travel_len_thresh = scale_(max_z_hop / tan(GCodeWriter::slope_threshold));
|
||||
float accum_len = 0.f;
|
||||
Polyline clipped_travel;
|
||||
|
||||
@@ -5337,8 +5465,7 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li
|
||||
gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract();
|
||||
|
||||
gcode += m_writer.reset_e();
|
||||
|
||||
// check if should + can lift (roughly from SuperSlicer)
|
||||
// Orca: check if should + can lift (roughly from SuperSlicer)
|
||||
RetractLiftEnforceType retract_lift_type = RetractLiftEnforceType(EXTRUDER_CONFIG(retract_lift_enforce));
|
||||
|
||||
bool needs_lift = toolchange
|
||||
@@ -5371,7 +5498,7 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool by_object)
|
||||
{
|
||||
if (!m_writer.need_toolchange(extruder_id))
|
||||
return "";
|
||||
@@ -5405,6 +5532,10 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
// Always reset the extrusion path, even if the tool change retract is set to zero.
|
||||
m_wipe.reset_path();
|
||||
|
||||
// BBS: insert skip object label before change filament while by object
|
||||
if (by_object)
|
||||
m_writer.add_object_change_labels(gcode);
|
||||
|
||||
if (m_writer.extruder() != nullptr) {
|
||||
// Process the custom filament_end_gcode. set_extruder() is only called if there is no wipe tower
|
||||
// so it should not be injected twice.
|
||||
|
||||
@@ -216,7 +216,7 @@ public:
|
||||
bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type);
|
||||
std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift);
|
||||
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
|
||||
std::string set_extruder(unsigned int extruder_id, double print_z);
|
||||
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false);
|
||||
bool is_BBL_Printer();
|
||||
|
||||
// SoftFever
|
||||
@@ -549,6 +549,7 @@ private:
|
||||
bool m_need_change_layer_lift_z = false;
|
||||
int m_start_gcode_filament = -1;
|
||||
|
||||
std::set<unsigned int> m_initial_layer_extruders;
|
||||
// BBS
|
||||
int get_bed_temperature(const int extruder_id, const bool is_first_layer, const BedType bed_type) const;
|
||||
|
||||
|
||||
@@ -91,34 +91,34 @@ inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance
|
||||
|
||||
void LinesBucketQueue::emplace_back_bucket(ExtrusionLayers &&els, const void *objPtr, Point offset)
|
||||
{
|
||||
auto oldSize = _buckets.capacity();
|
||||
_buckets.emplace_back(std::move(els), objPtr, offset);
|
||||
_pq.push(&_buckets.back());
|
||||
auto newSize = _buckets.capacity();
|
||||
auto oldSize = line_buckets.capacity();
|
||||
line_buckets.emplace_back(std::move(els), objPtr, offset);
|
||||
line_bucket_ptr_queue.push(&line_buckets.back());
|
||||
auto newSize = line_buckets.capacity();
|
||||
if (oldSize != newSize) { // pointers change
|
||||
decltype(_pq) newQueue;
|
||||
for (LinesBucket &bucket : _buckets) { newQueue.push(&bucket); }
|
||||
std::swap(_pq, newQueue);
|
||||
decltype(line_bucket_ptr_queue) newQueue;
|
||||
for (LinesBucket &bucket : line_buckets) { newQueue.push(&bucket); }
|
||||
std::swap(line_bucket_ptr_queue, newQueue);
|
||||
}
|
||||
}
|
||||
|
||||
// remove lowest and get the current bottom z
|
||||
float LinesBucketQueue::getCurrBottomZ()
|
||||
{
|
||||
auto lowest = _pq.top();
|
||||
_pq.pop();
|
||||
auto lowest = line_bucket_ptr_queue.top();
|
||||
line_bucket_ptr_queue.pop();
|
||||
float layerBottomZ = lowest->curBottomZ();
|
||||
std::vector<LinesBucket *> lowests;
|
||||
lowests.push_back(lowest);
|
||||
|
||||
while (_pq.empty() == false && std::abs(_pq.top()->curBottomZ() - lowest->curBottomZ()) < EPSILON) {
|
||||
lowests.push_back(_pq.top());
|
||||
_pq.pop();
|
||||
while (line_bucket_ptr_queue.empty() == false && std::abs(line_bucket_ptr_queue.top()->curBottomZ() - lowest->curBottomZ()) < EPSILON) {
|
||||
lowests.push_back(line_bucket_ptr_queue.top());
|
||||
line_bucket_ptr_queue.pop();
|
||||
}
|
||||
|
||||
for (LinesBucket *bp : lowests) {
|
||||
bp->raise();
|
||||
if (bp->valid()) { _pq.push(bp); }
|
||||
if (bp->valid()) { line_bucket_ptr_queue.push(bp); }
|
||||
}
|
||||
return layerBottomZ;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ float LinesBucketQueue::getCurrBottomZ()
|
||||
LineWithIDs LinesBucketQueue::getCurLines() const
|
||||
{
|
||||
LineWithIDs lines;
|
||||
for (const LinesBucket &bucket : _buckets) {
|
||||
for (const LinesBucket &bucket : line_buckets) {
|
||||
if (bucket.valid()) {
|
||||
LineWithIDs tmpLines = bucket.curLines();
|
||||
lines.insert(lines.end(), tmpLines.begin(), tmpLines.end());
|
||||
|
||||
@@ -109,12 +109,12 @@ struct LinesBucketPtrComp
|
||||
class LinesBucketQueue
|
||||
{
|
||||
public:
|
||||
std::vector<LinesBucket> _buckets;
|
||||
std::priority_queue<LinesBucket *, std::vector<LinesBucket *>, LinesBucketPtrComp> _pq;
|
||||
std::vector<LinesBucket> line_buckets;
|
||||
std::priority_queue<LinesBucket *, std::vector<LinesBucket *>, LinesBucketPtrComp> line_bucket_ptr_queue;
|
||||
|
||||
public:
|
||||
void emplace_back_bucket(ExtrusionLayers &&els, const void *objPtr, Point offset);
|
||||
bool valid() const { return _pq.empty() == false; }
|
||||
bool valid() const { return line_bucket_ptr_queue.empty() == false; }
|
||||
float getCurrBottomZ();
|
||||
LineWithIDs getCurLines() const;
|
||||
};
|
||||
|
||||
@@ -44,6 +44,7 @@ static const size_t MIN_EXTRUDERS_COUNT = 5;
|
||||
static const float DEFAULT_FILAMENT_DIAMETER = 1.75f;
|
||||
static const int DEFAULT_FILAMENT_HRC = 0;
|
||||
static const float DEFAULT_FILAMENT_DENSITY = 1.245f;
|
||||
static const float DEFAULT_FILAMENT_COST = 29.99f;
|
||||
static const int DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE = 0;
|
||||
static const Slic3r::Vec3f DEFAULT_EXTRUDER_OFFSET = Slic3r::Vec3f::Zero();
|
||||
|
||||
@@ -64,7 +65,9 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
|
||||
"_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER",
|
||||
"_GP_TOTAL_LAYER_NUMBER_PLACEHOLDER",
|
||||
" MANUAL_TOOL_CHANGE ",
|
||||
"_DURING_PRINT_EXHAUST_FAN"
|
||||
"_DURING_PRINT_EXHAUST_FAN",
|
||||
" WIPE_TOWER_START",
|
||||
" WIPE_TOWER_END"
|
||||
};
|
||||
|
||||
const std::vector<std::string> GCodeProcessor::Reserved_Tags_compatible = {
|
||||
@@ -81,7 +84,10 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags_compatible = {
|
||||
"_GP_LAST_LINE_M73_PLACEHOLDER",
|
||||
"_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER",
|
||||
"_GP_TOTAL_LAYER_NUMBER_PLACEHOLDER",
|
||||
" MANUAL_TOOL_CHANGE "
|
||||
" MANUAL_TOOL_CHANGE ",
|
||||
"_DURING_PRINT_EXHAUST_FAN",
|
||||
" WIPE_TOWER_START",
|
||||
" WIPE_TOWER_END"
|
||||
};
|
||||
|
||||
|
||||
@@ -732,22 +738,30 @@ void GCodeProcessor::UsedFilaments::reset()
|
||||
color_change_cache = 0.0f;
|
||||
volumes_per_color_change = std::vector<double>();
|
||||
|
||||
tool_change_cache = 0.0f;
|
||||
model_extrude_cache = 0.0f;
|
||||
volumes_per_extruder.clear();
|
||||
|
||||
flush_per_filament.clear();
|
||||
|
||||
role_cache = 0.0f;
|
||||
filaments_per_role.clear();
|
||||
|
||||
wipe_tower_cache = 0.0f;
|
||||
wipe_tower_volume_per_extruder.clear();
|
||||
}
|
||||
|
||||
void GCodeProcessor::UsedFilaments::increase_caches(double extruded_volume)
|
||||
void GCodeProcessor::UsedFilaments::increase_model_caches(double extruded_volume)
|
||||
{
|
||||
color_change_cache += extruded_volume;
|
||||
tool_change_cache += extruded_volume;
|
||||
model_extrude_cache += extruded_volume;
|
||||
role_cache += extruded_volume;
|
||||
}
|
||||
|
||||
void GCodeProcessor::UsedFilaments::increase_wipe_tower_caches(double extruded_volume)
|
||||
{
|
||||
wipe_tower_cache += extruded_volume;
|
||||
}
|
||||
|
||||
void GCodeProcessor::UsedFilaments::process_color_change_cache()
|
||||
{
|
||||
if (color_change_cache != 0.0f) {
|
||||
@@ -756,15 +770,27 @@ void GCodeProcessor::UsedFilaments::process_color_change_cache()
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::UsedFilaments::process_extruder_cache(GCodeProcessor* processor)
|
||||
void GCodeProcessor::UsedFilaments::process_model_cache(GCodeProcessor* processor)
|
||||
{
|
||||
size_t active_extruder_id = processor->m_extruder_id;
|
||||
if (tool_change_cache != 0.0f) {
|
||||
if (model_extrude_cache != 0.0f) {
|
||||
if (volumes_per_extruder.find(active_extruder_id) != volumes_per_extruder.end())
|
||||
volumes_per_extruder[active_extruder_id] += tool_change_cache;
|
||||
volumes_per_extruder[active_extruder_id] += model_extrude_cache;
|
||||
else
|
||||
volumes_per_extruder[active_extruder_id] = tool_change_cache;
|
||||
tool_change_cache = 0.0f;
|
||||
volumes_per_extruder[active_extruder_id] = model_extrude_cache;
|
||||
model_extrude_cache = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::UsedFilaments::process_wipe_tower_cache(GCodeProcessor* processor)
|
||||
{
|
||||
size_t active_extruder_id = processor->m_extruder_id;
|
||||
if (wipe_tower_cache != 0.0f) {
|
||||
if (wipe_tower_volume_per_extruder.find(active_extruder_id) != wipe_tower_volume_per_extruder.end())
|
||||
wipe_tower_volume_per_extruder[active_extruder_id] += wipe_tower_cache;
|
||||
else
|
||||
wipe_tower_volume_per_extruder[active_extruder_id] = wipe_tower_cache;
|
||||
wipe_tower_cache = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,8 +825,9 @@ void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor
|
||||
void GCodeProcessor::UsedFilaments::process_caches(GCodeProcessor* processor)
|
||||
{
|
||||
process_color_change_cache();
|
||||
process_extruder_cache(processor);
|
||||
process_model_cache(processor);
|
||||
process_role_cache(processor);
|
||||
process_wipe_tower_cache(processor);
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
@@ -852,8 +879,10 @@ void GCodeProcessorResult::reset() {
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
required_nozzle_HRC = std::vector<int>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_HRC);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
filament_costs = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_COST);
|
||||
custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
|
||||
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
|
||||
bed_match_result = BedMatchResult(true);
|
||||
warnings.clear();
|
||||
|
||||
//BBS: add mutex for protection of gcode result
|
||||
@@ -962,6 +991,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_result.required_nozzle_HRC.resize(extruders_count);
|
||||
m_result.filament_densities.resize(extruders_count);
|
||||
m_result.filament_vitrification_temperature.resize(extruders_count);
|
||||
m_result.filament_costs.resize(extruders_count);
|
||||
m_extruder_temps.resize(extruders_count);
|
||||
m_result.nozzle_hrc = static_cast<int>(config.nozzle_hrc.getInt());
|
||||
m_result.nozzle_type = config.nozzle_type;
|
||||
@@ -972,6 +1002,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_result.required_nozzle_HRC[i] = static_cast<int>(config.required_nozzle_HRC.get_at(i));
|
||||
m_result.filament_densities[i] = static_cast<float>(config.filament_density.get_at(i));
|
||||
m_result.filament_vitrification_temperature[i] = static_cast<float>(config.temperature_vitrification.get_at(i));
|
||||
m_result.filament_costs[i] = static_cast<float>(config.filament_cost.get_at(i));
|
||||
}
|
||||
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper || m_flavor == gcfRepRapFirmware) {
|
||||
@@ -1027,6 +1058,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
|
||||
if (z_offset != nullptr)
|
||||
m_z_offset = z_offset->value;
|
||||
|
||||
}
|
||||
|
||||
void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
@@ -1114,6 +1146,19 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
m_result.filament_densities.emplace_back(DEFAULT_FILAMENT_DENSITY);
|
||||
}
|
||||
}
|
||||
|
||||
//BBS
|
||||
const ConfigOptionFloats* filament_costs = config.option<ConfigOptionFloats>("filament_cost");
|
||||
if (filament_costs != nullptr) {
|
||||
m_result.filament_costs.clear();
|
||||
m_result.filament_costs.resize(filament_costs->values.size());
|
||||
for (size_t i = 0; i < filament_costs->values.size(); ++i)
|
||||
m_result.filament_costs[i]=static_cast<float>(filament_costs->values[i]);
|
||||
}
|
||||
for (size_t i = m_result.filament_costs.size(); i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_costs.emplace_back(DEFAULT_FILAMENT_COST);
|
||||
}
|
||||
|
||||
//BBS
|
||||
const ConfigOptionInts* filament_vitrification_temperature = config.option<ConfigOptionInts>("temperature_vitrification");
|
||||
if (filament_vitrification_temperature != nullptr) {
|
||||
@@ -1330,6 +1375,7 @@ void GCodeProcessor::reset()
|
||||
m_cached_position.reset();
|
||||
m_wiping = false;
|
||||
m_flushing = false;
|
||||
m_wipe_tower = false;
|
||||
m_remaining_volume = 0.f;
|
||||
// BBS: arc move related data
|
||||
m_move_path_type = EMovePathType::Noop_move;
|
||||
@@ -2106,6 +2152,17 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
|
||||
return;
|
||||
}
|
||||
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Tower_Start))) {
|
||||
m_wipe_tower = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Tower_End))) {
|
||||
m_wipe_tower = false;
|
||||
m_used_filaments.process_wipe_tower_cache(this);
|
||||
return;
|
||||
}
|
||||
|
||||
//BBS: flush start tag
|
||||
if (boost::starts_with(comment, GCodeProcessor::Flush_Start_Tag)) {
|
||||
m_flushing = true;
|
||||
@@ -2811,10 +2868,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
||||
float delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
|
||||
float volume_extruded_filament = area_filament_cross_section * delta_pos[E];
|
||||
float area_toolpath_cross_section = volume_extruded_filament / delta_xyz;
|
||||
|
||||
// save extruded volume to the cache
|
||||
m_used_filaments.increase_caches(volume_extruded_filament);
|
||||
|
||||
if (m_wipe_tower) {
|
||||
m_used_filaments.increase_wipe_tower_caches(volume_extruded_filament);
|
||||
}
|
||||
else {
|
||||
// save extruded volume to the cache
|
||||
m_used_filaments.increase_model_caches(volume_extruded_filament);
|
||||
}
|
||||
// volume extruded filament / tool displacement = area toolpath cross section
|
||||
m_mm3_per_mm = area_toolpath_cross_section;
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
@@ -3268,10 +3328,14 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
if (type == EMoveType::Extrude) {
|
||||
float volume_extruded_filament = area_filament_cross_section * delta_pos[E];
|
||||
float area_toolpath_cross_section = volume_extruded_filament / delta_xyz;
|
||||
|
||||
//BBS: save extruded volume to the cache
|
||||
m_used_filaments.increase_caches(volume_extruded_filament);
|
||||
|
||||
if (m_wipe_tower) {
|
||||
//BBS: save wipe tower volume to the cache
|
||||
m_used_filaments.increase_wipe_tower_caches(volume_extruded_filament);
|
||||
}
|
||||
else {
|
||||
//BBS: save extruded volume to the cache
|
||||
m_used_filaments.increase_model_caches(volume_extruded_filament);
|
||||
}
|
||||
//BBS: volume extruded filament / tool displacement = area toolpath cross section
|
||||
m_mm3_per_mm = area_toolpath_cross_section;
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
@@ -4320,7 +4384,7 @@ void GCodeProcessor::process_filaments(CustomGCode::Type code)
|
||||
m_used_filaments.process_color_change_cache();
|
||||
|
||||
if (code == CustomGCode::ToolChange) {
|
||||
m_used_filaments.process_extruder_cache(this);
|
||||
m_used_filaments.process_model_cache(this);
|
||||
//BBS: reset remaining filament
|
||||
m_remaining_volume = m_nozzle_volume;
|
||||
}
|
||||
@@ -4353,6 +4417,7 @@ void GCodeProcessor::update_estimated_times_stats()
|
||||
|
||||
m_result.print_statistics.volumes_per_color_change = m_used_filaments.volumes_per_color_change;
|
||||
m_result.print_statistics.volumes_per_extruder = m_used_filaments.volumes_per_extruder;
|
||||
m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volume_per_extruder;
|
||||
m_result.print_statistics.flush_per_filament = m_used_filaments.flush_per_filament;
|
||||
m_result.print_statistics.used_filaments_per_role = m_used_filaments.filaments_per_role;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Slic3r {
|
||||
|
||||
std::vector<double> volumes_per_color_change;
|
||||
std::map<size_t, double> volumes_per_extruder;
|
||||
std::map<size_t, double> wipe_tower_volumes_per_extruder;
|
||||
//BBS: the flush amount of every filament
|
||||
std::map<size_t, double> flush_per_filament;
|
||||
std::map<ExtrusionRole, std::pair<double, double>> used_filaments_per_role;
|
||||
@@ -88,6 +89,7 @@ namespace Slic3r {
|
||||
}
|
||||
volumes_per_color_change.clear();
|
||||
volumes_per_color_change.shrink_to_fit();
|
||||
wipe_tower_volumes_per_extruder.clear();
|
||||
volumes_per_extruder.clear();
|
||||
flush_per_filament.clear();
|
||||
used_filaments_per_role.clear();
|
||||
@@ -109,11 +111,23 @@ namespace Slic3r {
|
||||
ConflictResult() = default;
|
||||
};
|
||||
|
||||
struct BedMatchResult
|
||||
{
|
||||
bool match;
|
||||
std::string bed_type_name;
|
||||
int extruder_id;
|
||||
BedMatchResult():match(true),bed_type_name(""),extruder_id(-1) {}
|
||||
BedMatchResult(bool _match,const std::string& _bed_type_name="",int _extruder_id=-1)
|
||||
:match(_match),bed_type_name(_bed_type_name),extruder_id(_extruder_id)
|
||||
{}
|
||||
};
|
||||
|
||||
using ConflictResultOpt = std::optional<ConflictResult>;
|
||||
|
||||
struct GCodeProcessorResult
|
||||
{
|
||||
ConflictResultOpt conflict_result;
|
||||
BedMatchResult bed_match_result;
|
||||
|
||||
struct SettingsIds
|
||||
{
|
||||
@@ -190,6 +204,7 @@ namespace Slic3r {
|
||||
std::vector<float> filament_diameters;
|
||||
std::vector<int> required_nozzle_HRC;
|
||||
std::vector<float> filament_densities;
|
||||
std::vector<float> filament_costs;
|
||||
std::vector<int> filament_vitrification_temperature;
|
||||
PrintEstimatedStatistics print_statistics;
|
||||
std::vector<CustomGCode::Item> custom_gcode_per_print_z;
|
||||
@@ -223,11 +238,13 @@ namespace Slic3r {
|
||||
extruder_colors = other.extruder_colors;
|
||||
filament_diameters = other.filament_diameters;
|
||||
filament_densities = other.filament_densities;
|
||||
filament_costs = other.filament_costs;
|
||||
print_statistics = other.print_statistics;
|
||||
custom_gcode_per_print_z = other.custom_gcode_per_print_z;
|
||||
spiral_vase_layers = other.spiral_vase_layers;
|
||||
warnings = other.warnings;
|
||||
bed_type = other.bed_type;
|
||||
bed_match_result = other.bed_match_result;
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
time = other.time;
|
||||
#endif
|
||||
@@ -261,7 +278,9 @@ namespace Slic3r {
|
||||
Estimated_Printing_Time_Placeholder,
|
||||
Total_Layer_Number_Placeholder,
|
||||
Manual_Tool_Change,
|
||||
During_Print_Exhaust_Fan
|
||||
During_Print_Exhaust_Fan,
|
||||
Wipe_Tower_Start,
|
||||
Wipe_Tower_End,
|
||||
};
|
||||
|
||||
static const std::string& reserved_tag(ETags tag) { return s_IsBBLPrinter ? Reserved_Tags[static_cast<unsigned char>(tag)] : Reserved_Tags_compatible[static_cast<unsigned char>(tag)]; }
|
||||
@@ -474,9 +493,12 @@ namespace Slic3r {
|
||||
double color_change_cache;
|
||||
std::vector<double> volumes_per_color_change;
|
||||
|
||||
double tool_change_cache;
|
||||
double model_extrude_cache;
|
||||
std::map<size_t, double> volumes_per_extruder;
|
||||
|
||||
double wipe_tower_cache;
|
||||
std::map<size_t, double>wipe_tower_volume_per_extruder;
|
||||
|
||||
//BBS: the flush amount of every filament
|
||||
std::map<size_t, double> flush_per_filament;
|
||||
|
||||
@@ -485,10 +507,12 @@ namespace Slic3r {
|
||||
|
||||
void reset();
|
||||
|
||||
void increase_caches(double extruded_volume);
|
||||
void increase_model_caches(double extruded_volume);
|
||||
void increase_wipe_tower_caches(double extruded_volume);
|
||||
|
||||
void process_color_change_cache();
|
||||
void process_extruder_cache(GCodeProcessor* processor);
|
||||
void process_model_cache(GCodeProcessor* processor);
|
||||
void process_wipe_tower_cache(GCodeProcessor* processor);
|
||||
void update_flush_per_filament(size_t extrude_id, float flush_length);
|
||||
void process_role_cache(GCodeProcessor* processor);
|
||||
void process_caches(GCodeProcessor* processor);
|
||||
@@ -637,6 +661,7 @@ namespace Slic3r {
|
||||
CachedPosition m_cached_position;
|
||||
bool m_wiping;
|
||||
bool m_flushing;
|
||||
bool m_wipe_tower;
|
||||
float m_remaining_volume;
|
||||
bool m_manual_filament_change;
|
||||
|
||||
|
||||
+1130
-1362
File diff suppressed because it is too large
Load Diff
@@ -27,136 +27,139 @@ class Grid;
|
||||
|
||||
namespace SeamPlacerImpl {
|
||||
|
||||
// ************ FOR BACKPORT COMPATIBILITY ONLY ***************
|
||||
// Angle from v1 to v2, returning double atan2(y, x) normalized to <-PI, PI>.
|
||||
template<typename Derived, typename Derived2> inline double angle(const Eigen::MatrixBase<Derived> &v1, const Eigen::MatrixBase<Derived2> &v2)
|
||||
{
|
||||
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "angle(): first parameter is not a 2D vector");
|
||||
static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "angle(): second parameter is not a 2D vector");
|
||||
auto v1d = v1.template cast<double>();
|
||||
auto v2d = v2.template cast<double>();
|
||||
return atan2(cross2(v1d, v2d), v1d.dot(v2d));
|
||||
}
|
||||
// ***************************
|
||||
|
||||
struct GlobalModelInfo;
|
||||
struct SeamComparator;
|
||||
|
||||
enum class EnforcedBlockedSeamPoint {
|
||||
Blocked = 0,
|
||||
Neutral = 1,
|
||||
Enforced = 2,
|
||||
Blocked = 0,
|
||||
Neutral = 1,
|
||||
Enforced = 2,
|
||||
};
|
||||
|
||||
// struct representing single perimeter loop
|
||||
struct Perimeter {
|
||||
size_t start_index{};
|
||||
size_t end_index{}; //inclusive!
|
||||
size_t seam_index{};
|
||||
float flow_width{};
|
||||
struct Perimeter
|
||||
{
|
||||
size_t start_index{};
|
||||
size_t end_index{}; // inclusive!
|
||||
size_t seam_index{};
|
||||
float flow_width{};
|
||||
|
||||
// During alignment, a final position may be stored here. In that case, finalized is set to true.
|
||||
// Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position
|
||||
// Random position also uses this flexibility to set final seam point position
|
||||
bool finalized = false;
|
||||
Vec3f final_seam_position = Vec3f::Zero();
|
||||
// During alignment, a final position may be stored here. In that case, finalized is set to true.
|
||||
// Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position
|
||||
// Random position also uses this flexibility to set final seam point position
|
||||
bool finalized = false;
|
||||
Vec3f final_seam_position = Vec3f::Zero();
|
||||
};
|
||||
|
||||
//Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created,
|
||||
// Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created,
|
||||
// then all the needed attributes are computed and finally, for each perimeter one point is chosen as seam.
|
||||
// This seam position can be then further aligned
|
||||
struct SeamCandidate {
|
||||
SeamCandidate(const Vec3f &pos, Perimeter &perimeter,
|
||||
float local_ccw_angle,
|
||||
EnforcedBlockedSeamPoint type) :
|
||||
position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), embedded_distance(0.0f), local_ccw_angle(
|
||||
local_ccw_angle), type(type), central_enforcer(false) {
|
||||
}
|
||||
const Vec3f position;
|
||||
// pointer to Perimeter loop of this point. It is shared across all points of the loop
|
||||
Perimeter &perimeter;
|
||||
float visibility;
|
||||
float overhang;
|
||||
// distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join)
|
||||
// Negative sign means inside the print, comes from EdgeGrid structure
|
||||
float embedded_distance;
|
||||
float local_ccw_angle;
|
||||
EnforcedBlockedSeamPoint type;
|
||||
bool central_enforcer; //marks this candidate as central point of enforced segment on the perimeter - important for alignment
|
||||
struct SeamCandidate
|
||||
{
|
||||
SeamCandidate(const Vec3f &pos, Perimeter &perimeter, float local_ccw_angle, EnforcedBlockedSeamPoint type)
|
||||
: position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), embedded_distance(0.0f), local_ccw_angle(local_ccw_angle), type(type), central_enforcer(false)
|
||||
{}
|
||||
const Vec3f position;
|
||||
// pointer to Perimeter loop of this point. It is shared across all points of the loop
|
||||
Perimeter &perimeter;
|
||||
float visibility;
|
||||
float overhang;
|
||||
// distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join)
|
||||
// Negative sign means inside the print, comes from EdgeGrid structure
|
||||
float embedded_distance;
|
||||
float local_ccw_angle;
|
||||
EnforcedBlockedSeamPoint type;
|
||||
bool central_enforcer; // marks this candidate as central point of enforced segment on the perimeter - important for alignment
|
||||
};
|
||||
|
||||
struct SeamCandidateCoordinateFunctor {
|
||||
SeamCandidateCoordinateFunctor(const std::vector<SeamCandidate> &seam_candidates) :
|
||||
seam_candidates(seam_candidates) {
|
||||
}
|
||||
const std::vector<SeamCandidate> &seam_candidates;
|
||||
float operator()(size_t index, size_t dim) const {
|
||||
return seam_candidates[index].position[dim];
|
||||
}
|
||||
struct SeamCandidateCoordinateFunctor
|
||||
{
|
||||
SeamCandidateCoordinateFunctor(const std::vector<SeamCandidate> &seam_candidates) : seam_candidates(seam_candidates) {}
|
||||
const std::vector<SeamCandidate> &seam_candidates;
|
||||
float operator()(size_t index, size_t dim) const { return seam_candidates[index].position[dim]; }
|
||||
};
|
||||
} // namespace SeamPlacerImpl
|
||||
|
||||
struct PrintObjectSeamData
|
||||
{
|
||||
using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
|
||||
using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>;
|
||||
|
||||
struct LayerSeams
|
||||
{
|
||||
Slic3r::deque<SeamPlacerImpl::Perimeter> perimeters;
|
||||
std::vector<SeamPlacerImpl::SeamCandidate> points;
|
||||
std::unique_ptr<SeamCandidatesTree> points_tree;
|
||||
};
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter
|
||||
std::vector<LayerSeams> layers;
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD
|
||||
// tree of all points of the given layer
|
||||
struct LayerSeams
|
||||
{
|
||||
Slic3r::deque<SeamPlacerImpl::Perimeter> perimeters;
|
||||
std::vector<SeamPlacerImpl::SeamCandidate> points;
|
||||
std::unique_ptr<SeamCandidatesTree> points_tree;
|
||||
};
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter
|
||||
std::vector<LayerSeams> layers;
|
||||
// Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD
|
||||
// tree of all points of the given layer
|
||||
|
||||
void clear()
|
||||
{
|
||||
layers.clear();
|
||||
}
|
||||
void clear() { layers.clear(); }
|
||||
};
|
||||
|
||||
class SeamPlacer {
|
||||
class SeamPlacer
|
||||
{
|
||||
public:
|
||||
// Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples
|
||||
static constexpr size_t raycasting_visibility_samples_count = 30000;
|
||||
static constexpr size_t fast_decimation_triangle_count_target = 16000;
|
||||
//square of number of rays per sample point
|
||||
static constexpr size_t sqr_rays_per_sample_point = 5;
|
||||
// Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples
|
||||
static constexpr size_t raycasting_visibility_samples_count = 30000;
|
||||
static constexpr size_t fast_decimation_triangle_count_target = 16000;
|
||||
//square of number of rays per sample point
|
||||
static constexpr size_t sqr_rays_per_sample_point = 5;
|
||||
|
||||
// snapping angle - angles larger than this value will be snapped to during seam painting
|
||||
static constexpr float sharp_angle_snapping_threshold = 55.0f * float(PI) / 180.0f;
|
||||
// overhang angle for seam placement that still yields good results, in degrees, measured from vertical direction
|
||||
static constexpr float overhang_angle_threshold = 50.0f * float(PI) / 180.0f;
|
||||
// snapping angle - angles larger than this value will be snapped to during seam painting
|
||||
static constexpr float sharp_angle_snapping_threshold = 55.0f * float(PI) / 180.0f;
|
||||
// overhang angle for seam placement that still yields good results, in degrees, measured from vertical direction
|
||||
//BBS
|
||||
static constexpr float overhang_angle_threshold = 45.0f * float(PI) / 180.0f;
|
||||
|
||||
// determines angle importance compared to visibility ( neutral value is 1.0f. )
|
||||
static constexpr float angle_importance_aligned = 0.6f;
|
||||
static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visibility info noise
|
||||
// determines angle importance compared to visibility ( neutral value is 1.0f. )
|
||||
static constexpr float angle_importance_aligned = 0.6f;
|
||||
static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visibility info noise
|
||||
|
||||
// For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size
|
||||
static constexpr float enforcer_oversampling_distance = 0.2f;
|
||||
// For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size
|
||||
static constexpr float enforcer_oversampling_distance = 0.2f;
|
||||
|
||||
// When searching for seam clusters for alignment:
|
||||
// following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer
|
||||
static constexpr float seam_align_score_tolerance = 0.3f;
|
||||
// seam_align_tolerable_dist_factor - how far to search for seam from current position, final dist is seam_align_tolerable_dist_factor * flow_width
|
||||
static constexpr float seam_align_tolerable_dist_factor = 4.0f;
|
||||
// minimum number of seams needed in cluster to make alignment happen
|
||||
static constexpr size_t seam_align_minimum_string_seams = 6;
|
||||
// millimeters covered by spline; determines number of splines for the given string
|
||||
static constexpr size_t seam_align_mm_per_segment = 4.0f;
|
||||
// When searching for seam clusters for alignment:
|
||||
// following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer
|
||||
static constexpr float seam_align_score_tolerance = 0.3f;
|
||||
// seam_align_tolerable_dist_factor - how far to search for seam from current position, final dist is seam_align_tolerable_dist_factor * flow_width
|
||||
static constexpr float seam_align_tolerable_dist_factor = 4.0f;
|
||||
// minimum number of seams needed in cluster to make alignment happen
|
||||
static constexpr size_t seam_align_minimum_string_seams = 6;
|
||||
// millimeters covered by spline; determines number of splines for the given string
|
||||
static constexpr size_t seam_align_mm_per_segment = 4.0f;
|
||||
|
||||
//The following data structures hold all perimeter points for all PrintObject.
|
||||
std::unordered_map<const PrintObject*, PrintObjectSeamData> m_seam_per_object;
|
||||
// The following data structures hold all perimeter points for all PrintObject.
|
||||
std::unordered_map<const PrintObject *, PrintObjectSeamData> m_seam_per_object;
|
||||
|
||||
void init(const Print &print, std::function<void(void)> throw_if_canceled_func);
|
||||
void init(const Print &print, std::function<void(void)> throw_if_canceled_func);
|
||||
|
||||
void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const;
|
||||
void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const;
|
||||
|
||||
private:
|
||||
void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info);
|
||||
void calculate_candidates_visibility(const PrintObject *po,
|
||||
const SeamPlacerImpl::GlobalModelInfo &global_model_info);
|
||||
void calculate_overhangs_and_layer_embedding(const PrintObject *po);
|
||||
void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator);
|
||||
std::vector<std::pair<size_t, size_t>> find_seam_string(const PrintObject *po,
|
||||
std::pair<size_t, size_t> start_seam,
|
||||
const SeamPlacerImpl::SeamComparator &comparator) const;
|
||||
std::optional<std::pair<size_t, size_t>> find_next_seam_in_layer(
|
||||
const std::vector<PrintObjectSeamData::LayerSeams> &layers,
|
||||
const Vec3f& projected_position,
|
||||
const size_t layer_idx, const float max_distance,
|
||||
const SeamPlacerImpl::SeamComparator &comparator) const;
|
||||
void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference);
|
||||
void calculate_candidates_visibility(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info);
|
||||
void calculate_overhangs_and_layer_embedding(const PrintObject *po);
|
||||
void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator);
|
||||
std::vector<std::pair<size_t, size_t>> find_seam_string(const PrintObject *po, std::pair<size_t, size_t> start_seam, const SeamPlacerImpl::SeamComparator &comparator) const;
|
||||
std::optional<std::pair<size_t, size_t>> find_next_seam_in_layer(const std::vector<PrintObjectSeamData::LayerSeams> &layers,
|
||||
const Vec3f & projected_position,
|
||||
const size_t layer_idx,
|
||||
const float max_distance,
|
||||
const SeamPlacerImpl::SeamComparator & comparator) const;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -388,6 +388,11 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
it_per_layer_extruder_override = per_layer_extruder_switches.begin();
|
||||
unsigned int extruder_override = 0;
|
||||
|
||||
// BBS: collect first layer extruders of an object's wall, which will be used by brim generator
|
||||
int layerCount = 0;
|
||||
std::vector<int> firstLayerExtruders;
|
||||
firstLayerExtruders.clear();
|
||||
|
||||
// Collect the object extruders.
|
||||
for (auto layer : object.layers()) {
|
||||
LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
|
||||
@@ -413,8 +418,12 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
something_nonoverriddable = true;
|
||||
}
|
||||
|
||||
if (something_nonoverriddable)
|
||||
if (something_nonoverriddable){
|
||||
layer_tools.extruders.emplace_back((extruder_override == 0) ? region.config().wall_filament.value : extruder_override);
|
||||
if (layerCount == 0) {
|
||||
firstLayerExtruders.emplace_back((extruder_override == 0) ? region.config().wall_filament.value : extruder_override);
|
||||
}
|
||||
}
|
||||
|
||||
layer_tools.has_object = true;
|
||||
}
|
||||
@@ -449,8 +458,12 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
if (has_solid_infill || has_infill)
|
||||
layer_tools.has_object = true;
|
||||
}
|
||||
layerCount++;
|
||||
}
|
||||
|
||||
sort_remove_duplicates(firstLayerExtruders);
|
||||
const_cast<PrintObject&>(object).object_first_layer_wall_extruders = firstLayerExtruders;
|
||||
|
||||
for (auto& layer : m_layer_tools) {
|
||||
// Sort and remove duplicates
|
||||
sort_remove_duplicates(layer.extruders);
|
||||
@@ -1027,8 +1040,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
if (!object->config().flush_into_infill && !object->config().flush_into_objects && !object->config().flush_into_support)
|
||||
continue;
|
||||
bool wipe_into_infill_only = !object->config().flush_into_objects && object->config().flush_into_infill;
|
||||
bool is_infill_first = print.default_region_config().wall_infill_order == WallInfillOrder::InfillInnerOuter ||
|
||||
print.default_region_config().wall_infill_order == WallInfillOrder::InfillOuterInner;
|
||||
bool is_infill_first = print.config().is_infill_first;
|
||||
if (is_infill_first != perimeters_done || wipe_into_infill_only) {
|
||||
for (const ExtrusionEntity* ee : layerm->fills.entities) { // iterate through all infill Collections
|
||||
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
@@ -1082,7 +1094,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
break;
|
||||
|
||||
auto &entities = this_support_layer->support_fills.entities;
|
||||
if (support_overriddable && !is_support_overridden(object)) {
|
||||
if (support_overriddable && !is_support_overridden(object) && !(object_config.support_interface_not_for_body.value && !support_intf_overriddable &&(new_extruder==object_config.support_interface_filament-1||old_extruder==object_config.support_interface_filament-1))) {
|
||||
set_support_extruder_override(object, copy, new_extruder, num_of_copies);
|
||||
for (const ExtrusionEntity* ee : entities) {
|
||||
if (ee->role() == erSupportMaterial || ee->role() == erSupportTransition)
|
||||
@@ -1141,8 +1153,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
if (!object->config().flush_into_infill && !object->config().flush_into_objects)
|
||||
continue;
|
||||
|
||||
bool is_infill_first = print.default_region_config().wall_infill_order == WallInfillOrder::InfillInnerOuter ||
|
||||
print.default_region_config().wall_infill_order == WallInfillOrder::InfillOuterInner;
|
||||
bool is_infill_first = print.config().is_infill_first;
|
||||
for (const ExtrusionEntity* ee : layerm->fills.entities) { // iterate through all infill Collections
|
||||
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
|
||||
|
||||
@@ -770,6 +770,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
"; CP TOOLCHANGE START\n")
|
||||
.comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
|
||||
|
||||
|
||||
if (tool != (unsigned)(-1))
|
||||
writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str())
|
||||
.append(";--------------------\n");
|
||||
@@ -787,6 +788,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
if (tool != (unsigned int)-1){ // This is not the last change.
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
|
||||
toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material,
|
||||
is_first_layer() ? m_filpar[tool].nozzle_temperature_initial_layer : m_filpar[tool].nozzle_temperature);
|
||||
toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
@@ -806,8 +808,8 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
writer.travel(Vec2f(0, 0));
|
||||
writer.travel(initial_position);
|
||||
}
|
||||
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_length); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
++ m_num_tool_changes;
|
||||
} else
|
||||
toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature);
|
||||
@@ -1185,6 +1187,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
.set_initial_tool(m_current_tool)
|
||||
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
|
||||
|
||||
// Slow down on the 1st layer.
|
||||
bool first_layer = is_first_layer();
|
||||
@@ -1324,6 +1327,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
writer.add_wipe_point(writer.pos())
|
||||
.add_wipe_point(target);
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
@@ -1601,6 +1605,9 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
|
||||
// BBS
|
||||
//m_internal_rotation += 180.f;
|
||||
|
||||
if (m_layer_info->depth < m_perimeter_width)
|
||||
continue;
|
||||
|
||||
if (m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width) {
|
||||
// align y shift to perimeter width
|
||||
float dy = m_extra_spacing * m_perimeter_width;
|
||||
@@ -1687,7 +1694,7 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall()
|
||||
// BBS: Delete some unnecessary travel
|
||||
//if (writer.x() > fill_box.ld.x() + EPSILON) writer.travel(fill_box.ld.x(), writer.y());
|
||||
//if (writer.y() > fill_box.ld.y() + EPSILON) writer.travel(writer.x(), fill_box.ld.y());
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
|
||||
// outer perimeter (always):
|
||||
// BBS
|
||||
box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
|
||||
@@ -1698,6 +1705,8 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall()
|
||||
Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld)));
|
||||
writer.add_wipe_point(writer.pos()).add_wipe_point(target);
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (!m_no_sparse_layers || toolchanges_on_layer)
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
#include "JumpPointSearch.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "libslic3r/AStar.hpp"
|
||||
#include "libslic3r/KDTreeIndirect.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <oneapi/tbb/scalable_allocator.h>
|
||||
|
||||
//#define DEBUG_FILES
|
||||
#ifdef DEBUG_FILES
|
||||
#include "libslic3r/SVG.hpp"
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// execute fn for each pixel on the line. If fn returns false, terminate the iteration
|
||||
template<typename PointFn> void dda(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
|
||||
{
|
||||
coord_t dx = abs(x1 - x0);
|
||||
coord_t dy = abs(y1 - y0);
|
||||
coord_t x = x0;
|
||||
coord_t y = y0;
|
||||
coord_t n = 1 + dx + dy;
|
||||
coord_t x_inc = (x1 > x0) ? 1 : -1;
|
||||
coord_t y_inc = (y1 > y0) ? 1 : -1;
|
||||
coord_t error = dx - dy;
|
||||
dx *= 2;
|
||||
dy *= 2;
|
||||
|
||||
for (; n > 0; --n) {
|
||||
if (!fn(x, y)) return;
|
||||
|
||||
if (error > 0) {
|
||||
x += x_inc;
|
||||
error -= dy;
|
||||
} else {
|
||||
y += y_inc;
|
||||
error += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will draw the line twice, second time with and offset of 1 in the direction of normal
|
||||
// may call the fn on the same coordiantes multiple times!
|
||||
template<typename PointFn> void double_dda_with_offset(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
|
||||
{
|
||||
Vec2d normal = Point{y1 - y0, x1 - x0}.cast<double>().normalized();
|
||||
normal.x() = ceil(normal.x());
|
||||
normal.y() = ceil(normal.y());
|
||||
Point start_offset = Point(x0, y0) + (normal).cast<coord_t>();
|
||||
Point end_offset = Point(x1, y1) + (normal).cast<coord_t>();
|
||||
|
||||
dda(x0, y0, x1, y1, fn);
|
||||
dda(start_offset.x(), start_offset.y(), end_offset.x(), end_offset.y(), fn);
|
||||
}
|
||||
|
||||
template<typename CellPositionType, typename CellQueryFn> class JPSTracer
|
||||
{
|
||||
public:
|
||||
// Use incoming_dir [0,0] for starting points, so that all directions are checked from that point
|
||||
struct Node
|
||||
{
|
||||
CellPositionType position;
|
||||
CellPositionType incoming_dir;
|
||||
};
|
||||
|
||||
JPSTracer(CellPositionType target, CellQueryFn is_passable) : target(target), is_passable(is_passable) {}
|
||||
|
||||
private:
|
||||
CellPositionType target;
|
||||
CellQueryFn is_passable; // should return boolean whether the cell is passable or not
|
||||
|
||||
CellPositionType find_jump_point(CellPositionType start, CellPositionType forward_dir) const
|
||||
{
|
||||
CellPositionType next = start + forward_dir;
|
||||
while (next != target && is_passable(next) && !(is_jump_point(next, forward_dir))) { next = next + forward_dir; }
|
||||
|
||||
if (is_passable(next)) {
|
||||
return next;
|
||||
} else {
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_jump_point(CellPositionType pos, CellPositionType forward_dir) const
|
||||
{
|
||||
if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) {
|
||||
// diagonal
|
||||
CellPositionType horizontal_check_dir = CellPositionType{forward_dir.x(), 0};
|
||||
CellPositionType vertical_check_dir = CellPositionType{0, forward_dir.y()};
|
||||
|
||||
if (!is_passable(pos - horizontal_check_dir) && is_passable(pos + forward_dir - 2 * horizontal_check_dir)) { return true; }
|
||||
|
||||
if (!is_passable(pos - vertical_check_dir) && is_passable(pos + forward_dir - 2 * vertical_check_dir)) { return true; }
|
||||
|
||||
if (find_jump_point(pos, horizontal_check_dir) != pos) { return true; }
|
||||
|
||||
if (find_jump_point(pos, vertical_check_dir) != pos) { return true; }
|
||||
|
||||
return false;
|
||||
} else { // horizontal or vertical
|
||||
CellPositionType side_dir = CellPositionType(forward_dir.y(), forward_dir.x());
|
||||
|
||||
if (!is_passable(pos + side_dir) && is_passable(pos + forward_dir + side_dir)) { return true; }
|
||||
|
||||
if (!is_passable(pos - side_dir) && is_passable(pos + forward_dir - side_dir)) { return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<class Fn> void foreach_reachable(const Node &from, Fn &&fn) const
|
||||
{
|
||||
const CellPositionType & pos = from.position;
|
||||
const CellPositionType & forward_dir = from.incoming_dir;
|
||||
std::vector<CellPositionType> dirs_to_check{};
|
||||
|
||||
if (abs(forward_dir.x()) + abs(forward_dir.y()) == 0) { // special case for starting point
|
||||
dirs_to_check = all_directions;
|
||||
} else if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) {
|
||||
// diagonal
|
||||
CellPositionType horizontal_check_dir = CellPositionType{forward_dir.x(), 0};
|
||||
CellPositionType vertical_check_dir = CellPositionType{0, forward_dir.y()};
|
||||
|
||||
if (!is_passable(pos - horizontal_check_dir) && is_passable(pos + forward_dir - 2 * horizontal_check_dir)) {
|
||||
dirs_to_check.push_back(forward_dir - 2 * horizontal_check_dir);
|
||||
}
|
||||
|
||||
if (!is_passable(pos - vertical_check_dir) && is_passable(pos + forward_dir - 2 * vertical_check_dir)) {
|
||||
dirs_to_check.push_back(forward_dir - 2 * vertical_check_dir);
|
||||
}
|
||||
|
||||
dirs_to_check.push_back(horizontal_check_dir);
|
||||
dirs_to_check.push_back(vertical_check_dir);
|
||||
dirs_to_check.push_back(forward_dir);
|
||||
|
||||
} else { // horizontal or vertical
|
||||
CellPositionType side_dir = CellPositionType(forward_dir.y(), forward_dir.x());
|
||||
|
||||
if (!is_passable(pos + side_dir) && is_passable(pos + forward_dir + side_dir)) { dirs_to_check.push_back(forward_dir + side_dir); }
|
||||
|
||||
if (!is_passable(pos - side_dir) && is_passable(pos + forward_dir - side_dir)) { dirs_to_check.push_back(forward_dir - side_dir); }
|
||||
dirs_to_check.push_back(forward_dir);
|
||||
}
|
||||
|
||||
for (const CellPositionType &dir : dirs_to_check) {
|
||||
CellPositionType jp = find_jump_point(pos, dir);
|
||||
if (jp != pos) fn(Node{jp, dir});
|
||||
}
|
||||
}
|
||||
|
||||
float distance(Node a, Node b) const { return (a.position - b.position).template cast<double>().norm(); }
|
||||
|
||||
float goal_heuristic(Node n) const { return n.position == target ? -1.f : (target - n.position).template cast<double>().norm(); }
|
||||
|
||||
size_t unique_id(Node n) const { return (static_cast<size_t>(uint16_t(n.position.x())) << 16) + static_cast<size_t>(uint16_t(n.position.y())); }
|
||||
|
||||
const std::vector<CellPositionType> all_directions{{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};
|
||||
};
|
||||
|
||||
void JPSPathFinder::clear()
|
||||
{
|
||||
inpassable.clear();
|
||||
max_search_box.max = Pixel(std::numeric_limits<coord_t>::min(), std::numeric_limits<coord_t>::min());
|
||||
max_search_box.min = Pixel(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max());
|
||||
add_obstacles(bed_shape);
|
||||
}
|
||||
|
||||
void JPSPathFinder::add_obstacles(const Lines &obstacles)
|
||||
{
|
||||
auto store_obstacle = [&](coord_t x, coord_t y) {
|
||||
max_search_box.max.x() = std::max(max_search_box.max.x(), x);
|
||||
max_search_box.max.y() = std::max(max_search_box.max.y(), y);
|
||||
max_search_box.min.x() = std::min(max_search_box.min.x(), x);
|
||||
max_search_box.min.y() = std::min(max_search_box.min.y(), y);
|
||||
inpassable.insert(Pixel{x, y});
|
||||
return true;
|
||||
};
|
||||
|
||||
for (const Line &l : obstacles) {
|
||||
Pixel start = pixelize(l.a);
|
||||
Pixel end = pixelize(l.b);
|
||||
double_dda_with_offset(start.x(), start.y(), end.x(), end.y(), store_obstacle);
|
||||
}
|
||||
}
|
||||
|
||||
Polyline JPSPathFinder::find_path(const Point &p0, const Point &p1)
|
||||
{
|
||||
Pixel start = pixelize(p0);
|
||||
Pixel end = pixelize(p1);
|
||||
if (inpassable.empty() || (start - end).cast<float>().norm() < 3.0) { return Polyline{p0, p1}; }
|
||||
|
||||
if (inpassable.find(start) != inpassable.end()) {
|
||||
dda(start.x(), start.y(), end.x(), end.y(), [&](coord_t x, coord_t y) {
|
||||
if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
|
||||
start = Pixel(x, y);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (inpassable.find(end) != inpassable.end()) {
|
||||
dda(end.x(), end.y(), start.x(), start.y(), [&](coord_t x, coord_t y) {
|
||||
if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
|
||||
end = Pixel(x, y);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
BoundingBox search_box = max_search_box;
|
||||
search_box.max -= Pixel(1, 1);
|
||||
search_box.min += Pixel(1, 1);
|
||||
|
||||
BoundingBox bounding_square(Points{start, end});
|
||||
bounding_square.max += Pixel(5, 5);
|
||||
bounding_square.min -= Pixel(5, 5);
|
||||
coord_t bounding_square_size = 2 * std::max(bounding_square.size().x(), bounding_square.size().y());
|
||||
bounding_square.max.x() += (bounding_square_size - bounding_square.size().x()) / 2;
|
||||
bounding_square.min.x() -= (bounding_square_size - bounding_square.size().x()) / 2;
|
||||
bounding_square.max.y() += (bounding_square_size - bounding_square.size().y()) / 2;
|
||||
bounding_square.min.y() -= (bounding_square_size - bounding_square.size().y()) / 2;
|
||||
|
||||
// Intersection - limit the search box to a square area around the start and end, to fasten the path searching
|
||||
search_box.max = search_box.max.cwiseMin(bounding_square.max);
|
||||
search_box.min = search_box.min.cwiseMax(bounding_square.min);
|
||||
|
||||
auto cell_query = [&](Pixel pixel) { return search_box.contains(pixel) && (pixel == start || pixel == end || inpassable.find(pixel) == inpassable.end()); };
|
||||
|
||||
JPSTracer<Pixel, decltype(cell_query)> tracer(end, cell_query);
|
||||
using QNode = astar::QNode<JPSTracer<Pixel, decltype(cell_query)>>;
|
||||
|
||||
std::unordered_map<size_t, QNode> astar_cache{};
|
||||
std::vector<Pixel> out_path;
|
||||
std::vector<decltype(tracer)::Node> out_nodes;
|
||||
|
||||
if (!astar::search_route(tracer, {start, {0, 0}}, std::back_inserter(out_nodes), astar_cache)) {
|
||||
// path not found - just reconstruct the best path from astar cache.
|
||||
// Note that astar_cache is NOT empty - at least the starting point should always be there
|
||||
auto coordiante_func = [&astar_cache](size_t idx, size_t dim) { return float(astar_cache[idx].node.position[dim]); };
|
||||
std::vector<size_t> keys;
|
||||
keys.reserve(astar_cache.size());
|
||||
for (const auto &pair : astar_cache) { keys.push_back(pair.first); }
|
||||
KDTreeIndirect<2, float, decltype(coordiante_func)> kd_tree(coordiante_func, keys);
|
||||
size_t closest_qnode = find_closest_point(kd_tree, end.cast<float>());
|
||||
|
||||
out_path.push_back(end);
|
||||
while (closest_qnode != astar::Unassigned) {
|
||||
out_path.push_back(astar_cache[closest_qnode].node.position);
|
||||
closest_qnode = astar_cache[closest_qnode].parent;
|
||||
}
|
||||
} else {
|
||||
for (const auto &node : out_nodes) { out_path.push_back(node.position); }
|
||||
out_path.push_back(start);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
auto scaled_points = [](const Points &ps) {
|
||||
Points r;
|
||||
for (const Point &p : ps) { r.push_back(Point::new_scale(p.x(), p.y())); }
|
||||
return r;
|
||||
};
|
||||
auto scaled_point = [](const Point &p) { return Point::new_scale(p.x(), p.y()); };
|
||||
::Slic3r::SVG svg(debug_out_path(("path_jps" + std::to_string(print_z) + "_" + std::to_string(rand() % 1000)).c_str()).c_str(),
|
||||
BoundingBox(scaled_point(search_box.min), scaled_point(search_box.max)));
|
||||
for (const auto &p : inpassable) { svg.draw(scaled_point(p), "black", scale_(0.4)); }
|
||||
for (const auto &qn : astar_cache) { svg.draw(scaled_point(qn.second.node.position), "blue", scale_(0.3)); }
|
||||
svg.draw(Polyline(scaled_points(out_path)), "yellow", scale_(0.25));
|
||||
svg.draw(scaled_point(end), "purple", scale_(0.4));
|
||||
svg.draw(scaled_point(start), "green", scale_(0.4));
|
||||
#endif
|
||||
|
||||
std::vector<Pixel> tmp_path;
|
||||
tmp_path.reserve(out_path.size());
|
||||
// Some path found, reverse and remove points that do not change direction
|
||||
std::reverse(out_path.begin(), out_path.end());
|
||||
{
|
||||
tmp_path.push_back(out_path.front()); // first point
|
||||
for (size_t i = 1; i < out_path.size() - 1; i++) {
|
||||
if ((out_path[i] - out_path[i - 1]).cast<float>().normalized() != (out_path[i + 1] - out_path[i]).cast<float>().normalized()) { tmp_path.push_back(out_path[i]); }
|
||||
}
|
||||
tmp_path.push_back(out_path.back()); // last_point
|
||||
out_path = tmp_path;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
svg.draw(Polyline(scaled_points(out_path)), "orange", scale_(0.20));
|
||||
#endif
|
||||
|
||||
tmp_path.clear();
|
||||
// remove redundant jump points - there are points that change direction but are not needed - this inefficiency arises from the
|
||||
// usage of grid search The removal alg tries to find the longest Px Px+k path without obstacles. If Px Px+k+1 is blocked, it will
|
||||
// insert the Px+k point to result and continue search from Px+k
|
||||
{
|
||||
tmp_path.push_back(out_path.front()); // first point
|
||||
size_t index_of_last_stored_point = 0;
|
||||
for (size_t i = 1; i < out_path.size(); i++) {
|
||||
if (i - index_of_last_stored_point < 2) continue;
|
||||
bool passable = true;
|
||||
auto store_obstacle = [&](coord_t x, coord_t y) {
|
||||
if (Pixel(x, y) != start && Pixel(x, y) != end && inpassable.find(Pixel(x, y)) != inpassable.end()) {
|
||||
passable = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
dda(tmp_path.back().x(), tmp_path.back().y(), out_path[i].x(), out_path[i].y(), store_obstacle);
|
||||
if (!passable) {
|
||||
tmp_path.push_back(out_path[i - 1]);
|
||||
index_of_last_stored_point = i - 1;
|
||||
}
|
||||
}
|
||||
tmp_path.push_back(out_path.back()); // last_point
|
||||
out_path = tmp_path;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
svg.draw(Polyline(scaled_points(out_path)), "red", scale_(0.15));
|
||||
svg.Close();
|
||||
#endif
|
||||
|
||||
// before returing the path, transform it from pixels back to points.
|
||||
// Also replace the first and last pixel by input points so that result path patches input params exactly.
|
||||
for (Pixel &p : out_path) { p = unpixelize(p); }
|
||||
out_path.front() = p0;
|
||||
out_path.back() = p1;
|
||||
|
||||
return Polyline(out_path);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#ifndef SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_
|
||||
#define SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_
|
||||
|
||||
#include "BoundingBox.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class JPSPathFinder
|
||||
{
|
||||
using Pixel = Point;
|
||||
std::unordered_set<Pixel, PointHash> inpassable;
|
||||
coordf_t print_z;
|
||||
BoundingBox max_search_box;
|
||||
Lines bed_shape;
|
||||
|
||||
const coord_t resolution = scaled(1.5);
|
||||
Pixel pixelize(const Point &p) { return p / resolution; }
|
||||
Point unpixelize(const Pixel &p) { return p * resolution; }
|
||||
|
||||
public:
|
||||
JPSPathFinder() = default;
|
||||
void init_bed_shape(const Points &bed_shape) { this->bed_shape = (to_lines(Polygon{bed_shape})); };
|
||||
void clear();
|
||||
void add_obstacles(const Lines &obstacles);
|
||||
Polyline find_path(const Point &start, const Point &end);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_ */
|
||||
@@ -179,7 +179,6 @@ void Layer::make_perimeters()
|
||||
&& config.opt_serialize("inner_wall_line_width") == other_config.opt_serialize("inner_wall_line_width")
|
||||
&& config.opt_serialize("outer_wall_line_width") == other_config.opt_serialize("outer_wall_line_width")
|
||||
&& config.detect_thin_wall == other_config.detect_thin_wall
|
||||
//&& config.wall_infill_order == other_config.wall_infill_order
|
||||
&& config.infill_wall_overlap == other_config.infill_wall_overlap
|
||||
&& config.fuzzy_skin == other_config.fuzzy_skin
|
||||
&& config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness
|
||||
|
||||
@@ -277,6 +277,7 @@ public:
|
||||
|
||||
// for tree supports
|
||||
ExPolygons base_areas;
|
||||
ExPolygons overhang_areas;
|
||||
|
||||
|
||||
// Is there any valid extrusion assigned to this LayerRegion?
|
||||
@@ -300,7 +301,6 @@ protected:
|
||||
size_t m_interface_id;
|
||||
|
||||
// for tree support
|
||||
ExPolygons overhang_areas;
|
||||
ExPolygons roof_areas;
|
||||
ExPolygons roof_1st_layer; // the layer just below roof. When working with PolySupport, this layer should be printed with regular material
|
||||
ExPolygons floor_areas;
|
||||
@@ -312,6 +312,7 @@ protected:
|
||||
int type;
|
||||
coordf_t dist_to_top; // mm dist to top
|
||||
bool need_infill = false;
|
||||
bool need_extra_wall = false;
|
||||
AreaGroup(ExPolygon *a, int t, coordf_t d) : area(a), type(t), dist_to_top(d) {}
|
||||
};
|
||||
enum OverhangType { Detected = 0, Enforced };
|
||||
|
||||
@@ -223,6 +223,12 @@ indexed_triangle_set cgal_to_indexed_triangle_set(const _Mesh &cgalmesh)
|
||||
return its;
|
||||
}
|
||||
|
||||
template<class _Mesh> TriangleMesh cgal_to_triangle_mesh(const _Mesh &cgalmesh)
|
||||
{
|
||||
indexed_triangle_set its = cgal_to_indexed_triangle_set(cgalmesh);
|
||||
return TriangleMesh(std::move(its));
|
||||
}
|
||||
|
||||
std::unique_ptr<CGALMesh, CGALMeshDeleter>
|
||||
triangle_mesh_to_cgal(const std::vector<stl_vertex> &V,
|
||||
const std::vector<stl_triangle_vertex_indices> &F)
|
||||
|
||||
@@ -97,9 +97,14 @@ Model& Model::assign_copy(const Model &rhs)
|
||||
);
|
||||
}
|
||||
|
||||
if (rhs.calib_pa_pattern) {
|
||||
this->calib_pa_pattern = std::make_unique<CalibPressureAdvancePattern>(CalibPressureAdvancePattern(*rhs.calib_pa_pattern));
|
||||
}
|
||||
|
||||
// BBS: for design info
|
||||
this->design_info = rhs.design_info;
|
||||
this->model_info = rhs.model_info;
|
||||
this->stl_design_id = rhs.stl_design_id;
|
||||
this->profile_info = rhs.profile_info;
|
||||
|
||||
return *this;
|
||||
@@ -130,6 +135,7 @@ Model& Model::assign_copy(Model &&rhs)
|
||||
|
||||
//BBS: add auxiliary path logic
|
||||
// BBS: backup, all in one temp dir
|
||||
this->stl_design_id = rhs.stl_design_id;
|
||||
this->backup_path = std::move(rhs.backup_path);
|
||||
this->object_backup_id_map = std::move(rhs.object_backup_id_map);
|
||||
this->next_object_backup_id = rhs.next_object_backup_id;
|
||||
@@ -927,6 +933,7 @@ void Model::load_from(Model& model)
|
||||
object_backup_id_map = model.object_backup_id_map;
|
||||
next_object_backup_id = model.next_object_backup_id;
|
||||
design_info = model.design_info;
|
||||
stl_design_id = model.stl_design_id;
|
||||
model_info = model.model_info;
|
||||
profile_info = model.profile_info;
|
||||
model.design_info.reset();
|
||||
|
||||
+12
-1
@@ -245,6 +245,11 @@ private:
|
||||
friend class ModelObject;
|
||||
};
|
||||
|
||||
enum class CutMode : int {
|
||||
cutPlanar,
|
||||
cutTongueAndGroove
|
||||
};
|
||||
|
||||
enum class CutConnectorType : int {
|
||||
Plug
|
||||
, Dowel
|
||||
@@ -267,6 +272,11 @@ enum class CutConnectorShape : int {
|
||||
, Undef
|
||||
//,D-shape
|
||||
};
|
||||
struct CutConnectorParas
|
||||
{
|
||||
float snap_space_proportion{0.3};
|
||||
float snap_bulge_proportion{0.15};
|
||||
};
|
||||
|
||||
struct CutConnectorAttributes
|
||||
{
|
||||
@@ -904,8 +914,8 @@ public:
|
||||
bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; }
|
||||
bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; }
|
||||
t_model_material_id material_id() const { return m_material_id; }
|
||||
void reset_extra_facets();
|
||||
void set_material_id(t_model_material_id material_id);
|
||||
void reset_extra_facets();
|
||||
ModelMaterial* material() const;
|
||||
void set_material(t_model_material_id material_id, const ModelMaterial &material);
|
||||
// Extract the current extruder ID based on this ModelVolume's config and the parent ModelObject's config.
|
||||
@@ -1488,6 +1498,7 @@ public:
|
||||
static GlobalSpeedMap printSpeedMap;
|
||||
|
||||
// DesignInfo of Model
|
||||
std::string stl_design_id;
|
||||
std::shared_ptr<ModelDesignInfo> design_info = nullptr;
|
||||
std::shared_ptr<ModelInfo> model_info = nullptr;
|
||||
std::shared_ptr<ModelProfileInfo> profile_info = nullptr;
|
||||
|
||||
@@ -1372,18 +1372,23 @@ static void remove_multiple_edges_in_vertices(MMU_Graph &graph, const std::vecto
|
||||
static void cut_segmented_layers(const std::vector<ExPolygons> &input_expolygons,
|
||||
std::vector<std::vector<ExPolygons>> &segmented_regions,
|
||||
const float cut_width,
|
||||
const float interlocking_depth,
|
||||
const std::function<void()> &throw_on_cancel_callback)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin";
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),[&segmented_regions, &input_expolygons, &cut_width, &throw_on_cancel_callback](const tbb::blocked_range<size_t>& range) {
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),
|
||||
[&segmented_regions, &input_expolygons, &cut_width, &interlocking_depth, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
|
||||
throw_on_cancel_callback();
|
||||
const size_t num_extruders_plus_one = segmented_regions[layer_idx].size();
|
||||
std::vector<ExPolygons> segmented_regions_cuts(num_extruders_plus_one); // Indexed by extruder_id
|
||||
for (size_t extruder_idx = 0; extruder_idx < num_extruders_plus_one; ++extruder_idx)
|
||||
if (const ExPolygons &ex_polygons = segmented_regions[layer_idx][extruder_idx]; !ex_polygons.empty())
|
||||
segmented_regions_cuts[extruder_idx] = diff_ex(ex_polygons, offset_ex(input_expolygons[layer_idx], cut_width));
|
||||
segmented_regions[layer_idx] = std::move(segmented_regions_cuts);
|
||||
const float region_cut_width = ((layer_idx % 2 == 0) && (interlocking_depth != 0.f)) ? interlocking_depth : cut_width;
|
||||
const size_t num_extruders_plus_one = segmented_regions[layer_idx].size();
|
||||
if (region_cut_width > 0.f) {
|
||||
std::vector<ExPolygons> segmented_regions_cuts(num_extruders_plus_one); // Indexed by extruder_id
|
||||
for (size_t extruder_idx = 0; extruder_idx < num_extruders_plus_one; ++extruder_idx)
|
||||
if (const ExPolygons &ex_polygons = segmented_regions[layer_idx][extruder_idx]; !ex_polygons.empty())
|
||||
segmented_regions_cuts[extruder_idx] = diff_ex(ex_polygons, offset_ex(input_expolygons[layer_idx], -region_cut_width));
|
||||
segmented_regions[layer_idx] = std::move(segmented_regions_cuts);
|
||||
}
|
||||
}
|
||||
}); // end of parallel_for
|
||||
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - end";
|
||||
@@ -1664,9 +1669,12 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
||||
self = union_ex(self);
|
||||
}
|
||||
// Trim one region by the other if some of the regions overlap.
|
||||
for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++ color_idx)
|
||||
triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx],
|
||||
triangles_by_color_merged[color_idx - 1][layer_idx]);
|
||||
ExPolygons painted_regions;
|
||||
for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
||||
triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx], painted_regions);
|
||||
append(painted_regions, triangles_by_color_merged[color_idx][layer_idx]);
|
||||
}
|
||||
triangles_by_color_merged[0][layer_idx] = diff_ex(triangles_by_color_merged[0][layer_idx], painted_regions);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2039,10 +2047,10 @@ std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(con
|
||||
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - end";
|
||||
throw_on_cancel_callback();
|
||||
|
||||
//if (auto w = print_object.config().mmu_segmented_region_max_width; w > 0.f) {
|
||||
// cut_segmented_layers(input_expolygons, segmented_regions, float(-scale_(w)), throw_on_cancel_callback);
|
||||
// throw_on_cancel_callback();
|
||||
//}
|
||||
if (auto max_width = print_object.config().mmu_segmented_region_max_width, interlocking_depth = print_object.config().mmu_segmented_region_interlocking_depth; max_width > 0.f || interlocking_depth > 0.f) {
|
||||
cut_segmented_layers(input_expolygons, segmented_regions, float(scale_(max_width)), float(scale_(interlocking_depth)), throw_on_cancel_callback);
|
||||
throw_on_cancel_callback();
|
||||
}
|
||||
|
||||
// The first index is extruder number (includes default extruder), and the second one is layer number
|
||||
std::vector<std::vector<ExPolygons>> top_and_bottom_layers = mmu_segmentation_top_and_bottom_layers(print_object, input_expolygons, throw_on_cancel_callback);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <type_traits>
|
||||
|
||||
constexpr auto InvalidQueueID = std::numeric_limits<size_t>::max();
|
||||
template<typename T, typename IndexSetter, typename LessPredicate, const bool ResetIndexWhenRemoved = false>
|
||||
class MutablePriorityQueue
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "ExtrusionEntityCollection.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "VariableWidth.hpp"
|
||||
#include "CurveAnalyzer.hpp"
|
||||
@@ -1495,12 +1496,18 @@ void PerimeterGenerator::process_classic()
|
||||
|
||||
// BBS: don't simplify too much which influence arc fitting when export gcode if arc_fitting is enabled
|
||||
double surface_simplify_resolution = (print_config->enable_arc_fitting && this->config->fuzzy_skin == FuzzySkinType::None) ? 0.2 * m_scaled_resolution : m_scaled_resolution;
|
||||
for (const Surface &surface : this->slices->surfaces) {
|
||||
//BBS: reorder the surface to reduce the travel time
|
||||
ExPolygons surface_exp;
|
||||
for (const Surface &surface : this->slices->surfaces)
|
||||
surface_exp.push_back(surface.expolygon);
|
||||
std::vector<size_t> surface_order = chain_expolygons(surface_exp);
|
||||
for (size_t order_idx = 0; order_idx < surface_order.size(); order_idx++) {
|
||||
const Surface &surface = this->slices->surfaces[surface_order[order_idx]];
|
||||
// detect how many perimeters must be generated for this island
|
||||
int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops
|
||||
if (this->layer_id == 0 && this->config->only_one_wall_first_layer)
|
||||
loop_number = 0;
|
||||
//BBS: set the topmost layer to be one wall
|
||||
// Set the topmost layer to be one wall
|
||||
if (loop_number > 0 && config->only_one_wall_top && this->upper_slices == nullptr)
|
||||
loop_number = 0;
|
||||
|
||||
@@ -1723,8 +1730,8 @@ void PerimeterGenerator::process_classic()
|
||||
// we continue inwards after having finished the brim
|
||||
// TODO: add test for perimeter order
|
||||
bool is_outer_wall_first =
|
||||
this->config->wall_infill_order == WallInfillOrder::OuterInnerInfill ||
|
||||
this->config->wall_infill_order == WallInfillOrder::InfillOuterInner;
|
||||
this->object_config->wall_sequence == WallSequence::OuterInner ||
|
||||
this->object_config->wall_sequence == WallSequence::InnerOuterInner;
|
||||
if (is_outer_wall_first ||
|
||||
//BBS: always print outer wall first when there indeed has brim.
|
||||
(this->layer_id == 0 &&
|
||||
@@ -1732,7 +1739,7 @@ void PerimeterGenerator::process_classic()
|
||||
this->object_config->brim_width.value > 0))
|
||||
entities.reverse();
|
||||
// SoftFever: sandwich mode
|
||||
else if (this->config->wall_infill_order == WallInfillOrder::InnerOuterInnerInfill)
|
||||
else if (this->object_config->wall_sequence == WallSequence::InnerOuterInner)
|
||||
if (entities.entities.size() > 1){
|
||||
int last_outer=0;
|
||||
int outer = 0;
|
||||
@@ -1862,6 +1869,39 @@ void PerimeterGenerator::process_classic()
|
||||
} // for each island
|
||||
}
|
||||
|
||||
//BBS:
|
||||
void PerimeterGenerator::add_infill_contour_for_arachne( ExPolygons infill_contour,
|
||||
int loops,
|
||||
coord_t ext_perimeter_spacing,
|
||||
coord_t perimeter_spacing,
|
||||
coord_t min_perimeter_infill_spacing,
|
||||
coord_t spacing,
|
||||
bool is_inner_part)
|
||||
{
|
||||
if( offset_ex(infill_contour, -float(spacing / 2.)).empty() )
|
||||
{
|
||||
infill_contour.clear(); // Infill region is too small, so let's filter it out.
|
||||
}
|
||||
|
||||
// create one more offset to be used as boundary for fill
|
||||
// we offset by half the perimeter spacing (to get to the actual infill boundary)
|
||||
// and then we offset back and forth by half the infill spacing to only consider the
|
||||
// non-collapsing regions
|
||||
coord_t insert = (loops < 0) ? 0: ext_perimeter_spacing;
|
||||
if (is_inner_part || loops > 0)
|
||||
insert = perimeter_spacing;
|
||||
|
||||
insert = coord_t(scale_(this->config->infill_wall_overlap.get_abs_value(unscale<double>(insert))));
|
||||
|
||||
Polygons inner_pp;
|
||||
for (ExPolygon &ex : infill_contour)
|
||||
ex.simplify_p(m_scaled_resolution, &inner_pp);
|
||||
|
||||
this->fill_surfaces->append(offset2_ex(union_ex(inner_pp), float(-min_perimeter_infill_spacing / 2.), float(insert + min_perimeter_infill_spacing / 2.)), stInternal);
|
||||
|
||||
append(*this->fill_no_overlap, offset2_ex(union_ex(inner_pp), float(-min_perimeter_infill_spacing / 2.), float(+min_perimeter_infill_spacing / 2.)));
|
||||
}
|
||||
|
||||
// Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper
|
||||
// "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling"
|
||||
void PerimeterGenerator::process_arachne()
|
||||
@@ -1973,7 +2013,7 @@ void PerimeterGenerator::process_arachne()
|
||||
}
|
||||
loop_number = int(perimeters.size()) - 1;
|
||||
|
||||
#ifdef ARACHNE_DEBUG
|
||||
#ifdef ARACHNE_DEBUG
|
||||
{
|
||||
static int iRun = 0;
|
||||
export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour()));
|
||||
@@ -1996,14 +2036,12 @@ void PerimeterGenerator::process_arachne()
|
||||
int direction = -1;
|
||||
|
||||
bool is_outer_wall_first =
|
||||
this->config->wall_infill_order == WallInfillOrder::OuterInnerInfill ||
|
||||
this->config->wall_infill_order == WallInfillOrder::InfillOuterInner ||
|
||||
this->config->wall_infill_order == WallInfillOrder::InnerOuterInnerInfill;
|
||||
this->object_config->wall_sequence == WallSequence::OuterInner ||
|
||||
this->object_config->wall_sequence == WallSequence::InnerOuterInner;
|
||||
|
||||
if (layer_id == 0){ // disable inner outer inner algorithm after the first layer
|
||||
is_outer_wall_first =
|
||||
this->config->wall_infill_order == WallInfillOrder::OuterInnerInfill ||
|
||||
this->config->wall_infill_order == WallInfillOrder::InfillOuterInner;
|
||||
this->object_config->wall_sequence == WallSequence::OuterInner;
|
||||
}
|
||||
if (is_outer_wall_first) {
|
||||
start_perimeter = 0;
|
||||
@@ -2242,8 +2280,9 @@ void PerimeterGenerator::process_arachne()
|
||||
this->loops->append(extrusion_coll);
|
||||
}
|
||||
|
||||
ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour());
|
||||
ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour());
|
||||
const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
||||
|
||||
if (offset_ex(infill_contour, -float(spacing / 2.)).empty())
|
||||
infill_contour.clear(); // Infill region is too small, so let's filter it out.
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ public:
|
||||
void process_classic();
|
||||
void process_arachne();
|
||||
|
||||
void add_infill_contour_for_arachne( ExPolygons infill_contour, int loops, coord_t ext_perimeter_spacing, coord_t perimeter_spacing, coord_t min_perimeter_infill_spacing, coord_t spacing, bool is_inner_part );
|
||||
|
||||
double ext_mm3_per_mm() const { return m_ext_mm3_per_mm; }
|
||||
double mm3_per_mm() const { return m_mm3_per_mm; }
|
||||
double mm3_per_mm_overhang() const { return m_mm3_per_mm_overhang; }
|
||||
|
||||
@@ -83,6 +83,7 @@ using Transform2d = Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAli
|
||||
using Transform3f = Eigen::Transform<float, 3, Eigen::Affine, Eigen::DontAlign>;
|
||||
using Transform3d = Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign>;
|
||||
|
||||
// using ColorRGBA = std::array<float, 4>;
|
||||
// I don't know why Eigen::Transform::Identity() return a const object...
|
||||
template<int N, class T> Transform<N, T> identity() { return Transform<N, T>::Identity(); }
|
||||
inline const auto &identity3f = identity<3, float>;
|
||||
|
||||
@@ -683,5 +683,4 @@ Polygon make_circle_num_segments(double radius, size_t num_segments)
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
+338
-78
@@ -518,6 +518,8 @@ void Preset::save(DynamicPrintConfig* parent_config)
|
||||
else
|
||||
from_str = std::string("Default");
|
||||
|
||||
boost::filesystem::create_directories(fs::path(this->file).parent_path());
|
||||
|
||||
//BBS: only save difference if it has parent
|
||||
if (parent_config) {
|
||||
DynamicPrintConfig temp_config;
|
||||
@@ -530,15 +532,36 @@ void Preset::save(DynamicPrintConfig* parent_config)
|
||||
opt_dst->set(opt_src);
|
||||
}
|
||||
temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string(), this->custom_defined);
|
||||
}
|
||||
else
|
||||
} else if (!filament_id.empty() && inherits().empty()) {
|
||||
DynamicPrintConfig temp_config = config;
|
||||
temp_config.set_key_value(BBL_JSON_KEY_FILAMENT_ID, new ConfigOptionString(filament_id));
|
||||
temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string(), this->custom_defined);
|
||||
} else {
|
||||
this->config.save_to_json(this->file, this->name, from_str, this->version.to_string(), this->custom_defined);
|
||||
}
|
||||
|
||||
fs::path idx_file(this->file);
|
||||
idx_file.replace_extension(".info");
|
||||
this->save_info(idx_file.string());
|
||||
}
|
||||
|
||||
void Preset::reload(Preset const &parent)
|
||||
{
|
||||
DynamicPrintConfig config;
|
||||
// BBS: change to json format
|
||||
// ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule);
|
||||
std::map<std::string, std::string> key_values;
|
||||
std::string reason;
|
||||
ForwardCompatibilitySubstitutionRule substitution_rule = ForwardCompatibilitySubstitutionRule::Disable;
|
||||
try {
|
||||
ConfigSubstitutions config_substitutions = config.load_from_json(file, substitution_rule, key_values, reason);
|
||||
this->config = parent.config;
|
||||
this->config.apply(std::move(config));
|
||||
} catch (const std::exception &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading the user-config file: %1%. Reason: %2%") % file % err.what();
|
||||
}
|
||||
}
|
||||
|
||||
// Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty.
|
||||
std::string Preset::label(bool no_alias) const
|
||||
{
|
||||
@@ -665,7 +688,7 @@ std::string Preset::get_printer_type(PresetBundle *preset_bundle)
|
||||
vendor_name = vendor_profile.first;
|
||||
return vendor_model.model_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -686,6 +709,25 @@ std::string Preset::get_current_printer_type(PresetBundle *preset_bundle)
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Preset::has_lidar(PresetBundle *preset_bundle)
|
||||
{
|
||||
bool has_lidar = false;
|
||||
if (preset_bundle) {
|
||||
auto config = &preset_bundle->printers.get_edited_preset().config;
|
||||
std::string vendor_name;
|
||||
for (auto vendor_profile : preset_bundle->vendors) {
|
||||
for (auto vendor_model : vendor_profile.second.models)
|
||||
if (vendor_model.name == config->opt_string("printer_model")) {
|
||||
vendor_name = vendor_profile.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!vendor_name.empty())
|
||||
has_lidar = vendor_name.compare("BBL") == 0 ? true : false;
|
||||
}
|
||||
return has_lidar;
|
||||
}
|
||||
|
||||
bool Preset::is_custom_defined()
|
||||
{
|
||||
if (custom_defined == "1")
|
||||
@@ -706,7 +748,7 @@ BedType Preset::get_default_bed_type(PresetBundle* preset_bundle)
|
||||
}
|
||||
|
||||
std::string model_id = this->get_printer_type(preset_bundle);
|
||||
if (model_id == "BL-P001" || model_id == "BL-P002") {
|
||||
if (model_id == "BL-P001" || model_id == "BL-P002" || model_id == "C13") {
|
||||
return BedType::btPC;
|
||||
} else if (model_id == "C11") {
|
||||
return BedType::btPEI;
|
||||
@@ -717,7 +759,7 @@ BedType Preset::get_default_bed_type(PresetBundle* preset_bundle)
|
||||
bool Preset::has_cali_lines(PresetBundle* preset_bundle)
|
||||
{
|
||||
std::string model_id = this->get_printer_type(preset_bundle);
|
||||
if (model_id == "BL-P001" || model_id == "BL-P002") {
|
||||
if (model_id == "BL-P001" || model_id == "BL-P002" || model_id == "C13") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -727,7 +769,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"layer_height", "initial_layer_print_height", "wall_loops", "slice_closing_radius", "spiral_mode", "slicing_mode",
|
||||
"top_shell_layers", "top_shell_thickness", "bottom_shell_layers", "bottom_shell_thickness",
|
||||
"extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold","overhang_reverse_internal_only",
|
||||
"seam_position", "staggered_inner_seams", "wall_infill_order", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern",
|
||||
"seam_position", "staggered_inner_seams", "wall_sequence", "is_infill_first", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern",
|
||||
"infill_direction",
|
||||
"minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern",
|
||||
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle",
|
||||
@@ -746,7 +788,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"support_interface_pattern", "support_interface_spacing", "support_interface_loop_pattern",
|
||||
"support_top_z_distance", "support_on_build_plate_only","support_critical_regions_only", "bridge_no_support", "thick_bridges", "max_bridge_length", "print_sequence", "support_remove_small_overhang",
|
||||
"filename_format", "wall_filament", "support_bottom_z_distance",
|
||||
"sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament",
|
||||
"sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament","support_interface_not_for_body",
|
||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width",
|
||||
"inner_wall_line_width", "outer_wall_line_width", "sparse_infill_line_width", "internal_solid_infill_line_width",
|
||||
"top_surface_line_width", "support_line_width", "infill_wall_overlap", "bridge_flow", "internal_bridge_flow",
|
||||
@@ -774,7 +816,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes",
|
||||
"wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extruder", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming",
|
||||
"wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic",
|
||||
"hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted"
|
||||
"hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth",
|
||||
};
|
||||
|
||||
static std::vector<std::string> s_Preset_filament_options {
|
||||
@@ -819,7 +861,7 @@ static std::vector<std::string> s_Preset_printer_options {
|
||||
"printer_technology",
|
||||
"printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor",
|
||||
"fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs",
|
||||
"single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "change_extrusion_role_gcode",
|
||||
"single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "change_extrusion_role_gcode",
|
||||
"printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
|
||||
"default_print_profile", "inherits",
|
||||
"silent_mode",
|
||||
@@ -1018,8 +1060,13 @@ void PresetCollection::load_presets(
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/732
|
||||
boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
|
||||
// Load custom roots first
|
||||
if (fs::exists(dir / "base")) {
|
||||
load_presets(dir.string(), "base", substitutions, substitution_rule);
|
||||
}
|
||||
|
||||
//BBS: add config related logs
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, load presets from %1%, current type %2%")%dir %Preset::get_type_string(m_type);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, load presets from %1%, current type %2%")%dir %Preset::get_type_string(m_type);
|
||||
//BBS do not parse folder if not exists
|
||||
m_dir_path = dir.string();
|
||||
if (!fs::exists(dir)) {
|
||||
@@ -1084,8 +1131,12 @@ void PresetCollection::load_presets(
|
||||
}
|
||||
preset.version = *version;
|
||||
|
||||
if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end())
|
||||
preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID];
|
||||
if (key_values.find(BBL_JSON_KEY_IS_CUSTOM) != key_values.end())
|
||||
preset.custom_defined = key_values[BBL_JSON_KEY_IS_CUSTOM];
|
||||
if (key_values.find("instantiation") != key_values.end())
|
||||
preset.is_visible = key_values["instantiation"] != "false";
|
||||
|
||||
//BBS: use inherit config as the base
|
||||
Preset* inherit_preset = nullptr;
|
||||
@@ -1105,12 +1156,12 @@ void PresetCollection::load_presets(
|
||||
preset.filament_id = inherit_preset->filament_id;
|
||||
}
|
||||
else {
|
||||
if (!preset.is_custom_defined()) {
|
||||
// We support custom root preset now
|
||||
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(inherits_config);
|
||||
if ((inherits_config2 && !inherits_config2->value.empty()) && !preset.is_custom_defined()) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent for config %1%!")%preset.file;
|
||||
continue;
|
||||
}
|
||||
//should not happen
|
||||
//BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent for config %1%!")%preset.file;
|
||||
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
|
||||
preset.config = default_preset.config;
|
||||
}
|
||||
@@ -1147,6 +1198,7 @@ void PresetCollection::load_presets(
|
||||
fs::remove(file_path);
|
||||
}
|
||||
presets_loaded.emplace_back(preset);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " load config successful and preset name is:" << preset.name;
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
@@ -1219,16 +1271,26 @@ int PresetCollection::get_differed_values_to_update(Preset& preset, std::map<std
|
||||
if (opt_src)
|
||||
key_values[option] = opt_src->serialize();
|
||||
}
|
||||
//add other values
|
||||
key_values[BBL_JSON_KEY_VERSION] = preset.version.to_string();
|
||||
key_values[BBL_JSON_KEY_BASE_ID] = preset.base_id;
|
||||
key_values[BBL_JSON_KEY_UPDATE_TIME] = std::to_string(preset.updated_time);
|
||||
key_values[BBL_JSON_KEY_TYPE] = Preset::get_iot_type_string(preset.type);
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" Error: can not find the parent! Should not happen, name %1%") %preset.name;
|
||||
return -1;
|
||||
for (auto iter = preset.config.cbegin(); iter != preset.config.cend(); ++iter)
|
||||
{
|
||||
key_values[iter->first] = iter->second->serialize();
|
||||
}
|
||||
}
|
||||
|
||||
//add other values
|
||||
key_values[BBL_JSON_KEY_VERSION] = preset.version.to_string();
|
||||
if (!preset.base_id.empty()) {
|
||||
key_values[BBL_JSON_KEY_BASE_ID] = preset.base_id;
|
||||
} else {
|
||||
key_values.erase(BBL_JSON_KEY_BASE_ID);
|
||||
if (get_preset_base(preset) == &preset && !preset.filament_id.empty()) {
|
||||
key_values[BBL_JSON_KEY_FILAMENT_ID] = preset.filament_id;
|
||||
}
|
||||
}
|
||||
key_values[BBL_JSON_KEY_UPDATE_TIME] = std::to_string(preset.updated_time);
|
||||
key_values[BBL_JSON_KEY_TYPE] = Preset::get_iot_type_string(preset.type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1363,7 +1425,7 @@ bool PresetCollection::reset_project_embedded_presets()
|
||||
return re_select;
|
||||
}
|
||||
|
||||
void PresetCollection::set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo)
|
||||
void PresetCollection::set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo, long long update_time)
|
||||
{
|
||||
lock();
|
||||
for (auto it = m_presets.begin(); it != m_presets.end(); it++) {
|
||||
@@ -1373,16 +1435,34 @@ void PresetCollection::set_sync_info_and_save(std::string name, std::string sett
|
||||
preset->sync_info.clear();
|
||||
else
|
||||
preset->sync_info = syncinfo;
|
||||
if (get_preset_base(*preset) == preset) {
|
||||
for (auto & preset2 : m_presets)
|
||||
if (preset2.inherits() == preset->name) {
|
||||
preset2.base_id = setting_id;
|
||||
preset2.save_info();
|
||||
}
|
||||
}
|
||||
preset->setting_id = setting_id;
|
||||
preset->save_info();
|
||||
if (update_time > 0)
|
||||
preset->updated_time = update_time;
|
||||
preset->sync_info == "update" ? preset->save(nullptr) : preset->save_info();
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool PresetCollection::need_sync(std::string name, std::string setting_id, long long update_time)
|
||||
{
|
||||
lock();
|
||||
auto preset = find_preset(name, false, true);
|
||||
bool need = preset == nullptr || preset->setting_id != setting_id || preset->updated_time < update_time;
|
||||
unlock();
|
||||
return need;
|
||||
}
|
||||
|
||||
//BBS: get user presets
|
||||
int PresetCollection::get_user_presets(std::vector<Preset>& result_presets)
|
||||
int PresetCollection::get_user_presets(PresetBundle *preset_bundle, std::vector<Preset> &result_presets)
|
||||
{
|
||||
int count = 0;
|
||||
result_presets.clear();
|
||||
@@ -1390,6 +1470,10 @@ int PresetCollection::get_user_presets(std::vector<Preset>& result_presets)
|
||||
lock();
|
||||
for (Preset &preset : m_presets) {
|
||||
if (!preset.is_user()) continue;
|
||||
if (get_preset_base(preset) != &preset && preset.base_id.empty()) continue;
|
||||
if (!preset.setting_id.empty() && preset.sync_info.empty()) continue;
|
||||
//if (!preset.is_bbl_vendor_preset(preset_bundle)) continue;
|
||||
if (preset.sync_info == "hold") continue;
|
||||
|
||||
result_presets.push_back(preset);
|
||||
count++;
|
||||
@@ -1426,7 +1510,9 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std:
|
||||
for (auto it = m_presets.begin(); it != m_presets.end(); it++) {
|
||||
Preset* preset = &m_presets[it - m_presets.begin()];
|
||||
if (!preset->is_user()) continue;
|
||||
preset->file = path_from_name(preset->name);
|
||||
if (preset->sync_info != "save") continue;
|
||||
preset->sync_info.clear();
|
||||
preset->file = path_for_preset(*preset);
|
||||
|
||||
if (preset->is_custom_defined()) {
|
||||
preset->save(nullptr);
|
||||
@@ -1434,11 +1520,13 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std:
|
||||
//BBS: only save difference for user preset
|
||||
std::string inherits = Preset::inherits(preset->config);
|
||||
if (inherits.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find inherits for %1% , should not happen")%preset->name;
|
||||
// BBS add sync info
|
||||
preset->sync_info = "delete";
|
||||
need_to_delete_list.push_back(preset->setting_id);
|
||||
delete_name_list.push_back(preset->name);
|
||||
// We support custom root preset now
|
||||
//BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find inherits for %1% , should not happen")%preset->name;
|
||||
//// BBS add sync info
|
||||
//preset->sync_info = "delete";
|
||||
//need_to_delete_list.push_back(preset->setting_id);
|
||||
//delete_name_list.push_back(preset->name);
|
||||
preset->save(nullptr);
|
||||
continue;
|
||||
}
|
||||
Preset* parent_preset = this->find_preset(inherits, false, true);
|
||||
@@ -1471,7 +1559,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
//std::deque<Preset> presets_loaded;
|
||||
int count = 0;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, name %1% , total value counts %2%")%name %preset_values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, name %1% , total value counts %2%")%name %preset_values.size();
|
||||
|
||||
//if the version is not matching, skip it
|
||||
if (preset_values.find(BBL_JSON_KEY_VERSION) == preset_values.end()) {
|
||||
@@ -1497,13 +1585,6 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
}
|
||||
std::string cloud_setting_id = preset_values[BBL_JSON_KEY_SETTING_ID];
|
||||
|
||||
//base_id
|
||||
if (preset_values.find(BBL_JSON_KEY_BASE_ID) == preset_values.end()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find base_id, not loading for user preset %1%")%name;
|
||||
return false;
|
||||
}
|
||||
std::string cloud_base_id = preset_values[BBL_JSON_KEY_BASE_ID];
|
||||
|
||||
//update_time
|
||||
long long cloud_update_time = 0;
|
||||
if (preset_values.find(BBL_JSON_KEY_UPDATE_TIME) != preset_values.end()) {
|
||||
@@ -1517,12 +1598,6 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
}
|
||||
std::string cloud_user_id = preset_values[BBL_JSON_KEY_USER_ID];
|
||||
|
||||
//filament_id
|
||||
std::string cloud_filament_id;
|
||||
if ((m_type == Preset::TYPE_FILAMENT) && preset_values.find(BBL_JSON_KEY_FILAMENT_ID) != preset_values.end()) {
|
||||
cloud_filament_id = preset_values[BBL_JSON_KEY_FILAMENT_ID];
|
||||
}
|
||||
|
||||
lock();
|
||||
//std::string name = preset->name;
|
||||
auto iter = this->find_preset_internal(name);
|
||||
@@ -1535,6 +1610,11 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
iter->sync_info = "update";
|
||||
else
|
||||
iter->sync_info.clear();
|
||||
// Fixup possible data lost
|
||||
iter->setting_id = cloud_setting_id;
|
||||
fs::path idx_file(iter->file);
|
||||
idx_file.replace_extension(".info");
|
||||
iter->save_info(idx_file.string());
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("preset %1%'s update_time is eqaul or newer, cloud update_time %2%, local update_time %3%")%name %cloud_update_time %iter->updated_time;
|
||||
unlock();
|
||||
return false;
|
||||
@@ -1542,11 +1622,24 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
else {
|
||||
//update the one from cloud which is newer
|
||||
need_update = true;
|
||||
iter->sync_info.clear();
|
||||
}
|
||||
}
|
||||
|
||||
DynamicPrintConfig new_config, cloud_config;
|
||||
// base_id
|
||||
if (preset_values.find(BBL_JSON_KEY_BASE_ID) == preset_values.end()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find base_id, not loading for user preset %1%") % name;
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
std::string cloud_base_id = preset_values[BBL_JSON_KEY_BASE_ID];
|
||||
|
||||
//filament_id
|
||||
std::string cloud_filament_id;
|
||||
if ((m_type == Preset::TYPE_FILAMENT) && preset_values.find(BBL_JSON_KEY_FILAMENT_ID) != preset_values.end()) {
|
||||
cloud_filament_id = preset_values[BBL_JSON_KEY_FILAMENT_ID];
|
||||
}
|
||||
|
||||
DynamicPrintConfig new_config, cloud_config;
|
||||
try {
|
||||
ConfigSubstitutions config_substitutions = cloud_config.load_string_map(preset_values, rule);
|
||||
if (! config_substitutions.empty())
|
||||
@@ -1570,12 +1663,16 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
new_config = inherit_preset->config;
|
||||
}
|
||||
else {
|
||||
// We support custom root preset now
|
||||
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(inherits_config);
|
||||
if (inherits_config2 && !inherits_config2->value.empty()) {
|
||||
//we should skip this preset here
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip")%name;
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
|
||||
//new_config = default_preset.config;
|
||||
//we should skip this preset here
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip")%name;
|
||||
unlock();
|
||||
return false;
|
||||
new_config = default_preset.config;
|
||||
}
|
||||
new_config.apply(std::move(cloud_config));
|
||||
Preset::normalize(new_config);
|
||||
@@ -1591,7 +1688,8 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
}
|
||||
iter->config = new_config;
|
||||
iter->updated_time = cloud_update_time;
|
||||
iter->version = cloud_version.value();
|
||||
iter->sync_info = "save";
|
||||
iter->version = cloud_version.value();
|
||||
iter->user_id = cloud_user_id;
|
||||
iter->setting_id = cloud_setting_id;
|
||||
iter->base_id = cloud_base_id;
|
||||
@@ -1607,7 +1705,8 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
preset.loaded = true;
|
||||
preset.config = new_config;
|
||||
preset.updated_time = cloud_update_time;
|
||||
preset.version = cloud_version.value();
|
||||
preset.sync_info = "save";
|
||||
preset.version = cloud_version.value();
|
||||
preset.user_id = cloud_user_id;
|
||||
preset.setting_id = cloud_setting_id;
|
||||
preset.base_id = cloud_base_id;
|
||||
@@ -1651,28 +1750,33 @@ void PresetCollection::update_after_user_presets_loaded()
|
||||
return;
|
||||
}
|
||||
|
||||
//BBS: validate_printers
|
||||
bool PresetCollection::validate_printers(const std::string &name, DynamicPrintConfig& config, std::string &inherit)
|
||||
//BBS: validate_preset
|
||||
bool PresetCollection::validate_preset(const std::string &preset_name, std::string &inherit_name)
|
||||
{
|
||||
std::string& original_name = config.opt_string("printer_settings_id", true);
|
||||
std::deque<Preset>::iterator it = this->find_preset_internal(original_name);
|
||||
bool found = it != m_presets.end() && it->name == original_name && (it->is_system || it->is_default);
|
||||
std::deque<Preset>::iterator it = this->find_preset_internal(preset_name);
|
||||
bool found = (it != m_presets.end()) && (it->name == preset_name) && (it->is_system || it->is_default);
|
||||
if (!found) {
|
||||
it = this->find_preset_renamed(original_name);
|
||||
it = this->find_preset_renamed(preset_name);
|
||||
found = it != m_presets.end() && (it->is_system || it->is_default);
|
||||
}
|
||||
if (!found) {
|
||||
if (!inherit.empty()) {
|
||||
it = this->find_preset_internal(inherit);
|
||||
found = it != m_presets.end() && it->name == inherit && (it->is_system || it->is_default);
|
||||
if (!inherit_name.empty()) {
|
||||
it = this->find_preset_internal(inherit_name);
|
||||
found = it != m_presets.end() && it->name == inherit_name && (it->is_system || it->is_default);
|
||||
if (found)
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": preset_name %1%, inherit_name %2%, found inherit in list")%preset_name %inherit_name;
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": preset_name %1%, inherit_name %2%, can not found preset and inherit in list")%preset_name %inherit_name;
|
||||
}
|
||||
else {
|
||||
//inherit is null , should not happen , just consider it as valid
|
||||
found = false;
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format(": name %1%, printer_settings %2%, no inherit, set to not found")%name %original_name;
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": preset_name %1%, no inherit, set to not found")%preset_name;
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format(": name %1%, printer_settings %2%, inherit %3%, found result %4%")%name %original_name % inherit % found;
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": preset_name %1%, found in list")%preset_name;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
@@ -1945,7 +2049,7 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
||||
}
|
||||
else {
|
||||
//external config
|
||||
preset.file = path_from_name(preset.name);
|
||||
preset.file = path_for_preset(preset);
|
||||
//BBS: save full config here for external
|
||||
//we can not reach here
|
||||
preset.save(nullptr);
|
||||
@@ -1985,6 +2089,113 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string
|
||||
return preset;
|
||||
}
|
||||
|
||||
bool PresetCollection::clone_presets(std::vector<Preset const *> const &presets, std::vector<std::string> &failures, std::function<void(Preset &, Preset::Type &)> modifier, bool force_rewritten)
|
||||
{
|
||||
std::vector<Preset> new_presets;
|
||||
for (auto curr_preset : presets) {
|
||||
new_presets.push_back(*curr_preset);
|
||||
auto &preset = new_presets.back();
|
||||
preset.vendor = nullptr;
|
||||
preset.renamed_from.clear();
|
||||
preset.setting_id.clear();
|
||||
preset.inherits().clear();
|
||||
preset.is_default = false;
|
||||
preset.is_system = false;
|
||||
preset.is_external = false;
|
||||
preset.is_visible = true;
|
||||
preset.is_project_embedded = false;
|
||||
modifier(preset, m_type);
|
||||
if (find_preset(preset.name) && !force_rewritten) {
|
||||
failures.push_back(preset.name);
|
||||
}
|
||||
preset.file = this->path_for_preset(preset);
|
||||
if (m_type == Preset::TYPE_PRINT)
|
||||
preset.config.option<ConfigOptionString>("print_settings_id", true)->value = preset.name;
|
||||
else if (m_type == Preset::TYPE_FILAMENT)
|
||||
preset.config.option<ConfigOptionStrings>("filament_settings_id", true)->values[0] = preset.name;
|
||||
else if (m_type == Preset::TYPE_PRINTER)
|
||||
preset.config.option<ConfigOptionString>("printer_settings_id", true)->value = preset.name;
|
||||
}
|
||||
if (!failures.empty() && !force_rewritten)
|
||||
return false;
|
||||
lock();
|
||||
auto old_name = this->get_edited_preset().name;
|
||||
for (auto preset : new_presets) {
|
||||
preset.alias.clear();
|
||||
auto it = this->find_preset_internal(preset.name);
|
||||
assert((it == m_presets.end() || it->name != preset.name) || force_rewritten);
|
||||
if (it == m_presets.end() || it->name != preset.name) {
|
||||
Preset &new_preset = *m_presets.insert(it, preset);
|
||||
new_preset.save(nullptr);
|
||||
} else if (force_rewritten) {
|
||||
*it = preset;
|
||||
(*it).save(nullptr);
|
||||
}
|
||||
}
|
||||
this->select_preset_by_name(old_name, true);
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PresetCollection::clone_presets_for_printer(std::vector<Preset const *> const &presets, std::vector<std::string> &failures, std::string const &printer, bool force_rewritten)
|
||||
{
|
||||
return clone_presets(presets, failures, [printer](Preset &preset, Preset::Type &type) {
|
||||
std::string prefix = preset.name.substr(0, preset.name.find(" @"));
|
||||
std::replace(prefix.begin(), prefix.end(), '/', '-');
|
||||
preset.name = prefix + " @" + printer;
|
||||
//preset.alias = "";
|
||||
auto *compatible_printers = dynamic_cast<ConfigOptionStrings *>(preset.config.option("compatible_printers"));
|
||||
compatible_printers->values = std::vector<std::string>{ printer };
|
||||
}, force_rewritten);
|
||||
}
|
||||
|
||||
bool PresetCollection::create_presets_from_template_for_printer(std::vector<Preset const *> const & templates,
|
||||
std::vector<std::string> & failures,
|
||||
std::string const & printer,
|
||||
std::function<std::string(std::string)> create_filament_id,
|
||||
bool force_rewritten)
|
||||
{
|
||||
return clone_presets(templates, failures, [printer, create_filament_id](Preset &preset, Preset::Type &type) {
|
||||
std::string prefix = preset.name.substr(0, preset.name.find(" @"));
|
||||
std::replace(prefix.begin(), prefix.end(), '/', '-');
|
||||
preset.name = prefix + " @" + printer;
|
||||
auto *compatible_printers = dynamic_cast<ConfigOptionStrings *>(preset.config.option("compatible_printers"));
|
||||
compatible_printers->values = std::vector<std::string>{printer};
|
||||
preset.is_visible = true;
|
||||
if (type == Preset::TYPE_FILAMENT)
|
||||
preset.filament_id = create_filament_id(prefix);
|
||||
}, force_rewritten);
|
||||
}
|
||||
|
||||
bool PresetCollection::clone_presets_for_filament(Preset const *const & preset,
|
||||
std::vector<std::string> &failures,
|
||||
std::string const & filament_name,
|
||||
std::string const & filament_id,
|
||||
const DynamicConfig & dynamic_config,
|
||||
const std::string & compatible_printers,
|
||||
bool force_rewritten)
|
||||
{
|
||||
std::vector<Preset const *> const presets = {preset};
|
||||
return clone_presets(presets, failures, [&filament_name, &filament_id, &dynamic_config, &compatible_printers](Preset &preset, Preset::Type &type) {
|
||||
preset.name = filament_name + " @" + compatible_printers;
|
||||
if (type == Preset::TYPE_FILAMENT) {
|
||||
preset.config.apply_only(dynamic_config, {"filament_vendor", "compatible_printers", "filament_type"},true);
|
||||
|
||||
preset.filament_id = filament_id;
|
||||
}
|
||||
},
|
||||
force_rewritten);
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<Preset const *>> PresetCollection::get_filament_presets() const
|
||||
{
|
||||
std::map<std::string, std::vector<Preset const *>> filament_presets;
|
||||
for (auto &preset : m_presets) {
|
||||
if (get_preset_base(preset) == &preset) { filament_presets[preset.filament_id].push_back(&preset); }
|
||||
}
|
||||
return filament_presets;
|
||||
}
|
||||
|
||||
//BBS: add project embedded preset logic
|
||||
void PresetCollection::save_current_preset(const std::string &new_name, bool detach, bool save_to_project, Preset* _curr_preset)
|
||||
{
|
||||
@@ -2020,15 +2231,27 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": save preset %1% , with detach")%new_name;
|
||||
}
|
||||
//BBS: add lock logic for sync preset in background
|
||||
|
||||
if (m_type == Preset::TYPE_PRINT)
|
||||
preset.config.option<ConfigOptionString>("print_settings_id", true)->value = new_name;
|
||||
else if (m_type == Preset::TYPE_FILAMENT)
|
||||
preset.config.option<ConfigOptionStrings>("filament_settings_id", true)->values[0] = new_name;
|
||||
else if (m_type == Preset::TYPE_PRINTER)
|
||||
preset.config.option<ConfigOptionString>("printer_settings_id", true)->value = new_name;
|
||||
final_inherits = preset.inherits();
|
||||
unlock();
|
||||
// TODO: apply change from custom root to devided presets.
|
||||
if (preset.inherits().empty()) {
|
||||
for (auto &preset2 : m_presets)
|
||||
if (preset2.inherits() == preset.name)
|
||||
preset2.reload(preset);
|
||||
}
|
||||
} else {
|
||||
// Creating a new preset.
|
||||
Preset &preset = *m_presets.insert(it, curr_preset);
|
||||
std::string &inherits = preset.inherits();
|
||||
std::string old_name = preset.name;
|
||||
preset.name = new_name;
|
||||
preset.file = this->path_from_name(new_name);
|
||||
preset.vendor = nullptr;
|
||||
preset.alias.clear();
|
||||
preset.renamed_from.clear();
|
||||
@@ -2037,19 +2260,16 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
// Clear the link to the parent profile.
|
||||
inherits.clear();
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": save preset %1% , with detach")%new_name;
|
||||
} else if (preset.is_system) {
|
||||
// Inheriting from a system preset.
|
||||
inherits = /* preset.vendor->name + "/" + */ old_name;
|
||||
} else if (inherits.empty()) {
|
||||
// Inheriting from a user preset. Link the new preset to the old preset.
|
||||
// inherits = old_name;
|
||||
} else {
|
||||
// Inherited from a user preset. Just maintain the "inherited" flag,
|
||||
// meaning it will inherit from either the system preset, or the inherited user preset.
|
||||
auto base = get_preset_base(curr_preset);
|
||||
inherits = base ? base->name : "";
|
||||
}
|
||||
preset.is_default = false;
|
||||
preset.is_system = false;
|
||||
preset.is_external = false;
|
||||
preset.file = this->path_for_preset(preset);
|
||||
// The newly saved preset will be activated -> make it visible.
|
||||
preset.is_visible = true;
|
||||
// Just system presets have aliases
|
||||
@@ -2061,11 +2281,11 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
else
|
||||
preset.is_project_embedded = false;
|
||||
if (m_type == Preset::TYPE_PRINT)
|
||||
preset.config.option<ConfigOptionString >("print_settings_id", true)->value = preset.name;
|
||||
preset.config.option<ConfigOptionString>("print_settings_id", true)->value = new_name;
|
||||
else if (m_type == Preset::TYPE_FILAMENT)
|
||||
preset.config.option<ConfigOptionStrings>("filament_settings_id", true)->values[0] = preset.name;
|
||||
preset.config.option<ConfigOptionStrings>("filament_settings_id", true)->values[0] = new_name;
|
||||
else if (m_type == Preset::TYPE_PRINTER)
|
||||
preset.config.option<ConfigOptionString>("printer_settings_id", true)->value = preset.name;
|
||||
preset.config.option<ConfigOptionString>("printer_settings_id", true)->value = new_name;
|
||||
//BBS: add lock logic for sync preset in background
|
||||
final_inherits = inherits;
|
||||
unlock();
|
||||
@@ -2081,7 +2301,6 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
this->get_selected_preset().base_id = parent_preset->setting_id;
|
||||
}
|
||||
}
|
||||
this->get_selected_preset().updated_time = (long long)Slic3r::Utils::get_current_time_utc();
|
||||
if (parent_preset)
|
||||
this->get_selected_preset().save(&(parent_preset->config));
|
||||
else
|
||||
@@ -2093,6 +2312,13 @@ bool PresetCollection::delete_current_preset()
|
||||
Preset &selected = this->get_selected_preset();
|
||||
if (selected.is_default)
|
||||
return false;
|
||||
|
||||
if (get_preset_base(selected) == &selected) {
|
||||
for (auto &preset2 : m_presets)
|
||||
if (preset2.inherits() == selected.name)
|
||||
return false;
|
||||
}
|
||||
|
||||
//BBS: add project embedded preset logic and refine is_external
|
||||
//if (! selected.is_external && ! selected.is_system) {
|
||||
if (! selected.is_system) {
|
||||
@@ -2142,7 +2368,7 @@ const Preset* PresetCollection::get_selected_preset_parent() const
|
||||
return nullptr;
|
||||
|
||||
const Preset &selected_preset = this->get_selected_preset();
|
||||
if (selected_preset.is_system || selected_preset.is_default)
|
||||
if (get_preset_base(selected_preset) == &selected_preset)
|
||||
return &selected_preset;
|
||||
|
||||
const Preset &edited_preset = this->get_edited_preset();
|
||||
@@ -2190,6 +2416,17 @@ const Preset* PresetCollection::get_preset_parent(const Preset& child) const
|
||||
preset;
|
||||
}
|
||||
|
||||
const Preset *PresetCollection::get_preset_base(const Preset &child) const
|
||||
{
|
||||
if (child.is_system || child.is_default)
|
||||
return &child;
|
||||
// Handle user preset
|
||||
if (child.inherits().empty())
|
||||
return &child; // this is user root
|
||||
auto inherits = find_preset(child.inherits());
|
||||
return inherits ? get_preset_base(*inherits) : nullptr;
|
||||
}
|
||||
|
||||
// Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist.
|
||||
PresetWithVendorProfile PresetCollection::get_preset_with_vendor_profile(const Preset &preset) const
|
||||
{
|
||||
@@ -2614,12 +2851,20 @@ std::vector<std::string> PresetCollection::system_preset_names() const
|
||||
}
|
||||
|
||||
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
|
||||
std::string PresetCollection::path_from_name(const std::string &new_name) const
|
||||
std::string PresetCollection::path_from_name(const std::string &new_name, bool detach) const
|
||||
{
|
||||
//BBS: change to json format
|
||||
//std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini");
|
||||
std::string file_name = boost::iends_with(new_name, ".json") ? new_name : (new_name + ".json");
|
||||
return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
|
||||
if (detach)
|
||||
return (boost::filesystem::path(m_dir_path) / "base" / file_name).make_preferred().string();
|
||||
else
|
||||
return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
|
||||
}
|
||||
|
||||
std::string PresetCollection::path_for_preset(const Preset &preset) const
|
||||
{
|
||||
return path_from_name(preset.name, get_preset_base(preset) == &preset);
|
||||
}
|
||||
|
||||
const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const
|
||||
@@ -2643,6 +2888,21 @@ const Preset* PrinterPresetCollection::find_system_preset_by_model_and_variant(c
|
||||
return it != cend() ? &*it : nullptr;
|
||||
}
|
||||
|
||||
const Preset *PrinterPresetCollection::find_custom_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const
|
||||
{
|
||||
if (model_id.empty()) { return nullptr; }
|
||||
|
||||
const auto it = std::find_if(cbegin(), cend(), [&](const Preset &preset) {
|
||||
if (preset.config.opt_string("printer_model") != model_id)
|
||||
return false;
|
||||
if (variant.empty())
|
||||
return true;
|
||||
return preset.config.opt_string("printer_variant") == variant;
|
||||
});
|
||||
|
||||
return it != cend() ? &*it : nullptr;
|
||||
}
|
||||
|
||||
bool PrinterPresetCollection::only_default_printers() const
|
||||
{
|
||||
for (const auto& printer : get_presets()) {
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#define PRESET_PRINTER_NAME "machine"
|
||||
#define PRESET_SLA_PRINT_NAME "sla_print"
|
||||
#define PRESET_SLA_MATERIALS_NAME "sla_materials"
|
||||
#define PRESET_PROFILES_DIR "profiles"
|
||||
#define PRESET_PROFILES_TEMOLATE_DIR "profiles_template"
|
||||
#define PRESET_TEMPLATE_DIR "Template"
|
||||
#define PRESET_CUSTOM_VENDOR "Custom"
|
||||
|
||||
//BBS: iot preset type strings
|
||||
#define PRESET_IOT_PRINTER_TYPE "printer"
|
||||
@@ -57,6 +61,8 @@
|
||||
#define BBL_JSON_KEY_DEFAULT_MATERIALS "default_materials"
|
||||
#define BBL_JSON_KEY_MODEL_ID "model_id"
|
||||
|
||||
//BBL: json path
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -171,6 +177,8 @@ public:
|
||||
// This type is here to support PresetConfigSubstitutions for physical printers, however it does not belong to the Preset class,
|
||||
// PhysicalPrinter class is used instead.
|
||||
TYPE_PHYSICAL_PRINTER,
|
||||
// BBS: plate config
|
||||
TYPE_PLATE,
|
||||
// BBS: model config
|
||||
TYPE_MODEL,
|
||||
};
|
||||
@@ -245,6 +253,7 @@ public:
|
||||
//BBS: add logic for only difference save
|
||||
//if parent_config is null, save all keys, otherwise, only save difference
|
||||
void save(DynamicPrintConfig* parent_config);
|
||||
void reload(Preset const & parent);
|
||||
|
||||
// Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty.
|
||||
std::string label(bool no_alias) const;
|
||||
@@ -300,6 +309,8 @@ public:
|
||||
std::string get_filament_type(std::string &display_filament_type);
|
||||
std::string get_printer_type(PresetBundle *preset_bundle); // get edited preset type
|
||||
std::string get_current_printer_type(PresetBundle *preset_bundle); // get current preset type
|
||||
|
||||
bool has_lidar(PresetBundle *preset_bundle);
|
||||
bool is_custom_defined();
|
||||
|
||||
BedType get_default_bed_type(PresetBundle *preset_bundle);
|
||||
@@ -386,8 +397,8 @@ public:
|
||||
typedef std::function<void(Preset* preset, std::string sync_info)> SyncFunc;
|
||||
//BBS get m_presets begin
|
||||
Iterator lbegin() { return m_presets.begin(); }
|
||||
//BBS: validate_printers
|
||||
bool validate_printers(const std::string &name, DynamicPrintConfig& config, std::string &inherit);
|
||||
//BBS: validate_preset
|
||||
bool validate_preset(const std::string &name, std::string &inherit);
|
||||
|
||||
Iterator begin() { return m_presets.begin() + m_num_default_presets; }
|
||||
ConstIterator begin() const { return m_presets.cbegin() + m_num_default_presets; }
|
||||
@@ -425,8 +436,9 @@ public:
|
||||
bool load_user_preset(std::string name, std::map<std::string, std::string> preset_values, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule);
|
||||
void update_after_user_presets_loaded();
|
||||
//BBS: get user presets
|
||||
int get_user_presets(std::vector<Preset>& result_presets);
|
||||
void set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo);
|
||||
int get_user_presets(PresetBundle *preset_bundle, std::vector<Preset> &result_presets);
|
||||
void set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo, long long update_time);
|
||||
bool need_sync(std::string name, std::string setting_id, long long update_time);
|
||||
|
||||
//BBS: add function to generate differed preset for save
|
||||
//the pointer should be freed by the caller
|
||||
@@ -444,6 +456,20 @@ public:
|
||||
Preset& load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true, Semver file_version = Semver(), bool is_custom_defined = false);
|
||||
Preset& load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true, Semver file_version = Semver(), bool is_custom_defined = false);
|
||||
|
||||
bool clone_presets(std::vector<Preset const *> const &presets, std::vector<std::string> &failures, std::function<void(Preset &, Preset::Type &)> modifier, bool force_rewritten = false);
|
||||
bool clone_presets_for_printer(std::vector<Preset const *> const &presets, std::vector<std::string> &failures, std::string const &printer, bool force_rewritten = false);
|
||||
bool create_presets_from_template_for_printer(
|
||||
std::vector<Preset const *> const &templates, std::vector<std::string> &failures, std::string const &printer, std::function <std::string(std::string)> create_filament_id, bool force_rewritten = false);
|
||||
bool clone_presets_for_filament(Preset const *const & preset,
|
||||
std::vector<std::string> &failures,
|
||||
std::string const & filament_name,
|
||||
std::string const & filament_id,
|
||||
const DynamicConfig & dynamic_config,
|
||||
const std::string & compatible_printers,
|
||||
bool force_rewritten = false);
|
||||
|
||||
std::map<std::string, std::vector<Preset const *>> get_filament_presets() const;
|
||||
|
||||
// Returns a loaded preset, returns true if an existing preset was selected AND modified from config.
|
||||
// In that case the successive filament loaded for a multi material printer should not be modified, but
|
||||
// an external preset should be created instead.
|
||||
@@ -514,6 +540,7 @@ public:
|
||||
// Get parent preset for a child preset, based on the "inherits" field of a child,
|
||||
// where the "inherits" profile name is searched for in both m_presets and m_map_system_profile_renamed.
|
||||
const Preset* get_preset_parent(const Preset& child) const;
|
||||
const Preset* get_preset_base(const Preset& child) const;
|
||||
// Return the selected preset including the user modifications.
|
||||
Preset& get_edited_preset() { return m_edited_preset; }
|
||||
const Preset& get_edited_preset() const { return m_edited_preset; }
|
||||
@@ -648,7 +675,8 @@ public:
|
||||
bool select_preset_by_name(const std::string &name, bool force);
|
||||
|
||||
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
|
||||
std::string path_from_name(const std::string &new_name) const;
|
||||
std::string path_from_name(const std::string &new_name, bool detach = false) const;
|
||||
std::string path_for_preset(const Preset & preset) const;
|
||||
|
||||
size_t num_default_presets() { return m_num_default_presets; }
|
||||
|
||||
@@ -754,6 +782,7 @@ public:
|
||||
const Preset& default_preset_for(const DynamicPrintConfig &config) const override;
|
||||
|
||||
const Preset* find_system_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const;
|
||||
const Preset* find_custom_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const;
|
||||
|
||||
bool only_default_printers() const;
|
||||
private:
|
||||
|
||||
+400
-111
@@ -21,6 +21,7 @@
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/locale.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <miniz/miniz.h>
|
||||
|
||||
|
||||
// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir.
|
||||
@@ -540,6 +541,7 @@ std::string PresetBundle::get_hotend_model_for_printer_model(std::string model_n
|
||||
|
||||
PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule substitution_rule)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " entry and user is: " << user;
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
|
||||
@@ -600,9 +602,14 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(AppConfig &
|
||||
remove_users_preset(config, &my_presets);
|
||||
|
||||
std::map<std::string, std::map<std::string, std::string>>::iterator it;
|
||||
for (int pass = 0; pass < 2; ++pass)
|
||||
for (it = my_presets.begin(); it != my_presets.end(); it++) {
|
||||
std::string name = it->first;
|
||||
std::map<std::string, std::string>& value_map = it->second;
|
||||
// Load user root presets at first pass
|
||||
std::map<std::string, std::string>::iterator inherits_iter = value_map.find(BBL_JSON_KEY_INHERITS);
|
||||
if ((pass == 1) == (inherits_iter == value_map.end() || inherits_iter->second.empty()))
|
||||
continue;
|
||||
//get the type first
|
||||
std::map<std::string, std::string>::iterator type_iter = value_map.find(BBL_JSON_KEY_TYPE);
|
||||
if (type_iter == value_map.end()) {
|
||||
@@ -659,101 +666,189 @@ PresetsConfigSubstitutions PresetBundle::import_presets(std::vector<std::string>
|
||||
std::function<int(std::string const &)> override_confirm,
|
||||
ForwardCompatibilitySubstitutionRule rule)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry";
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
int overwrite = 0;
|
||||
std::vector<std::string> result;
|
||||
for (auto &file : files) {
|
||||
if (Slic3r::is_json_file(file)) {
|
||||
try {
|
||||
DynamicPrintConfig config;
|
||||
// BBS: change to json format
|
||||
// ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule);
|
||||
std::map<std::string, std::string> key_values;
|
||||
std::string reason;
|
||||
ConfigSubstitutions config_substitutions = config.load_from_json(file, rule, key_values, reason);
|
||||
std::string name = key_values[BBL_JSON_KEY_NAME];
|
||||
std::string version_str = key_values[BBL_JSON_KEY_VERSION];
|
||||
boost::optional<Semver> version = Semver::parse(version_str);
|
||||
if (!version) continue;
|
||||
Semver app_version = *(Semver::parse(SLIC3R_VERSION));
|
||||
if (version->maj() != app_version.maj()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Preset incompatibla, not loading: " << name;
|
||||
continue;
|
||||
}
|
||||
import_json_presets(substitutions, file, override_confirm, rule, overwrite, result);
|
||||
}
|
||||
// Determine if it is a preset bundle
|
||||
if (boost::iends_with(file, ".bbscfg") || boost::iends_with(file, ".bbsflmt") || boost::iends_with(file, ".zip")) {
|
||||
boost::system::error_code ec;
|
||||
// create user folder
|
||||
fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
|
||||
if (!fs::exists(user_folder)) fs::create_directory(user_folder, ec);
|
||||
if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message();
|
||||
// create default folder
|
||||
fs::path default_folder(user_folder / DEFAULT_USER_FOLDER_NAME);
|
||||
if (!fs::exists(default_folder)) fs::create_directory(default_folder, ec);
|
||||
if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message();
|
||||
//create temp folder
|
||||
//std::string user_default_temp_dir = data_dir() + "/" + PRESET_USER_DIR + "/" + DEFAULT_USER_FOLDER_NAME + "/" + "temp";
|
||||
fs::path temp_folder(default_folder / "temp");
|
||||
std::string user_default_temp_dir = temp_folder.make_preferred().string();
|
||||
if (fs::exists(temp_folder)) fs::remove_all(temp_folder);
|
||||
fs::create_directory(temp_folder, ec);
|
||||
if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message();
|
||||
|
||||
PresetCollection * collection = nullptr;
|
||||
if (config.has("printer_settings_id"))
|
||||
collection = &printers;
|
||||
else if (config.has("print_settings_id"))
|
||||
collection = &prints;
|
||||
else if (config.has("filament_settings_id"))
|
||||
collection = &filaments;
|
||||
if (collection == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Preset type is unknown, not loading: " << name;
|
||||
continue;
|
||||
}
|
||||
if (overwrite == 0) overwrite = 1;
|
||||
if (auto p = collection->find_preset(name, false)) {
|
||||
if (p->is_default || p->is_system) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Preset already present and is system preset, not loading: " << name;
|
||||
continue;
|
||||
}
|
||||
overwrite = override_confirm(name);
|
||||
}
|
||||
if (overwrite == 0 || overwrite == 2) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << name;
|
||||
continue;
|
||||
}
|
||||
file = boost::filesystem::path(file).make_preferred().string();
|
||||
mz_zip_archive zip_archive;
|
||||
mz_zip_zero_struct(&zip_archive);
|
||||
mz_bool status;
|
||||
|
||||
DynamicPrintConfig new_config;
|
||||
Preset * inherit_preset = nullptr;
|
||||
ConfigOption *inherits_config = config.option(BBL_JSON_KEY_INHERITS);
|
||||
std::string inherits_value;
|
||||
if (inherits_config) {
|
||||
ConfigOptionString *option_str = dynamic_cast<ConfigOptionString *>(inherits_config);
|
||||
inherits_value = option_str->value;
|
||||
inherit_preset = collection->find_preset(inherits_value, false, true);
|
||||
}
|
||||
if (inherit_preset) {
|
||||
new_config = inherit_preset->config;
|
||||
} else {
|
||||
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
|
||||
// new_config = default_preset.config;
|
||||
// we should skip this preset here
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip") % name;
|
||||
continue;
|
||||
}
|
||||
new_config.apply(std::move(config));
|
||||
/*if (!open_zip_reader(&zip_archive, file)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Failed to initialize reader ZIP archive";
|
||||
return substitutions;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "Success to initialize reader ZIP archive";
|
||||
}*/
|
||||
|
||||
Preset &preset = collection->load_preset(collection->path_from_name(name), name, std::move(new_config), false);
|
||||
preset.is_external = true;
|
||||
preset.version = *version;
|
||||
inherit_preset = collection->find_preset(inherits_value, false, true); // pointer maybe wrong after insert, redo find
|
||||
if (inherit_preset)
|
||||
preset.base_id = inherit_preset->setting_id;
|
||||
Preset::normalize(preset.config);
|
||||
// Report configuration fields, which are misplaced into a wrong group.
|
||||
const Preset &default_preset = collection->default_preset_for(new_config);
|
||||
std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config);
|
||||
if (!incorrect_keys.empty())
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << preset.file << "\" contains the following incorrect keys: " << incorrect_keys
|
||||
<< ", which were removed";
|
||||
if (!config_substitutions.empty())
|
||||
substitutions.push_back({name, collection->type(), PresetConfigSubstitutions::Source::UserFile, file, std::move(config_substitutions)});
|
||||
|
||||
preset.save(inherit_preset ? &inherit_preset->config : nullptr);
|
||||
result.push_back(file);
|
||||
} catch (const std::ifstream::failure &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("The config cannot be loaded: %1%. Reason: %2%") % file % err.what();
|
||||
} catch (const std::runtime_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Failed importing config file: %1%. Reason: %2%") % file % err.what();
|
||||
FILE *zipFile = boost::nowide::fopen(file.c_str(), "rb");
|
||||
status = mz_zip_reader_init_cfile(&zip_archive, zipFile, 0, MZ_ZIP_FLAG_CASE_SENSITIVE | MZ_ZIP_FLAG_IGNORE_PATH);
|
||||
if (MZ_FALSE == status) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to initialize reader ZIP archive";
|
||||
return substitutions;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Success to initialize reader ZIP archive";
|
||||
}
|
||||
|
||||
// Extract Files
|
||||
int num_files = mz_zip_reader_get_num_files(&zip_archive);
|
||||
for (int i = 0; i < num_files; i++) {
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
status = mz_zip_reader_file_stat(&zip_archive, i, &file_stat);
|
||||
if (status) {
|
||||
std::string file_name = file_stat.m_filename;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Form zip file: " << file << ". Read file name: " << file_stat.m_filename;
|
||||
size_t index = file_name.find_last_of('/');
|
||||
if (std::string::npos != index) {
|
||||
file_name = file_name.substr(index + 1);
|
||||
}
|
||||
if (BUNDLE_STRUCTURE_JSON_NAME == file_name) continue;
|
||||
// create target file path
|
||||
std::string target_file_path = boost::filesystem::path(temp_folder / file_name).make_preferred().string();
|
||||
|
||||
status = mz_zip_reader_extract_to_file(&zip_archive, i, encode_path(target_file_path.c_str()).c_str(), MZ_ZIP_FLAG_CASE_SENSITIVE);
|
||||
// target file is opened
|
||||
if (MZ_FALSE == status) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to open target file: " << target_file_path;
|
||||
} else {
|
||||
bool is_success = import_json_presets(substitutions, target_file_path, override_confirm, rule, overwrite, result);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " import target file: " << target_file_path << " import result" << is_success;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(zipFile);
|
||||
if (fs::exists(temp_folder)) fs::remove_all(temp_folder, ec);
|
||||
if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " remove directory failed: " << ec.message();
|
||||
}
|
||||
}
|
||||
files = result;
|
||||
return substitutions;
|
||||
}
|
||||
|
||||
bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & substitutions,
|
||||
std::string & file,
|
||||
std::function<int(std::string const &)> override_confirm,
|
||||
ForwardCompatibilitySubstitutionRule rule,
|
||||
int & overwrite,
|
||||
std::vector<std::string> & result)
|
||||
{
|
||||
try {
|
||||
DynamicPrintConfig config;
|
||||
// BBS: change to json format
|
||||
// ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule);
|
||||
std::map<std::string, std::string> key_values;
|
||||
std::string reason;
|
||||
ConfigSubstitutions config_substitutions = config.load_from_json(file, rule, key_values, reason);
|
||||
std::string name = key_values[BBL_JSON_KEY_NAME];
|
||||
std::string version_str = key_values[BBL_JSON_KEY_VERSION];
|
||||
boost::optional<Semver> version = Semver::parse(version_str);
|
||||
if (!version) return false;
|
||||
Semver app_version = *(Semver::parse(SLIC3R_VERSION));
|
||||
if (version->maj() != app_version.maj()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset incompatibla, not loading: " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
PresetCollection *collection = nullptr;
|
||||
if (config.has("printer_settings_id"))
|
||||
collection = &printers;
|
||||
else if (config.has("print_settings_id"))
|
||||
collection = &prints;
|
||||
else if (config.has("filament_settings_id"))
|
||||
collection = &filaments;
|
||||
if (collection == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset type is unknown, not loading: " << name;
|
||||
return false;
|
||||
}
|
||||
if (overwrite == 0) overwrite = 1;
|
||||
if (auto p = collection->find_preset(name, false)) {
|
||||
if (p->is_default || p->is_system) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset already present and is system preset, not loading: " << name;
|
||||
return false;
|
||||
}
|
||||
if (overwrite != 2 && overwrite != 3) overwrite = override_confirm(name); //3: yes to all 2: no to all
|
||||
}
|
||||
if (overwrite == 0 || overwrite == 2) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset already present, not loading: " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
DynamicPrintConfig new_config;
|
||||
Preset * inherit_preset = nullptr;
|
||||
ConfigOption * inherits_config = config.option(BBL_JSON_KEY_INHERITS);
|
||||
std::string inherits_value;
|
||||
if (inherits_config) {
|
||||
ConfigOptionString *option_str = dynamic_cast<ConfigOptionString *>(inherits_config);
|
||||
inherits_value = option_str->value;
|
||||
inherit_preset = collection->find_preset(inherits_value, false, true);
|
||||
}
|
||||
if (inherit_preset) {
|
||||
new_config = inherit_preset->config;
|
||||
} else {
|
||||
// We support custom root preset now
|
||||
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(inherits_config);
|
||||
if (inherits_config2 && !inherits_config2->value.empty()) {
|
||||
// we should skip this preset here
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip") % name;
|
||||
return false;
|
||||
}
|
||||
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
|
||||
const Preset &default_preset = collection->default_preset_for(config);
|
||||
new_config = default_preset.config;
|
||||
}
|
||||
new_config.apply(std::move(config));
|
||||
|
||||
Preset &preset = collection->load_preset(collection->path_from_name(name, inherit_preset == nullptr), name, std::move(new_config), false);
|
||||
if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end())
|
||||
preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID];
|
||||
preset.is_external = true;
|
||||
preset.version = *version;
|
||||
inherit_preset = collection->find_preset(inherits_value, false, true); // pointer maybe wrong after insert, redo find
|
||||
if (inherit_preset) preset.base_id = inherit_preset->setting_id;
|
||||
Preset::normalize(preset.config);
|
||||
// Report configuration fields, which are misplaced into a wrong group.
|
||||
const Preset &default_preset = collection->default_preset_for(new_config);
|
||||
std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config);
|
||||
if (!incorrect_keys.empty())
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << preset.file << "\" contains the following incorrect keys: " << incorrect_keys
|
||||
<< ", which were removed";
|
||||
if (!config_substitutions.empty())
|
||||
substitutions.push_back({name, collection->type(), PresetConfigSubstitutions::Source::UserFile, file, std::move(config_substitutions)});
|
||||
|
||||
preset.save(inherit_preset ? &inherit_preset->config : nullptr);
|
||||
result.push_back(file);
|
||||
} catch (const std::ifstream::failure &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("The config cannot be loaded: %1%. Reason: %2%") % file % err.what();
|
||||
} catch (const std::runtime_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Failed importing config file: %1%. Reason: %2%") % file % err.what();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//BBS save user preset to user_id preset folder
|
||||
void PresetBundle::save_user_presets(AppConfig& config, std::vector<std::string>& need_to_delete_list)
|
||||
{
|
||||
@@ -867,26 +962,80 @@ void PresetBundle::update_system_preset_setting_ids(std::map<std::string, std::m
|
||||
}
|
||||
|
||||
//BBS: validate printers from previous project
|
||||
bool PresetBundle::validate_printers(const std::string &name, DynamicPrintConfig& config)
|
||||
static std::set<std::string> gcodes_key_set = {"filament_end_gcode", "filament_start_gcode", "change_filament_gcode", "layer_change_gcode", "machine_end_gcode", "machine_pause_gcode", "machine_start_gcode",
|
||||
"template_custom_gcode", "printing_by_object_gcode", "before_layer_change_gcode", "time_lapse_gcode"};
|
||||
int PresetBundle::validate_presets(const std::string &file_name, DynamicPrintConfig& config, std::set<std::string>& different_gcodes)
|
||||
{
|
||||
// BBS TODO:
|
||||
#if 0
|
||||
std::vector<std::string> inherits_values;
|
||||
PrinterTechnology printer_technology = Preset::printer_technology(config);
|
||||
size_t num_extruders = (printer_technology == ptFFF) ?
|
||||
std::min(config.option<ConfigOptionFloats>("nozzle_diameter" )->values.size(),
|
||||
config.option<ConfigOptionFloats>("filament_diameter")->values.size()) : 1;
|
||||
inherits_values.resize(num_extruders + 2, std::string());
|
||||
inherits_values = config.option<ConfigOptionStrings>("inherits_group", true)->values;
|
||||
bool validated = false;
|
||||
std::vector<std::string> inherits_values = config.option<ConfigOptionStrings>("inherits_group", true)->values;
|
||||
std::vector<std::string> filament_preset_name = config.option<ConfigOptionStrings>("filament_settings_id", true)->values;
|
||||
std::string printer_preset = config.option<ConfigOptionString>("printer_settings_id", true)->value;
|
||||
bool has_different_settings_to_system = config.option("different_settings_to_system")?true:false;
|
||||
std::vector<std::string> different_values;
|
||||
int ret = VALIDATE_PRESETS_SUCCESS;
|
||||
|
||||
std::string inherits;
|
||||
if (inherits_values.size() >= (num_extruders + 2))
|
||||
inherits = inherits_values[num_extruders + 1];
|
||||
if (has_different_settings_to_system)
|
||||
different_values = config.option<ConfigOptionStrings>("different_settings_to_system", true)->values;
|
||||
|
||||
return this->printers.validate_printers(name, config, inherits);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
//PrinterTechnology printer_technology = Preset::printer_technology(config);
|
||||
size_t filament_count = config.option<ConfigOptionFloats>("filament_diameter")->values.size();
|
||||
inherits_values.resize(filament_count + 2, std::string());
|
||||
different_values.resize(filament_count + 2, std::string());
|
||||
filament_preset_name.resize(filament_count, std::string());
|
||||
|
||||
std::string printer_inherits = inherits_values[filament_count + 1];
|
||||
|
||||
validated = this->printers.validate_preset(printer_preset, printer_inherits);
|
||||
if (!validated) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found the printer preset not inherit from system") % file_name;
|
||||
different_gcodes.emplace(printer_preset);
|
||||
ret = VALIDATE_PRESETS_PRINTER_NOT_FOUND;
|
||||
}
|
||||
for(unsigned int index = 0; index < filament_count; index ++)
|
||||
{
|
||||
std::string filament_preset = filament_preset_name[index];
|
||||
std::string filament_inherits = inherits_values[index+1];
|
||||
|
||||
validated = this->filaments.validate_preset(filament_preset, filament_inherits);
|
||||
if (!validated) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found the filament %2% preset not inherit from system") % file_name %(index+1);
|
||||
different_gcodes.emplace(filament_preset);
|
||||
ret = VALIDATE_PRESETS_FILAMENTS_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
//self defined presets, return directly
|
||||
if (ret)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found self defined presets, count %2%") %file_name %different_gcodes.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
for(unsigned int index = 1; index < filament_count+2; index ++)
|
||||
{
|
||||
std::string different_settingss = different_values[index];
|
||||
|
||||
std::vector<std::string> different_keys;
|
||||
|
||||
Slic3r::unescape_strings_cstyle(different_settingss, different_keys);
|
||||
|
||||
for (unsigned int j = 0; j < different_keys.size(); j++) {
|
||||
if (gcodes_key_set.find(different_keys[j]) != gcodes_key_set.end()) {
|
||||
different_gcodes.emplace(different_keys[j]);
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":preset index %1%, different key %2%") %index %different_keys[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!different_gcodes.empty())
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found different gcodes count %2%") %file_name %different_gcodes.size();
|
||||
return VALIDATE_PRESETS_MODIFIED_GCODES;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":file_name %1%, validate presets success!") % file_name;
|
||||
|
||||
return VALIDATE_PRESETS_SUCCESS;
|
||||
}
|
||||
|
||||
void PresetBundle::remove_users_preset(AppConfig &config, std::map<std::string, std::map<std::string, std::string>> *my_presets)
|
||||
@@ -1113,6 +1262,116 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_pre
|
||||
return std::make_pair(std::move(substitutions), errors_cummulative);
|
||||
}
|
||||
|
||||
std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_models_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%") % compatibility_rule;
|
||||
if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)
|
||||
// Loading system presets, don't log substitutions.
|
||||
compatibility_rule = ForwardCompatibilitySubstitutionRule::EnableSilent;
|
||||
else if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem)
|
||||
// Loading system presets, throw on unknown option value.
|
||||
compatibility_rule = ForwardCompatibilitySubstitutionRule::Disable;
|
||||
|
||||
// Here the vendor specific read only Config Bundles are stored.
|
||||
boost::filesystem::path dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) {
|
||||
std::string vendor_file = dir_entry.path().string();
|
||||
if (Slic3r::is_json_file(vendor_file)) {
|
||||
std::string vendor_name = dir_entry.path().filename().string();
|
||||
// Remove the .json suffix.
|
||||
vendor_name.erase(vendor_name.size() - 5);
|
||||
try {
|
||||
// Load the config bundle, flatten it.
|
||||
append(substitutions, load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadVendorOnly, compatibility_rule).first);
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, errors_cummulative %1%") % errors_cummulative;
|
||||
return std::make_pair(std::move(substitutions), errors_cummulative);
|
||||
}
|
||||
|
||||
std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_filaments_json(ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%") % compatibility_rule;
|
||||
if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)
|
||||
// Loading system presets, don't log substitutions.
|
||||
compatibility_rule = ForwardCompatibilitySubstitutionRule::EnableSilent;
|
||||
else if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem)
|
||||
// Loading system presets, throw on unknown option value.
|
||||
compatibility_rule = ForwardCompatibilitySubstitutionRule::Disable;
|
||||
|
||||
// Here the vendor specific read only Config Bundles are stored.
|
||||
boost::filesystem::path dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
bool first = true;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) {
|
||||
std::string vendor_file = dir_entry.path().string();
|
||||
if (Slic3r::is_json_file(vendor_file)) {
|
||||
std::string vendor_name = dir_entry.path().filename().string();
|
||||
// Remove the .json suffix.
|
||||
vendor_name.erase(vendor_name.size() - 5);
|
||||
try {
|
||||
if (first) {
|
||||
// Reset this PresetBundle and load the first vendor config.
|
||||
append(substitutions, this->load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first);
|
||||
first = false;
|
||||
} else {
|
||||
// Load the other vendor configs, merge them with this PresetBundle.
|
||||
// Report duplicate profiles.
|
||||
PresetBundle other;
|
||||
append(substitutions, other.load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first);
|
||||
std::vector<std::string> duplicates = this->merge_presets(std::move(other));
|
||||
if (!duplicates.empty()) {
|
||||
errors_cummulative += "Found duplicated settings in vendor " + vendor_name + "'s json file lists: ";
|
||||
for (size_t i = 0; i < duplicates.size(); ++i) {
|
||||
if (i > 0) errors_cummulative += ", ";
|
||||
errors_cummulative += duplicates[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, errors_cummulative %1%") % errors_cummulative;
|
||||
return std::make_pair(std::move(substitutions), errors_cummulative);
|
||||
}
|
||||
|
||||
VendorProfile PresetBundle::get_custom_vendor_models() const
|
||||
{
|
||||
VendorProfile vendor;
|
||||
vendor.name = PRESET_CUSTOM_VENDOR;
|
||||
vendor.id = PRESET_CUSTOM_VENDOR;
|
||||
for (auto &preset : printers.get_presets()) {
|
||||
if (preset.is_system) continue;
|
||||
if (printers.get_preset_base(preset) != &preset) continue;
|
||||
if (preset.is_default) continue;
|
||||
auto model = preset.config.opt_string("printer_model");
|
||||
auto variant = preset.config.opt_string("printer_variant");
|
||||
auto iter_model = std::find_if(vendor.models.begin(), vendor.models.end(), [model](VendorProfile::PrinterModel &m) {
|
||||
return m.name == model;
|
||||
});
|
||||
if (iter_model == vendor.models.end()) {
|
||||
iter_model = vendor.models.emplace(vendor.models.end(), VendorProfile::PrinterModel{});
|
||||
iter_model->id = model;
|
||||
iter_model->name = model;
|
||||
iter_model->variants = {VendorProfile::PrinterVariant(variant)};
|
||||
} else {
|
||||
iter_model->variants.push_back(VendorProfile::PrinterVariant(variant));
|
||||
}
|
||||
}
|
||||
return vendor;
|
||||
}
|
||||
|
||||
// Merge one vendor's presets with the other vendor's presets, report duplicates.
|
||||
std::vector<std::string> PresetBundle::merge_presets(PresetBundle &&other)
|
||||
@@ -1181,6 +1440,28 @@ const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& p
|
||||
return presets.get_preset_name_by_alias(alias);
|
||||
}
|
||||
|
||||
//BBS: get filament required hrc by filament type
|
||||
const int PresetBundle::get_required_hrc_by_filament_type(const std::string& filament_type) const
|
||||
{
|
||||
static std::unordered_map<std::string, int>filament_type_to_hrc;
|
||||
if (filament_type_to_hrc.empty()) {
|
||||
for (auto iter = filaments.m_presets.begin(); iter != filaments.m_presets.end(); iter++) {
|
||||
if (iter->vendor && iter->vendor->id == "BBL") {
|
||||
if (iter->config.has("filament_type") && iter->config.has("required_nozzle_HRC")) {
|
||||
auto type = iter->config.opt_string("filament_type", 0);
|
||||
auto hrc = iter->config.opt_int("required_nozzle_HRC", 0);
|
||||
filament_type_to_hrc[type] = hrc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto iter = filament_type_to_hrc.find(filament_type);
|
||||
if (iter != filament_type_to_hrc.end())
|
||||
return iter->second;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//BBS: add project embedded preset logic
|
||||
void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::Type type,
|
||||
const std::vector<std::string>& unselected_options, bool save_to_project)
|
||||
@@ -1570,7 +1851,8 @@ unsigned int PresetBundle::sync_ams_list(unsigned int &unknowns)
|
||||
filament_colors.push_back(filament_color);
|
||||
continue;
|
||||
}
|
||||
auto iter = std::find_if(filaments.begin(), filaments.end(), [&filament_id](auto &f) { return f.is_compatible && f.is_system && f.filament_id == filament_id; });
|
||||
auto iter = std::find_if(filaments.begin(), filaments.end(), [this, &filament_id](auto &f) {
|
||||
return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
|
||||
if (iter == filaments.end()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
|
||||
auto filament_type = ams.opt_string("filament_type", 0u);
|
||||
@@ -1582,7 +1864,9 @@ unsigned int PresetBundle::sync_ams_list(unsigned int &unknowns)
|
||||
});
|
||||
}
|
||||
if (iter == filaments.end())
|
||||
iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) { return f.is_compatible && f.is_system; });
|
||||
iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) {
|
||||
return f.is_compatible && f.is_system;
|
||||
});
|
||||
if (iter == filaments.end())
|
||||
continue;
|
||||
++unknowns;
|
||||
@@ -2087,7 +2371,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
if (is_external)
|
||||
presets.load_external_preset(name_or_path, name, config.opt_string(key, true), config, different_keys, PresetCollection::LoadAndSelect::Always, file_version, filament_id);
|
||||
else
|
||||
presets.load_preset(presets.path_from_name(name), name, config, selected, file_version, is_custom_defined).save(nullptr);
|
||||
presets.load_preset(presets.path_from_name(name, inherits.empty()), name, config, selected, file_version, is_custom_defined).save(nullptr);
|
||||
};
|
||||
|
||||
switch (Preset::printer_technology(config)) {
|
||||
@@ -2156,7 +2440,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
loaded = this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config, filament_different_keys_set, PresetCollection::LoadAndSelect::Always, file_version, filament_id).first;
|
||||
else {
|
||||
// called from Config Wizard.
|
||||
loaded= &this->filaments.load_preset(this->filaments.path_from_name(name), name, config, true, file_version, is_custom_defined);
|
||||
loaded= &this->filaments.load_preset(this->filaments.path_from_name(name, inherits.empty()), name, config, true, file_version, is_custom_defined);
|
||||
loaded->save(nullptr);
|
||||
}
|
||||
this->filament_presets.clear();
|
||||
@@ -2831,10 +3115,9 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
// Enable substitutions for user config bundle, throw an exception when loading a system profile.
|
||||
ConfigSubstitutionContext substitution_context { compatibility_rule };
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string vendor_system_path = data_dir() + "/" + PRESET_SYSTEM_DIR;
|
||||
|
||||
//BBS: add config related logs
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, path %1%, compatibility_rule %2%")%path.c_str()%compatibility_rule;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, path %1%, compatibility_rule %2%")%path.c_str()%compatibility_rule;
|
||||
if (flags.has(LoadConfigBundleAttribute::ResetUserProfile) || flags.has(LoadConfigBundleAttribute::LoadSystem))
|
||||
// Reset this bundle, delete user profile files if SaveImported.
|
||||
this->reset(flags.has(LoadConfigBundleAttribute::SaveImported));
|
||||
@@ -2885,7 +3168,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
auto config_version = Semver::parse(version_str);
|
||||
if (! config_version) {
|
||||
throw ConfigurationError((boost::format("vendor %1%'s config version: %2% invalid\nSuggest cleaning the directory %3% firstly")
|
||||
% vendor_name % version_str %vendor_system_path).str());
|
||||
% vendor_name % version_str % path).str());
|
||||
} else {
|
||||
vendor_profile.config_version = std::move(*config_version);
|
||||
}
|
||||
@@ -2923,10 +3206,16 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
catch(nlohmann::detail::parse_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<<root_file<<" got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% firstly")
|
||||
%root_file %err.what() %vendor_system_path).str());
|
||||
%root_file %err.what() % path).str());
|
||||
//goto __error_process;
|
||||
}
|
||||
|
||||
if (flags.has(LoadConfigBundleAttribute::LoadFilamentOnly)) {
|
||||
machine_model_subfiles.clear();
|
||||
machine_subfiles.clear();
|
||||
process_subfiles.clear();
|
||||
}
|
||||
|
||||
//2) paste the machine model
|
||||
for (auto& machine_model : machine_model_subfiles)
|
||||
{
|
||||
@@ -3005,7 +3294,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
catch(nlohmann::detail::parse_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<< subfile <<" got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% firstly")
|
||||
%subfile %err.what() %vendor_system_path).str());
|
||||
%subfile %err.what() % path).str());
|
||||
}
|
||||
|
||||
if (! model.id.empty() && ! model.variants.empty())
|
||||
@@ -3091,7 +3380,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
}
|
||||
config = *default_config;
|
||||
config.apply(config_src);
|
||||
if (instantiation == "false") {
|
||||
if (instantiation == "false" && "Template" != vendor_name) {
|
||||
config_maps.emplace(preset_name, std::move(config));
|
||||
if ((presets_collection->type() == Preset::TYPE_FILAMENT) && (!filament_id.empty()))
|
||||
filament_id_maps.emplace(preset_name, filament_id);
|
||||
@@ -3169,7 +3458,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
loaded.setting_id = setting_id;
|
||||
loaded.filament_id = filament_id;
|
||||
if (presets_collection->type() == Preset::TYPE_FILAMENT) {
|
||||
if (filament_id.empty()) {
|
||||
if (filament_id.empty() && "Template" != vendor_name) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": can not find filament_id for " << preset_name;
|
||||
//throw ConfigurationError(format("can not find inherits %1% for %2%", inherits, preset_name));
|
||||
reason = "Can not find filament_id for " + preset_name;
|
||||
@@ -3221,7 +3510,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
//parse error
|
||||
std::string subfile_path = path + "/" + vendor_name + "/" + subfile.second;
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", got error when parse process setting from %1%") % subfile_path;
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path %vendor_system_path).str());
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path % path).str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3236,7 +3525,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
//parse error
|
||||
std::string subfile_path = path + "/" + vendor_name + "/" + subfile.second;
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", got error when parse filament setting from %1%") % subfile_path;
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path %vendor_system_path).str());
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path % path).str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3251,7 +3540,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
//parse error
|
||||
std::string subfile_path = path + "/" + vendor_name + "/" + subfile.second;
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", got error when parse printer setting from %1%") % subfile_path;
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path %vendor_system_path).str());
|
||||
throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path % path).str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,14 @@
|
||||
#include <unordered_map>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#define DEFAULT_USER_FOLDER_NAME "default"
|
||||
#define DEFAULT_USER_FOLDER_NAME "default"
|
||||
#define BUNDLE_STRUCTURE_JSON_NAME "bundle_structure.json"
|
||||
|
||||
#define VALIDATE_PRESETS_SUCCESS 0
|
||||
#define VALIDATE_PRESETS_PRINTER_NOT_FOUND 1
|
||||
#define VALIDATE_PRESETS_FILAMENTS_NOT_FOUND 2
|
||||
#define VALIDATE_PRESETS_MODIFIED_GCODES 3
|
||||
|
||||
|
||||
// define an enum class of vendor type
|
||||
enum class VendorType {
|
||||
@@ -57,6 +64,12 @@ public:
|
||||
PresetsConfigSubstitutions load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule rule);
|
||||
PresetsConfigSubstitutions load_user_presets(AppConfig &config, std::map<std::string, std::map<std::string, std::string>>& my_presets, ForwardCompatibilitySubstitutionRule rule);
|
||||
PresetsConfigSubstitutions import_presets(std::vector<std::string> &files, std::function<int(std::string const &)> override_confirm, ForwardCompatibilitySubstitutionRule rule);
|
||||
bool import_json_presets(PresetsConfigSubstitutions & substitutions,
|
||||
std::string & file,
|
||||
std::function<int(std::string const &)> override_confirm,
|
||||
ForwardCompatibilitySubstitutionRule rule,
|
||||
int & overwrite,
|
||||
std::vector<std::string> & result);
|
||||
void save_user_presets(AppConfig& config, std::vector<std::string>& need_to_delete_list);
|
||||
void remove_users_preset(AppConfig &config, std::map<std::string, std::map<std::string, std::string>> * my_presets = nullptr);
|
||||
void update_user_presets_directory(const std::string preset_folder);
|
||||
@@ -64,7 +77,7 @@ public:
|
||||
void update_system_preset_setting_ids(std::map<std::string, std::map<std::string, std::string>>& system_presets);
|
||||
|
||||
//BBS: add API to get previous machine
|
||||
bool validate_printers(const std::string &name, DynamicPrintConfig& config);
|
||||
int validate_presets(const std::string &file_name, DynamicPrintConfig& config, std::set<std::string>& different_gcodes);
|
||||
|
||||
//BBS: add function to generate differed preset for save
|
||||
//the pointer should be freed by the caller
|
||||
@@ -173,6 +186,7 @@ public:
|
||||
// Load a system config bundle.
|
||||
LoadSystem,
|
||||
LoadVendorOnly,
|
||||
LoadFilamentOnly,
|
||||
};
|
||||
using LoadConfigBundleAttributes = enum_bitmask<LoadConfigBundleAttribute>;
|
||||
// Load the config bundle based on the flags.
|
||||
@@ -189,7 +203,7 @@ public:
|
||||
//void export_current_configbundle(const std::string &path);
|
||||
//BBS: add a function to export system presets for cloud-slicer
|
||||
//void export_system_configs(const std::string &path);
|
||||
std::vector<std::string> export_current_configs(const std::string &path, std::function<int(std::string const &)> override_confirm,
|
||||
std::vector<std::string> export_current_configs(const std::string &path, std::function<int(std::string const &)> override_confirm,
|
||||
bool include_modify, bool export_system_settings = false);
|
||||
|
||||
// Enable / disable the "- default -" preset.
|
||||
@@ -218,11 +232,16 @@ public:
|
||||
|
||||
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const;
|
||||
|
||||
const int get_required_hrc_by_filament_type(const std::string& filament_type) const;
|
||||
// Save current preset of a provided type under a new name. If the name is different from the old one,
|
||||
// Unselected option would be reverted to the beginning values
|
||||
//BBS: add project embedded preset logic
|
||||
void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector<std::string>& unselected_options, bool save_to_project = false);
|
||||
|
||||
std::pair<PresetsConfigSubstitutions, std::string> load_system_models_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||
std::pair<PresetsConfigSubstitutions, std::string> load_system_filaments_json(ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||
VendorProfile get_custom_vendor_models() const;
|
||||
|
||||
//BBS: add BBL as default
|
||||
static const char *BBL_BUNDLE;
|
||||
static const char *BBL_DEFAULT_PRINTER_MODEL;
|
||||
|
||||
+32
-22
@@ -31,7 +31,7 @@
|
||||
#include "Geometry/ConvexHull.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "Support/SupportMaterial.hpp"
|
||||
#include "Thread.hpp"
|
||||
#include "Time.hpp"
|
||||
#include "GCode.hpp"
|
||||
@@ -102,6 +102,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"printable_area",
|
||||
//BBS: add bed_exclude_area
|
||||
"bed_exclude_area",
|
||||
"thumbnail_size",
|
||||
"before_layer_change_gcode",
|
||||
"enable_pressure_advance",
|
||||
"pressure_advance",
|
||||
@@ -113,6 +114,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"deretraction_speed",
|
||||
"close_fan_the_first_x_layers",
|
||||
"machine_end_gcode",
|
||||
"printing_by_object_gcode",
|
||||
"filament_end_gcode",
|
||||
"post_process",
|
||||
"extruder_clearance_height_to_rod",
|
||||
@@ -183,6 +185,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"nozzle_hrc",
|
||||
"required_nozzle_HRC",
|
||||
"upward_compatible_machine",
|
||||
"is_infill_first",
|
||||
// Orca
|
||||
"chamber_temperature",
|
||||
"thumbnails",
|
||||
@@ -310,7 +313,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
//|| opt_key == "resolution"
|
||||
//BBS: when enable arc fitting, we must re-generate perimeter
|
||||
|| opt_key == "enable_arc_fitting"
|
||||
|| opt_key == "wall_infill_order") {
|
||||
|| opt_key == "wall_sequence") {
|
||||
osteps.emplace_back(posPerimeters);
|
||||
osteps.emplace_back(posEstimateCurledExtrusions);
|
||||
osteps.emplace_back(posInfill);
|
||||
@@ -1145,19 +1148,19 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam
|
||||
|| std::abs((filament_diam - first_filament_diam) / first_filament_diam) > 0.1)
|
||||
// BBS: remove L()
|
||||
return { ("Different nozzle diameters and different filament diameters is not allowed when prime tower is enabled.") };
|
||||
return { L("Different nozzle diameters and different filament diameters is not allowed when prime tower is enabled.") };
|
||||
}
|
||||
|
||||
if (! m_config.use_relative_e_distances)
|
||||
return { ("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") };
|
||||
return { L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") };
|
||||
if (m_config.ooze_prevention)
|
||||
return { ("Ooze prevention is currently not supported with the prime tower enabled.") };
|
||||
return { L("Ooze prevention is currently not supported with the prime tower enabled.") };
|
||||
|
||||
// BBS: remove following logic and _L()
|
||||
#if 0
|
||||
if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware &&
|
||||
m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && m_config.gcode_flavor != gcfMarlinFirmware)
|
||||
return {("The prime tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.")};
|
||||
return { L("The prime tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.")};
|
||||
|
||||
if ((m_config.print_sequence == PrintSequence::ByObject) && extruders.size() > 1)
|
||||
return { L("The prime tower is not supported in \"By object\" print."), nullptr, "enable_prime_tower" };
|
||||
@@ -1339,13 +1342,6 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
if (layer_height > min_nozzle_diameter)
|
||||
return {L("Layer height cannot exceed nozzle diameter"), object, "layer_height"};
|
||||
|
||||
for (auto range : object->m_model_object->layer_config_ranges) {
|
||||
double range_layer_height = range.second.opt_float("layer_height");
|
||||
if (range_layer_height > object->m_slicing_params.max_layer_height ||
|
||||
range_layer_height < object->m_slicing_params.min_layer_height)
|
||||
return { L("Layer height cannot exceed nozzle diameter"), nullptr, "layer_height" };
|
||||
}
|
||||
|
||||
// Validate extrusion widths.
|
||||
std::string err_msg;
|
||||
if (!validate_extrusion_width(object->config(), "line_width", layer_height, err_msg))
|
||||
@@ -1626,16 +1622,21 @@ std::map<ObjectID, unsigned int> getObjectExtruderMap(const Print& print) {
|
||||
std::map<ObjectID, unsigned int> objectExtruderMap;
|
||||
for (const PrintObject* object : print.objects()) {
|
||||
// BBS
|
||||
unsigned int objectFirstLayerFirstExtruder = print.config().filament_diameter.size();
|
||||
auto firstLayerRegions = object->layers().front()->regions();
|
||||
if (!firstLayerRegions.empty()) {
|
||||
for (const LayerRegion* regionPtr : firstLayerRegions) {
|
||||
if (regionPtr -> has_extrusions())
|
||||
objectFirstLayerFirstExtruder = std::min(objectFirstLayerFirstExtruder,
|
||||
regionPtr->region().extruder(frExternalPerimeter));
|
||||
if (object->object_first_layer_wall_extruders.empty()){
|
||||
unsigned int objectFirstLayerFirstExtruder = print.config().filament_diameter.size();
|
||||
auto firstLayerRegions = object->layers().front()->regions();
|
||||
if (!firstLayerRegions.empty()) {
|
||||
for (const LayerRegion* regionPtr : firstLayerRegions) {
|
||||
if (regionPtr->has_extrusions())
|
||||
objectFirstLayerFirstExtruder = std::min(objectFirstLayerFirstExtruder,
|
||||
regionPtr->region().extruder(frExternalPerimeter));
|
||||
}
|
||||
}
|
||||
objectExtruderMap.insert(std::make_pair(object->id(), objectFirstLayerFirstExtruder));
|
||||
}
|
||||
else {
|
||||
objectExtruderMap.insert(std::make_pair(object->id(), object->object_first_layer_wall_extruders.front()));
|
||||
}
|
||||
objectExtruderMap.insert(std::make_pair(object->id(), objectFirstLayerFirstExtruder));
|
||||
}
|
||||
return objectExtruderMap;
|
||||
}
|
||||
@@ -1841,6 +1842,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
obj->infill();
|
||||
obj->ironing();
|
||||
obj->generate_support_material();
|
||||
obj->detect_overhangs_for_lift();
|
||||
obj->estimate_curled_extrusions();
|
||||
}
|
||||
}
|
||||
@@ -1980,7 +1982,15 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
}
|
||||
|
||||
// BBS
|
||||
if(!m_no_check)
|
||||
bool has_adaptive_layer_height = false;
|
||||
for (PrintObject* obj : m_objects) {
|
||||
if (obj->model_object()->layer_height_profile.empty() == false) {
|
||||
has_adaptive_layer_height = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO adaptive layer height won't work with conflict checker because m_fake_wipe_tower's path is generated using fixed layer height
|
||||
if(!m_no_check && !has_adaptive_layer_height)
|
||||
{
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
auto startTime = Clock::now();
|
||||
|
||||
@@ -437,6 +437,9 @@ public:
|
||||
// BBS: Boundingbox of the first layer
|
||||
BoundingBox firstLayerObjectBrimBoundingBox;
|
||||
|
||||
// BBS: returns 1-based indices of extruders used to print the first layer wall of objects
|
||||
std::vector<int> object_first_layer_wall_extruders;
|
||||
|
||||
// SoftFever
|
||||
size_t get_id() const { return m_id; }
|
||||
void set_id(size_t id) { m_id = id; }
|
||||
@@ -528,6 +531,7 @@ private:
|
||||
|
||||
std::vector < VolumeSlices > firstLayerObjSliceByVolume;
|
||||
std::vector<groupedVolumeSlices> firstLayerObjSliceByGroups;
|
||||
|
||||
// BBS: per object skirt
|
||||
ExtrusionEntityCollection m_skirt;
|
||||
|
||||
@@ -590,8 +594,6 @@ struct FakeWipeTower
|
||||
|
||||
std::vector<ExtrusionPaths> getFakeExtrusionPathsFromWipeTower() const
|
||||
{
|
||||
float h = height;
|
||||
float lh = layer_height;
|
||||
int d = scale_(depth);
|
||||
int w = scale_(width);
|
||||
int bd = scale_(brim_width);
|
||||
@@ -599,13 +601,13 @@ struct FakeWipeTower
|
||||
Point maxCorner = {minCorner.x() + w, minCorner.y() + d};
|
||||
|
||||
std::vector<ExtrusionPaths> paths;
|
||||
for (float hh = 0.f; hh < h; hh += lh) {
|
||||
ExtrusionPath path(ExtrusionRole::erWipeTower, 0.0, 0.0, lh);
|
||||
for (float h = 0.f; h < height; h += layer_height) {
|
||||
ExtrusionPath path(ExtrusionRole::erWipeTower, 0.0, 0.0, layer_height);
|
||||
path.polyline = {minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner};
|
||||
paths.push_back({path});
|
||||
|
||||
if (hh == 0.f) { // add brim
|
||||
ExtrusionPath fakeBrim(ExtrusionRole::erBrim, 0.0, 0.0, lh);
|
||||
if (h == 0.f) { // add brim
|
||||
ExtrusionPath fakeBrim(ExtrusionRole::erBrim, 0.0, 0.0, layer_height);
|
||||
Point wtbminCorner = {minCorner - Point{bd, bd}};
|
||||
Point wtbmaxCorner = {maxCorner + Point{bd, bd}};
|
||||
fakeBrim.polyline = {wtbminCorner, {wtbmaxCorner.x(), wtbminCorner.y()}, wtbmaxCorner, {wtbminCorner.x(), wtbmaxCorner.y()}, wtbminCorner};
|
||||
|
||||
@@ -22,6 +22,7 @@ enum StringExceptionType {
|
||||
STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMP = 2,
|
||||
STRING_EXCEPT_OBJECT_COLLISION_IN_SEQ_PRINT = 3,
|
||||
STRING_EXCEPT_OBJECT_COLLISION_IN_LAYER_PRINT = 4,
|
||||
STRING_EXCEPT_LAYER_HEIGHT_EXCEEDS_LIMIT = 5,
|
||||
STRING_EXCEPT_COUNT
|
||||
};
|
||||
|
||||
|
||||
+243
-85
@@ -179,6 +179,15 @@ static t_config_enum_values s_keys_map_WallInfillOrder {
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(WallInfillOrder)
|
||||
|
||||
//BBS
|
||||
static t_config_enum_values s_keys_map_WallSequence {
|
||||
{ "inner wall/outer wall", int(WallSequence::InnerOuter) },
|
||||
{ "outer wall/inner wall", int(WallSequence::OuterInner) },
|
||||
{ "inner-outer-inner wall", int(WallSequence::InnerOuterInner)}
|
||||
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(WallSequence)
|
||||
|
||||
//BBS
|
||||
static t_config_enum_values s_keys_map_PrintSequence {
|
||||
{ "by layer", int(PrintSequence::ByLayer) },
|
||||
@@ -309,6 +318,13 @@ static const t_config_enum_values s_keys_map_BedType = {
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BedType)
|
||||
|
||||
// BBS
|
||||
static const t_config_enum_values s_keys_map_FirstLayerSeq = {
|
||||
{ "Auto", flsAuto },
|
||||
{ "Customize", flsCutomize },
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FirstLayerSeq)
|
||||
|
||||
static t_config_enum_values s_keys_map_NozzleType {
|
||||
{ "undefine", int(NozzleType::ntUndefine) },
|
||||
{ "hardened_steel", int(NozzleType::ntHardenedSteel) },
|
||||
@@ -405,11 +421,13 @@ void PrintConfigDef::init_common_params()
|
||||
def = this->add("bed_custom_texture", coString);
|
||||
def->label = L("Bed custom texture");
|
||||
def->mode = comAdvanced;
|
||||
def->gui_type = ConfigOptionDef::GUIType::one_string;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("bed_custom_model", coString);
|
||||
def->label = L("Bed custom model");
|
||||
def->mode = comAdvanced;
|
||||
def->gui_type = ConfigOptionDef::GUIType::one_string;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("elefant_foot_compensation", coFloat);
|
||||
@@ -677,6 +695,17 @@ void PrintConfigDef::init_fff_params()
|
||||
def->max = 16;
|
||||
def->set_default_value(new ConfigOptionInts{0});
|
||||
|
||||
def = this->add("first_layer_sequence_choice", coEnum);
|
||||
def->category = L("Quality");
|
||||
def->label = L("First layer filament sequence");
|
||||
def->enum_keys_map = &ConfigOptionEnum<FirstLayerSeq>::get_enum_values();
|
||||
def->enum_values.push_back("Auto");
|
||||
def->enum_values.push_back("Customize");
|
||||
def->enum_labels.push_back(L("Auto"));
|
||||
def->enum_labels.push_back(L("Customize"));
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionEnum<FirstLayerSeq>(flsAuto));
|
||||
|
||||
def = this->add("before_layer_change_gcode", coString);
|
||||
def->label = L("Before layer change G-code");
|
||||
def->tooltip = L("This G-code is inserted at every layer change before lifting z");
|
||||
@@ -1191,6 +1220,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString("M104 S0 ; turn off temperature\nG28 X0 ; home X axis\nM84 ; disable motors\n"));
|
||||
|
||||
def = this->add("printing_by_object_gcode", coString);
|
||||
def->label = L("Between Object Gcode");
|
||||
def->tooltip = L("Insert Gcode between objects. This parameter will only come into effect when you print your models object by object");
|
||||
def->multiline = true;
|
||||
def->full_width = true;
|
||||
def->height = 12;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("filament_end_gcode", coStrings);
|
||||
def->label = L("End G-code");
|
||||
def->tooltip = L("End G-code when finish the printing of this filament");
|
||||
@@ -1292,23 +1330,26 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("wall_infill_order", coEnum);
|
||||
def->label = L("Order of inner wall/outer wall/infil");
|
||||
def = this->add("wall_sequence", coEnum);
|
||||
def->label = L("Order of walls");
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Print sequence of inner wall, outer wall and infill. ");
|
||||
def->enum_keys_map = &ConfigOptionEnum<WallInfillOrder>::get_enum_values();
|
||||
def->enum_values.push_back("inner wall/outer wall/infill");
|
||||
def->enum_values.push_back("outer wall/inner wall/infill");
|
||||
def->enum_values.push_back("infill/inner wall/outer wall");
|
||||
def->enum_values.push_back("infill/outer wall/inner wall");
|
||||
def->enum_values.push_back("inner-outer-inner wall/infill");
|
||||
def->enum_labels.push_back(L("inner/outer/infill"));
|
||||
def->enum_labels.push_back(L("outer/inner/infill"));
|
||||
def->enum_labels.push_back(L("infill/inner/outer"));
|
||||
def->enum_labels.push_back(L("infill/outer/inner"));
|
||||
def->enum_labels.push_back(L("inner-outer-inner/infill"));
|
||||
def->tooltip = L("Print sequence of inner wall and outer wall. ");
|
||||
def->enum_keys_map = &ConfigOptionEnum<WallSequence>::get_enum_values();
|
||||
def->enum_values.push_back("inner wall/outer wall");
|
||||
def->enum_values.push_back("outer wall/inner wall");
|
||||
def->enum_values.push_back("inner-outer-inner wall");
|
||||
def->enum_labels.push_back(L("inner/outer"));
|
||||
def->enum_labels.push_back(L("outer/inner"));
|
||||
def->enum_labels.push_back(L("inner wall/outer wall/inner wall"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<WallInfillOrder>(WallInfillOrder::InnerOuterInfill));
|
||||
def->set_default_value(new ConfigOptionEnum<WallSequence>(WallSequence::InnerOuter));
|
||||
|
||||
def = this->add("is_infill_first",coBool);
|
||||
def->label = L("Print infill first");
|
||||
def->tooltip = L("Order of wall/infill. false means print wall first. ");
|
||||
def->category = L("Quality");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool{false});
|
||||
|
||||
def = this->add("extruder", coInt);
|
||||
def->gui_type = ConfigOptionDef::GUIType::i_enum_open;
|
||||
@@ -1906,7 +1947,7 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def = this->add("accel_to_decel_factor", coPercent);
|
||||
def->label = L("accel_to_decel");
|
||||
def->tooltip = L("Klipper's max_accel_to_decel will be adjusted to this %% of acceleration");
|
||||
def->sidetext = L("%%");
|
||||
def->sidetext = L("%");
|
||||
def->min = 1;
|
||||
def->max = 100;
|
||||
def->mode = comAdvanced;
|
||||
@@ -2390,6 +2431,27 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("mmu_segmented_region_max_width", coFloat);
|
||||
def->label = L("Maximum width of a segmented region");
|
||||
def->tooltip = L("Maximum width of a segmented region. Zero disables this feature.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->category = L("Advanced");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.));
|
||||
|
||||
def = this->add("mmu_segmented_region_interlocking_depth", coFloat);
|
||||
def->label = L("Interlocking depth of a segmented region");
|
||||
//def->tooltip = L("Interlocking depth of a segmented region. It will be ignored if "
|
||||
// "\"mmu_segmented_region_max_width\" is zero or if \"mmu_segmented_region_interlocking_depth\""
|
||||
// "is bigger then \"mmu_segmented_region_max_width\". Zero disables this feature.");
|
||||
def->tooltip = L("Interlocking depth of a segmented region. Zero disables this feature.");
|
||||
def->sidetext = L("mm"); //(zero to disable)
|
||||
def->min = 0;
|
||||
def->category = L("Advanced");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.));
|
||||
|
||||
def = this->add("ironing_type", coEnum);
|
||||
def->label = L("Ironing Type");
|
||||
def->category = L("Quality");
|
||||
@@ -3072,8 +3134,27 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
"Using spiral line to lift z can prevent stringing");
|
||||
def->sidetext = L("mm");
|
||||
def->mode = comSimple;
|
||||
def->min = 0;
|
||||
def->max = 5;
|
||||
def->set_default_value(new ConfigOptionFloats { 0.4 });
|
||||
|
||||
def = this->add("retract_lift_above", coFloats);
|
||||
def->label = L("Z hop lower boundary");
|
||||
def->tooltip = L("Z hop will only come into effect when Z is above this value and is below the parameter: \"Z hop upper boundary\"");
|
||||
def->sidetext = L("mm");
|
||||
def->mode = comAdvanced;
|
||||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionFloats{0.});
|
||||
|
||||
def = this->add("retract_lift_below", coFloats);
|
||||
def->label = L("Z hop upper boundary");
|
||||
def->tooltip = L("If this value is positive, Z hop will only come into effect when Z is above the parameter: \"Z hop lower boundary\" and is below this value");
|
||||
def->sidetext = L("mm");
|
||||
def->mode = comAdvanced;
|
||||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionFloats{0.});
|
||||
|
||||
|
||||
def = this->add("z_hop_types", coEnums);
|
||||
def->label = L("Z hop type");
|
||||
def->tooltip = L("Z hop type");
|
||||
@@ -3223,7 +3304,7 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->tooltip = L("Distance from skirt to brim or object");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->max = 10;
|
||||
def->max = 60;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(2));
|
||||
|
||||
@@ -3570,7 +3651,14 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->tooltip = L("Filament to print support base and raft. \"Default\" means no specific filament for support and current filament is used");
|
||||
def->min = 0;
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
def->set_default_value(new ConfigOptionInt(0));
|
||||
|
||||
def = this->add("support_interface_not_for_body",coBool);
|
||||
def->label = L("Reduce interface filament for base");
|
||||
def->category = L("Support");
|
||||
def->tooltip = L("Avoid using support interface filament to print support base");
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("support_line_width", coFloatOrPercent);
|
||||
def->label = L("Support");
|
||||
@@ -3599,7 +3687,7 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->min = 0;
|
||||
// BBS
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
def->set_default_value(new ConfigOptionInt(0));
|
||||
|
||||
auto support_interface_top_layers = def = this->add("support_interface_top_layers", coInt);
|
||||
def->gui_type = ConfigOptionDef::GUIType::i_enum_open;
|
||||
@@ -3623,14 +3711,12 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->gui_type = ConfigOptionDef::GUIType::i_enum_open;
|
||||
def->label = L("Bottom interface layers");
|
||||
def->category = L("Support");
|
||||
//def->tooltip = L("Number of bottom interface layers. "
|
||||
// "-1 means same with use top interface layers");
|
||||
def->tooltip = L("Number of bottom interface layers");
|
||||
def->sidetext = L("layers");
|
||||
def->min = -1;
|
||||
def->enum_values.push_back("-1");
|
||||
append(def->enum_values, support_interface_top_layers->enum_values);
|
||||
//TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible
|
||||
def->enum_labels.push_back("-1");
|
||||
def->enum_labels.push_back(L("Same as top"));
|
||||
append(def->enum_labels, support_interface_top_layers->enum_labels);
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInt(0));
|
||||
@@ -3681,7 +3767,7 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->enum_labels.push_back(L("Lightning"));
|
||||
def->enum_labels.push_back(L("Hollow"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<SupportMaterialPattern>(smpRectilinear));
|
||||
def->set_default_value(new ConfigOptionEnum<SupportMaterialPattern>(smpDefault));
|
||||
|
||||
def = this->add("support_interface_pattern", coEnum);
|
||||
def->label = L("Interface pattern");
|
||||
@@ -3701,7 +3787,7 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->enum_labels.push_back(L("Rectilinear Interlaced"));
|
||||
def->enum_labels.push_back(L("Grid"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<SupportMaterialInterfacePattern>(smipRectilinear));
|
||||
def->set_default_value(new ConfigOptionEnum<SupportMaterialInterfacePattern>(smipAuto));
|
||||
|
||||
def = this->add("support_base_pattern_spacing", coFloat);
|
||||
def->label = L("Base pattern spacing");
|
||||
@@ -3919,12 +4005,12 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloat(3.));
|
||||
|
||||
def = this->add("tree_support_wall_count", coInt);
|
||||
def->label = L("Tree support wall loops");
|
||||
def->label = L("Support wall loops");
|
||||
def->category = L("Support");
|
||||
def->tooltip = L("This setting specify the count of walls around tree support");
|
||||
def->tooltip = L("This setting specify the count of walls around support");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
def->set_default_value(new ConfigOptionInt(0));
|
||||
|
||||
def = this->add("tree_support_with_infill", coBool);
|
||||
def->label = L("Tree support with infill");
|
||||
@@ -4126,7 +4212,7 @@ def = this->add("filament_loading_speed", coFloats);
|
||||
//def->sidetext = L("mm");
|
||||
def->mode = comDevelop;
|
||||
// BBS: change data type to floats to add partplate logic
|
||||
def->set_default_value(new ConfigOptionFloats{ 165.-10. });
|
||||
def->set_default_value(new ConfigOptionFloats{ 15. });
|
||||
|
||||
def = this->add("wipe_tower_y", coFloats);
|
||||
//def->label = L("Position Y");
|
||||
@@ -5207,6 +5293,19 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||
}
|
||||
} else if (opt_key == "overhang_fan_threshold" && value == "5%") {
|
||||
value = "10%";
|
||||
} else if( opt_key == "wall_infill_order" ) {
|
||||
if (value == "inner wall/outer wall/infill" || value == "infill/inner wall/outer wall") {
|
||||
opt_key = "wall_sequence";
|
||||
value = "inner wall/outer wall";
|
||||
} else if (value == "outer wall/inner wall/infill" || value == "infill/outer wall/inner wall") {
|
||||
opt_key = "wall_sequence";
|
||||
value = "outer wall/inner wall";
|
||||
} else if (value == "inner-outer-inner wall/infill") {
|
||||
opt_key = "wall_sequence";
|
||||
value = "inner-outer-inner wall";
|
||||
} else {
|
||||
opt_key = "wall_sequence";
|
||||
}
|
||||
} else if(opt_key == "single_extruder_multi_material") {
|
||||
value = "1";
|
||||
}
|
||||
@@ -5229,6 +5328,9 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||
else if (opt_key == "initial_layer_flow_ratio") {
|
||||
opt_key = "bottom_solid_infill_flow_ratio";
|
||||
}
|
||||
else if(opt_key == "ironing_direction") {
|
||||
opt_key = "ironing_angle";
|
||||
}
|
||||
|
||||
// Ignore the following obsolete configuration keys:
|
||||
static std::set<std::string> ignore = {
|
||||
@@ -5245,7 +5347,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||
"can_switch_nozzle_type", "can_add_auxiliary_fan", "extra_flush_volume", "spaghetti_detector", "adaptive_layer_height",
|
||||
"z_hop_type", "z_lift_type", "bed_temperature_difference",
|
||||
"extruder_type",
|
||||
"internal_bridge_support_thickness","extruder_clearance_max_radius"
|
||||
"internal_bridge_support_thickness","extruder_clearance_max_radius", "top_area_threshold"
|
||||
};
|
||||
|
||||
if (ignore.find(opt_key) != ignore.end()) {
|
||||
@@ -5888,20 +5990,20 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def->set_default_value(new ConfigOptionBool(false));*/
|
||||
|
||||
def = this->add("export_3mf", coString);
|
||||
def->label = L("Export 3MF");
|
||||
def->tooltip = L("Export project as 3MF.");
|
||||
def->label = "Export 3MF";
|
||||
def->tooltip = "Export project as 3MF.";
|
||||
def->cli_params = "filename.3mf";
|
||||
def->set_default_value(new ConfigOptionString("output.3mf"));
|
||||
|
||||
def = this->add("export_slicedata", coString);
|
||||
def->label = L("Export slicing data");
|
||||
def->tooltip = L("Export slicing data to a folder.");
|
||||
def->label = "Export slicing data";
|
||||
def->tooltip = "Export slicing data to a folder.";
|
||||
def->cli_params = "slicing_data_directory";
|
||||
def->set_default_value(new ConfigOptionString("cached_data"));
|
||||
|
||||
def = this->add("load_slicedata", coStrings);
|
||||
def->label = L("Load slicing data");
|
||||
def->tooltip = L("Load cached slicing data from directory");
|
||||
def->label = "Load slicing data";
|
||||
def->tooltip = "Load cached slicing data from directory";
|
||||
def->cli_params = "slicing_data_directory";
|
||||
def->set_default_value(new ConfigOptionString("cached_data"));
|
||||
|
||||
@@ -5911,8 +6013,8 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def->set_default_value(new ConfigOptionBool(false));*/
|
||||
|
||||
def = this->add("export_stl", coBool);
|
||||
def->label = L("Export STL");
|
||||
def->tooltip = L("Export the objects as multiple STL.");
|
||||
def->label = "Export STL";
|
||||
def->tooltip = "Export the objects as multiple STL.";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
/*def = this->add("export_gcode", coBool);
|
||||
@@ -5929,27 +6031,33 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def->set_default_value(new ConfigOptionBool(false));*/
|
||||
|
||||
def = this->add("slice", coInt);
|
||||
def->label = L("Slice");
|
||||
def->tooltip = L("Slice the plates: 0-all plates, i-plate i, others-invalid");
|
||||
def->label = "Slice";
|
||||
def->tooltip = "Slice the plates: 0-all plates, i-plate i, others-invalid";
|
||||
def->cli = "slice";
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionInt(0));
|
||||
|
||||
def = this->add("help", coBool);
|
||||
def->label = L("Help");
|
||||
def->tooltip = L("Show command help.");
|
||||
def->label = "Help";
|
||||
def->tooltip = "Show command help.";
|
||||
def->cli = "help|h";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("uptodate", coBool);
|
||||
def->label = L("UpToDate");
|
||||
def->tooltip = L("Update the configs values of 3mf to latest.");
|
||||
def->label = "UpToDate";
|
||||
def->tooltip = "Update the configs values of 3mf to latest.";
|
||||
def->cli = "uptodate";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("load_defaultfila", coBool);
|
||||
def->label = L("Load default filaments");
|
||||
def->tooltip = L("Load first filament as default for those not loaded");
|
||||
def->label = "Load default filaments";
|
||||
def->tooltip = "Load first filament as default for those not loaded";
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("min_save", coBool);
|
||||
def->label = "Minimum save";
|
||||
def->tooltip = "export 3mf with minimum size.";
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
@@ -5960,15 +6068,15 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("mtcpp", coInt);
|
||||
def->label = L("mtcpp");
|
||||
def->tooltip = L("max triangle count per plate for slicing.");
|
||||
def->label = "mtcpp";
|
||||
def->tooltip = "max triangle count per plate for slicing.";
|
||||
def->cli = "mtcpp";
|
||||
def->cli_params = "count";
|
||||
def->set_default_value(new ConfigOptionInt(1000000));
|
||||
|
||||
def = this->add("mstpp", coInt);
|
||||
def->label = L("mstpp");
|
||||
def->tooltip = L("max slicing time per plate in seconds.");
|
||||
def->label = "mstpp";
|
||||
def->tooltip = "max slicing time per plate in seconds.";
|
||||
def->cli = "mstpp";
|
||||
def->cli_params = "time";
|
||||
def->set_default_value(new ConfigOptionInt(300));
|
||||
@@ -5977,12 +6085,11 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def = this->add("no_check", coBool);
|
||||
def->label = L("No check");
|
||||
def->tooltip = L("Do not run any validity checks, such as gcode path conflicts check.");
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("normative_check", coBool);
|
||||
def->label = L("Normative check");
|
||||
def->tooltip = L("Check the normative items.");
|
||||
def->label = "Normative check";
|
||||
def->tooltip = "Check the normative items.";
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
@@ -5997,19 +6104,19 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def->set_default_value(new ConfigOptionBool(false));*/
|
||||
|
||||
def = this->add("info", coBool);
|
||||
def->label = L("Output Model Info");
|
||||
def->tooltip = L("Output the model's information.");
|
||||
def->label = "Output Model Info";
|
||||
def->tooltip = "Output the model's information.";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("export_settings", coString);
|
||||
def->label = L("Export Settings");
|
||||
def->tooltip = L("Export settings to a file.");
|
||||
def->label = "Export Settings";
|
||||
def->tooltip = "Export settings to a file.";
|
||||
def->cli_params = "settings.json";
|
||||
def->set_default_value(new ConfigOptionString("output.json"));
|
||||
|
||||
def = this->add("pipe", coString);
|
||||
def->label = L("Send progress to pipe");
|
||||
def->tooltip = L("Send progress to pipe.");
|
||||
def->label = "Send progress to pipe";
|
||||
def->tooltip = "Send progress to pipe.";
|
||||
def->cli_params = "pipename";
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
}
|
||||
@@ -6053,15 +6160,15 @@ CLITransformConfigDef::CLITransformConfigDef()
|
||||
def->set_default_value(new ConfigOptionPoint(Vec2d(100,100)));*/
|
||||
|
||||
def = this->add("arrange", coInt);
|
||||
def->label = L("Arrange Options");
|
||||
def->tooltip = L("Arrange options: 0-disable, 1-enable, others-auto");
|
||||
def->label = "Arrange Options";
|
||||
def->tooltip = "Arrange options: 0-disable, 1-enable, others-auto";
|
||||
def->cli_params = "option";
|
||||
//def->cli = "arrange|a";
|
||||
def->set_default_value(new ConfigOptionInt(0));
|
||||
|
||||
def = this->add("repetitions", coInt);
|
||||
def->label = L("Repetions count");
|
||||
def->tooltip = L("Repetions count of the whole model");
|
||||
def->label = "Repetions count";
|
||||
def->tooltip = "Repetions count of the whole model";
|
||||
def->cli_params = "count";
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
@@ -6078,16 +6185,17 @@ CLITransformConfigDef::CLITransformConfigDef()
|
||||
|
||||
/*def = this->add("duplicate_grid", coPoint);
|
||||
def->label = L("Duplicate by grid");
|
||||
def->tooltip = L("Multiply copies by creating a grid.");
|
||||
def->tooltip = L("Multiply copies by creating a grid.");*/
|
||||
|
||||
def = this->add("assemble", coBool);
|
||||
def->label = L("Assemble");
|
||||
def->tooltip = L("Arrange the supplied models in a plate and merge them in a single model in order to perform actions once.");
|
||||
def->cli = "merge|m";*/
|
||||
def->label = "Assemble";
|
||||
def->tooltip = "Arrange the supplied models in a plate and merge them in a single model in order to perform actions once.";
|
||||
//def->cli = "merge|m";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("convert_unit", coBool);
|
||||
def->label = L("Convert Unit");
|
||||
def->tooltip = L("Convert the units of model");
|
||||
def->label = "Convert Unit";
|
||||
def->tooltip = "Convert the units of model";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("orient", coInt);
|
||||
@@ -6107,8 +6215,8 @@ CLITransformConfigDef::CLITransformConfigDef()
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("rotate_x", coFloat);
|
||||
def->label = L("Rotate around X");
|
||||
def->tooltip = L("Rotation angle around the X axis in degrees.");
|
||||
def->label = "Rotate around X";
|
||||
def->tooltip = "Rotation angle around the X axis in degrees.";
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("rotate_y", coFloat);
|
||||
@@ -6117,8 +6225,8 @@ CLITransformConfigDef::CLITransformConfigDef()
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("scale", coFloat);
|
||||
def->label = L("Scale");
|
||||
def->tooltip = L("Scale the model by a float factor");
|
||||
def->label = "Scale";
|
||||
def->tooltip = "Scale the model by a float factor";
|
||||
def->cli_params = "factor";
|
||||
def->set_default_value(new ConfigOptionFloat(1.f));
|
||||
|
||||
@@ -6159,29 +6267,47 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
def->tooltip = L("Load configuration from the specified file. It can be used more than once to load options from multiple files.");*/
|
||||
|
||||
def = this->add("load_settings", coStrings);
|
||||
def->label = L("Load General Settings");
|
||||
def->tooltip = L("Load process/machine settings from the specified file");
|
||||
def->label = "Load General Settings";
|
||||
def->tooltip = "Load process/machine settings from the specified file";
|
||||
def->cli_params = "\"setting1.json;setting2.json\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("load_filaments", coStrings);
|
||||
def->label = L("Load Filament Settings");
|
||||
def->tooltip = L("Load filament settings from the specified file list");
|
||||
def->label = "Load Filament Settings";
|
||||
def->tooltip = "Load filament settings from the specified file list";
|
||||
def->cli_params = "\"filament1.json;filament2.json;...\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("skip_objects", coInts);
|
||||
def->label = L("Skip Objects");
|
||||
def->tooltip = L("Skip some objects in this print");
|
||||
def->label = "Skip Objects";
|
||||
def->tooltip = "Skip some objects in this print";
|
||||
def->cli_params = "\"3,5,10,77\"";
|
||||
def->set_default_value(new ConfigOptionInts());
|
||||
|
||||
def = this->add("clone_objects", coInts);
|
||||
def->label = "Clone Objects";
|
||||
def->tooltip = "Clone objects in the load list";
|
||||
def->cli_params = "\"1,3,1,10\"";
|
||||
def->set_default_value(new ConfigOptionInts());
|
||||
|
||||
def = this->add("uptodate_settings", coStrings);
|
||||
def->label = L("load uptodate process/machine settings when using uptodate");
|
||||
def->tooltip = L("load uptodate process/machine settings from the specified file when using uptodate");
|
||||
def->label = "load uptodate process/machine settings when using uptodate";
|
||||
def->tooltip = "load uptodate process/machine settings from the specified file when using uptodate";
|
||||
def->cli_params = "\"setting1.json;setting2.json\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("uptodate_filaments", coStrings);
|
||||
def->label = "load uptodate filament settings when using uptodate";
|
||||
def->tooltip = "load uptodate filament settings from the specified file when using uptodate";
|
||||
def->cli_params = "\"filament1.json;filament2.json;...\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("load_assemble_list", coString);
|
||||
def->label = "Load assemble list";
|
||||
def->tooltip = "Load assemble object list from config file";
|
||||
def->cli_params = "assemble_list.json";
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
/*def = this->add("output", coString);
|
||||
def->label = L("Output File");
|
||||
def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file).");
|
||||
@@ -6205,18 +6331,23 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
|
||||
|
||||
def = this->add("outputdir", coString);
|
||||
def->label = L("Output directory");
|
||||
def->tooltip = L("Output directory for the exported files.");
|
||||
def->label = "Output directory";
|
||||
def->tooltip = "Output directory for the exported files.";
|
||||
def->cli_params = "dir";
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
def = this->add("debug", coInt);
|
||||
def->label = L("Debug level");
|
||||
def->tooltip = L("Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n");
|
||||
def->label = "Debug level";
|
||||
def->tooltip = "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n";
|
||||
def->min = 0;
|
||||
def->cli_params = "level";
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
def = this->add("enable_timelapse", coBool);
|
||||
def->label = "Enable timeplapse for print";
|
||||
def->tooltip = "If enabled, this slicing will be considered using timelapse";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
#if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(SLIC3R_GUI)
|
||||
/*def = this->add("sw_renderer", coBool);
|
||||
def->label = L("Render with a software renderer");
|
||||
@@ -6229,6 +6360,33 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
def->tooltip = L("Load custom gcode from json");
|
||||
def->cli_params = "custom_gcode_toolchange.json";
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
def = this->add("load_filament_ids", coInts);
|
||||
def->label = "Load filament ids";
|
||||
def->tooltip = "Load filament ids for each object";
|
||||
def->cli_params = "\"1,2,3,1\"";
|
||||
def->set_default_value(new ConfigOptionInts());
|
||||
|
||||
def = this->add("allow_multicolor_oneplate", coBool);
|
||||
def->label = "Allow multiple color on one plate";
|
||||
def->tooltip = "If enabled, the arrange will allow multiple color on one plate";
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("allow_rotations", coBool);
|
||||
def->label = "Allow rotatations when arrange";
|
||||
def->tooltip = "If enabled, the arrange will allow rotations when place object";
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("avoid_extrusion_cali_region", coBool);
|
||||
def->label = "Avoid extrusion calibrate region when doing arrange";
|
||||
def->tooltip = "If enabled, the arrange will avoid extrusion calibrate region when place object";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("skip_modified_gcodes", coBool);
|
||||
def->label = "Skip modified gcodes in 3mf";
|
||||
def->tooltip = "Skip the modified gcodes in 3mf from Printer or filament Presets";
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
}
|
||||
|
||||
const CLIActionsConfigDef cli_actions_config_def;
|
||||
|
||||
@@ -90,6 +90,14 @@ enum class WallInfillOrder {
|
||||
InnerOuterInnerInfill,
|
||||
Count,
|
||||
};
|
||||
|
||||
// BBS
|
||||
enum class WallSequence {
|
||||
InnerOuter,
|
||||
OuterInner,
|
||||
InnerOuterInner,
|
||||
Count,
|
||||
};
|
||||
//BBS
|
||||
enum class PrintSequence {
|
||||
ByLayer,
|
||||
@@ -216,6 +224,12 @@ enum BedType {
|
||||
btCount
|
||||
};
|
||||
|
||||
// BBS
|
||||
enum FirstLayerSeq {
|
||||
flsAuto,
|
||||
flsCutomize
|
||||
};
|
||||
|
||||
// BBS
|
||||
enum NozzleType {
|
||||
ntUndefine = 0,
|
||||
@@ -348,7 +362,6 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeThumbnailsFormat)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrintHostType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(AuthorizationType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType)
|
||||
|
||||
#undef CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS
|
||||
|
||||
// Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs.
|
||||
@@ -687,6 +700,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
// Force the generation of solid shells between adjacent materials/volumes.
|
||||
((ConfigOptionBool, interface_shells))
|
||||
((ConfigOptionFloat, layer_height))
|
||||
((ConfigOptionFloat, mmu_segmented_region_max_width))
|
||||
((ConfigOptionFloat, mmu_segmented_region_interlocking_depth))
|
||||
((ConfigOptionFloat, raft_contact_distance))
|
||||
((ConfigOptionFloat, raft_expansion))
|
||||
((ConfigOptionPercent, raft_first_layer_density))
|
||||
@@ -709,6 +724,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionInt, enforce_support_layers))
|
||||
((ConfigOptionInt, support_filament))
|
||||
((ConfigOptionFloatOrPercent, support_line_width))
|
||||
((ConfigOptionBool, support_interface_not_for_body))
|
||||
((ConfigOptionBool, support_interface_loop_pattern))
|
||||
((ConfigOptionInt, support_interface_filament))
|
||||
((ConfigOptionInt, support_interface_top_layers))
|
||||
@@ -735,6 +751,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
// BBS
|
||||
((ConfigOptionBool, flush_into_infill))
|
||||
((ConfigOptionBool, flush_into_support))
|
||||
((ConfigOptionEnum<WallSequence>, wall_sequence))
|
||||
// BBS
|
||||
((ConfigOptionFloat, tree_support_branch_distance))
|
||||
((ConfigOptionFloat, tree_support_tip_diameter))
|
||||
@@ -824,6 +841,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionEnum<InfillPattern>, ironing_pattern))
|
||||
((ConfigOptionPercent, ironing_flow))
|
||||
((ConfigOptionFloat, ironing_spacing))
|
||||
((ConfigOptionFloat, ironing_direction))
|
||||
((ConfigOptionFloat, ironing_speed))
|
||||
((ConfigOptionFloat, ironing_angle))
|
||||
// Detect bridging perimeters
|
||||
@@ -917,7 +935,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
PRINT_CONFIG_CLASS_DEFINE(
|
||||
GCodeConfig,
|
||||
|
||||
((ConfigOptionString, before_layer_change_gcode))
|
||||
((ConfigOptionString, before_layer_change_gcode))
|
||||
((ConfigOptionString, printing_by_object_gcode))
|
||||
((ConfigOptionFloats, deretraction_speed))
|
||||
//BBS
|
||||
((ConfigOptionBool, enable_arc_fitting))
|
||||
@@ -941,6 +960,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionInts, required_nozzle_HRC))
|
||||
// BBS
|
||||
((ConfigOptionBool, scan_first_layer))
|
||||
((ConfigOptionPoints, thumbnail_size))
|
||||
// ((ConfigOptionBool, spaghetti_detector))
|
||||
((ConfigOptionBool, gcode_add_line_number))
|
||||
((ConfigOptionBool, bbl_bed_temperature_gcode))
|
||||
@@ -1037,6 +1057,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
//BBS: add bed_exclude_area
|
||||
((ConfigOptionPoints, bed_exclude_area))
|
||||
// BBS
|
||||
((ConfigOptionString, bed_custom_texture))
|
||||
((ConfigOptionString, bed_custom_model))
|
||||
((ConfigOptionEnum<BedType>, curr_bed_type))
|
||||
((ConfigOptionInts, cool_plate_temp))
|
||||
((ConfigOptionInts, eng_plate_temp))
|
||||
@@ -1141,12 +1163,13 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionInt, slow_down_layers))
|
||||
((ConfigOptionInts, support_material_interface_fan_speed))
|
||||
// Orca: notes for profiles from PrusaSlicer
|
||||
((ConfigOptionStrings, filament_notes))
|
||||
((ConfigOptionString, notes))
|
||||
((ConfigOptionString, printer_notes))
|
||||
((ConfigOptionStrings, filament_notes))
|
||||
((ConfigOptionString, notes))
|
||||
((ConfigOptionString, printer_notes))
|
||||
|
||||
((ConfigOptionBools, activate_chamber_temp_control))
|
||||
((ConfigOptionInts , chamber_temperature))
|
||||
((ConfigOptionBool, is_infill_first))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ using namespace std::literals;
|
||||
#endif
|
||||
|
||||
// #define SLIC3R_DEBUG
|
||||
|
||||
// Make assert active if SLIC3R_DEBUG
|
||||
#ifdef SLIC3R_DEBUG
|
||||
#undef NDEBUG
|
||||
@@ -912,7 +911,8 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
}
|
||||
} else if (
|
||||
opt_key == "wall_loops"
|
||||
|| opt_key == "only_one_wall_top"
|
||||
|| opt_key == "top_one_wall_type"
|
||||
|| opt_key == "min_width_top_surface"
|
||||
|| opt_key == "only_one_wall_first_layer"
|
||||
|| opt_key == "extra_perimeters_on_overhangs"
|
||||
|| opt_key == "initial_layer_line_width"
|
||||
@@ -945,6 +945,8 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
steps.emplace_back(posPerimeters);
|
||||
} else if (
|
||||
opt_key == "layer_height"
|
||||
|| opt_key == "mmu_segmented_region_max_width"
|
||||
|| opt_key == "mmu_segmented_region_interlocking_depth"
|
||||
|| opt_key == "raft_layers"
|
||||
|| opt_key == "raft_contact_distance"
|
||||
|| opt_key == "slice_closing_radius"
|
||||
@@ -995,6 +997,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
|| opt_key == "support_interface_pattern"
|
||||
|| opt_key == "support_interface_loop_pattern"
|
||||
|| opt_key == "support_interface_filament"
|
||||
|| opt_key == "support_interface_not_for_body"
|
||||
|| opt_key == "support_interface_spacing"
|
||||
|| opt_key == "support_bottom_interface_spacing" //BBS
|
||||
|| opt_key == "support_base_pattern"
|
||||
|
||||
@@ -398,14 +398,14 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
|
||||
auto bb = bounding_box(m);
|
||||
Eigen::AlignedBox<float, 3> ebb{bb.min.cast<float>(),
|
||||
bb.max.cast<float>()};
|
||||
|
||||
AABBTreeIndirect::traverse(
|
||||
tree,
|
||||
AABBTreeIndirect::intersecting(ebb),
|
||||
[&part_to_drill, &hollowed_mesh](size_t faceid)
|
||||
{
|
||||
part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[faceid]);
|
||||
});
|
||||
//BBS
|
||||
//AABBTreeIndirect::traverse(
|
||||
// tree,
|
||||
// AABBTreeIndirect::intersecting(ebb),
|
||||
// [&part_to_drill, &hollowed_mesh](size_t faceid)
|
||||
//{
|
||||
// part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[faceid]);
|
||||
//});
|
||||
|
||||
auto cgal_meshpart = MeshBoolean::cgal::triangle_mesh_to_cgal(
|
||||
remove_unconnected_vertices(part_to_drill));
|
||||
|
||||
+10
-10
@@ -430,16 +430,16 @@ std::vector<double> smooth_height_profile(const std::vector<double>& profile, co
|
||||
// return false;
|
||||
//};
|
||||
|
||||
//int count = 0;
|
||||
//std::vector<double> ret = profile;
|
||||
//bool has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP);
|
||||
//while (has_steep_change && count < 6) {
|
||||
// ret = gauss_blur(ret, smoothing_params);
|
||||
// has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP);
|
||||
// count++;
|
||||
//}
|
||||
//return ret;
|
||||
return gauss_blur(profile, smoothing_params);
|
||||
int count = 0;
|
||||
std::vector<double> ret = profile;
|
||||
// bool has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP);
|
||||
while (/*has_steep_change &&*/ count < 6) {
|
||||
ret = gauss_blur(ret, smoothing_params);
|
||||
//has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP);
|
||||
count++;
|
||||
}
|
||||
return ret;
|
||||
// return gauss_blur(profile, smoothing_params);
|
||||
}
|
||||
|
||||
void adjust_layer_height_profile(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,332 @@
|
||||
// Tree supports by Thomas Rahm, losely based on Tree Supports by CuraEngine.
|
||||
// Original source of Thomas Rahm's tree supports:
|
||||
// https://github.com/ThomasRahm/CuraEngine
|
||||
//
|
||||
// Original CuraEngine copyright:
|
||||
// Copyright (c) 2021 Ultimaker B.V.
|
||||
// CuraEngine is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
#ifndef slic3r_TreeSupport_hpp
|
||||
#define slic3r_TreeSupport_hpp
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include "../Point.hpp"
|
||||
#include "../BoundingBox.hpp"
|
||||
#include "../Utils.hpp"
|
||||
#include "TreeModelVolumes.hpp"
|
||||
#include "TreeSupportCommon.hpp"
|
||||
|
||||
// #define TREE_SUPPORT_SHOW_ERRORS
|
||||
|
||||
#ifdef SLIC3R_TREESUPPORTS_PROGRESS
|
||||
// The various stages of the process can be weighted differently in the progress bar.
|
||||
// These weights are obtained experimentally using a small sample size. Sensible weights can differ drastically based on the assumed default settings and model.
|
||||
#define TREE_PROGRESS_TOTAL 10000
|
||||
#define TREE_PROGRESS_PRECALC_COLL TREE_PROGRESS_TOTAL * 0.1
|
||||
#define TREE_PROGRESS_PRECALC_AVO TREE_PROGRESS_TOTAL * 0.4
|
||||
#define TREE_PROGRESS_GENERATE_NODES TREE_PROGRESS_TOTAL * 0.1
|
||||
#define TREE_PROGRESS_AREA_CALC TREE_PROGRESS_TOTAL * 0.3
|
||||
#define TREE_PROGRESS_DRAW_AREAS TREE_PROGRESS_TOTAL * 0.1
|
||||
#define TREE_PROGRESS_GENERATE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3
|
||||
#define TREE_PROGRESS_SMOOTH_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3
|
||||
#define TREE_PROGRESS_FINALIZE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3
|
||||
#endif // SLIC3R_TREESUPPORTS_PROGRESS
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
// Forward declarations
|
||||
class TreeSupport;
|
||||
class Print;
|
||||
class PrintObject;
|
||||
class SupportGeneratorLayer;
|
||||
using SupportGeneratorLayersPtr = std::vector<SupportGeneratorLayer*>;
|
||||
|
||||
namespace TreeSupport3D
|
||||
{
|
||||
|
||||
// The number of vertices in each circle.
|
||||
static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25;
|
||||
|
||||
struct AreaIncreaseSettings
|
||||
{
|
||||
AreaIncreaseSettings(
|
||||
TreeModelVolumes::AvoidanceType type = TreeModelVolumes::AvoidanceType::Fast, coord_t increase_speed = 0,
|
||||
bool increase_radius = false, bool no_error = false, bool use_min_distance = false, bool move = false) :
|
||||
increase_speed{ increase_speed }, type{ type }, increase_radius{ increase_radius }, no_error{ no_error }, use_min_distance{ use_min_distance }, move{ move } {}
|
||||
|
||||
coord_t increase_speed;
|
||||
// Packing for smaller memory footprint of SupportElementState && SupportElementMerging
|
||||
TreeModelVolumes::AvoidanceType type;
|
||||
bool increase_radius : 1;
|
||||
bool no_error : 1;
|
||||
bool use_min_distance : 1;
|
||||
bool move : 1;
|
||||
bool operator==(const AreaIncreaseSettings& other) const
|
||||
{
|
||||
return type == other.type &&
|
||||
increase_speed == other.increase_speed &&
|
||||
increase_radius == other.increase_radius &&
|
||||
no_error == other.no_error &&
|
||||
use_min_distance == other.use_min_distance &&
|
||||
move == other.move;
|
||||
}
|
||||
};
|
||||
|
||||
#define TREE_SUPPORTS_TRACK_LOST
|
||||
|
||||
// C++17 does not support in place initializers of bit values, thus a constructor zeroing the bits is provided.
|
||||
struct SupportElementStateBits {
|
||||
SupportElementStateBits() :
|
||||
to_buildplate(false),
|
||||
to_model_gracious(false),
|
||||
use_min_xy_dist(false),
|
||||
supports_roof(false),
|
||||
can_use_safe_radius(false),
|
||||
skip_ovalisation(false),
|
||||
#ifdef TREE_SUPPORTS_TRACK_LOST
|
||||
lost(false),
|
||||
verylost(false),
|
||||
#endif // TREE_SUPPORTS_TRACK_LOST
|
||||
deleted(false),
|
||||
marked(false)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief The element trys to reach the buildplate
|
||||
*/
|
||||
bool to_buildplate : 1;
|
||||
|
||||
/*!
|
||||
* \brief Will the branch be able to rest completely on a flat surface, be it buildplate or model ?
|
||||
*/
|
||||
bool to_model_gracious : 1;
|
||||
|
||||
/*!
|
||||
* \brief Whether the min_xy_distance can be used to get avoidance or similar. Will only be true if support_xy_overrides_z=Z overrides X/Y.
|
||||
*/
|
||||
bool use_min_xy_dist : 1;
|
||||
|
||||
/*!
|
||||
* \brief True if this Element or any parent provides support to a support roof.
|
||||
*/
|
||||
bool supports_roof : 1;
|
||||
|
||||
/*!
|
||||
* \brief An influence area is considered safe when it can use the holefree avoidance <=> It will not have to encounter holes on its way downward.
|
||||
*/
|
||||
bool can_use_safe_radius : 1;
|
||||
|
||||
/*!
|
||||
* \brief Skip the ovalisation to parent and children when generating the final circles.
|
||||
*/
|
||||
bool skip_ovalisation : 1;
|
||||
|
||||
#ifdef TREE_SUPPORTS_TRACK_LOST
|
||||
// Likely a lost branch, debugging information.
|
||||
bool lost : 1;
|
||||
bool verylost : 1;
|
||||
#endif // TREE_SUPPORTS_TRACK_LOST
|
||||
|
||||
// Not valid anymore, to be deleted.
|
||||
bool deleted : 1;
|
||||
|
||||
// General purpose flag marking a visited element.
|
||||
bool marked : 1;
|
||||
};
|
||||
|
||||
struct SupportElementState : public SupportElementStateBits
|
||||
{
|
||||
int type = 0;
|
||||
coordf_t radius = 0;
|
||||
float print_z = 0;
|
||||
|
||||
/*!
|
||||
* \brief The layer this support elements wants reach
|
||||
*/
|
||||
LayerIndex target_height;
|
||||
|
||||
/*!
|
||||
* \brief The position this support elements wants to support on layer=target_height
|
||||
*/
|
||||
Point target_position;
|
||||
|
||||
/*!
|
||||
* \brief The next position this support elements wants to reach. NOTE: This is mainly a suggestion regarding direction inside the influence area.
|
||||
*/
|
||||
Point next_position;
|
||||
|
||||
/*!
|
||||
* \brief The next height this support elements wants to reach
|
||||
*/
|
||||
LayerIndex layer_idx;
|
||||
|
||||
/*!
|
||||
* \brief The Effective distance to top of this element regarding radius increases and collision calculations.
|
||||
*/
|
||||
uint32_t effective_radius_height;
|
||||
|
||||
/*!
|
||||
* \brief The amount of layers this element is below the topmost layer of this branch.
|
||||
*/
|
||||
uint32_t distance_to_top;
|
||||
|
||||
/*!
|
||||
* \brief The resulting center point around which a circle will be drawn later.
|
||||
* Will be set by setPointsOnAreas
|
||||
*/
|
||||
Point result_on_layer{ std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max() };
|
||||
bool result_on_layer_is_set() const { return this->result_on_layer != Point{ std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max() }; }
|
||||
void result_on_layer_reset() { this->result_on_layer = Point{ std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max() }; }
|
||||
/*!
|
||||
* \brief The amount of extra radius we got from merging branches that could have reached the buildplate, but merged with ones that can not.
|
||||
*/
|
||||
coord_t increased_to_model_radius; // how much to model we increased only relevant for merging
|
||||
|
||||
/*!
|
||||
* \brief Counter about the times the elephant foot was increased. Can be fractions for merge reasons.
|
||||
*/
|
||||
double elephant_foot_increases;
|
||||
|
||||
/*!
|
||||
* \brief The element trys not to move until this dtt is reached, is set to 0 if the element had to move.
|
||||
*/
|
||||
uint32_t dont_move_until;
|
||||
|
||||
/*!
|
||||
* \brief Settings used to increase the influence area to its current state.
|
||||
*/
|
||||
AreaIncreaseSettings last_area_increase;
|
||||
|
||||
/*!
|
||||
* \brief Amount of roof layers that were not yet added, because the branch needed to move.
|
||||
*/
|
||||
uint32_t missing_roof_layers;
|
||||
|
||||
// called by increase_single_area() and increaseAreas()
|
||||
[[nodiscard]] static SupportElementState propagate_down(const SupportElementState& src)
|
||||
{
|
||||
SupportElementState dst{ src };
|
||||
++dst.distance_to_top;
|
||||
--dst.layer_idx;
|
||||
// set to invalid as we are a new node on a new layer
|
||||
dst.result_on_layer_reset();
|
||||
dst.skip_ovalisation = false;
|
||||
return dst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Get the Distance to top regarding the real radius this part will have. This is different from distance_to_top, which is can be used to calculate the top most layer of the branch.
|
||||
* \param elem[in] The SupportElement one wants to know the effectiveDTT
|
||||
* \return The Effective DTT.
|
||||
*/
|
||||
[[nodiscard]] inline size_t getEffectiveDTT(const TreeSupportSettings &settings, const SupportElementState &elem)
|
||||
{
|
||||
return elem.effective_radius_height < settings.increase_radius_until_layer ?
|
||||
(elem.distance_to_top < settings.increase_radius_until_layer ? elem.distance_to_top : settings.increase_radius_until_layer) :
|
||||
elem.effective_radius_height;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Get the Radius, that this element will have.
|
||||
* \param elem[in] The Element.
|
||||
* \return The radius the element has.
|
||||
*/
|
||||
[[nodiscard]] inline coord_t support_element_radius(const TreeSupportSettings &settings, const SupportElementState &elem)
|
||||
{
|
||||
return settings.getRadius(getEffectiveDTT(settings, elem), elem.elephant_foot_increases);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Get the collision Radius of this Element. This can be smaller then the actual radius, as the drawAreas will cut off areas that may collide with the model.
|
||||
* \param elem[in] The Element.
|
||||
* \return The collision radius the element has.
|
||||
*/
|
||||
[[nodiscard]] inline coord_t support_element_collision_radius(const TreeSupportSettings &settings, const SupportElementState &elem)
|
||||
{
|
||||
return settings.getRadius(elem.effective_radius_height, elem.elephant_foot_increases);
|
||||
}
|
||||
|
||||
struct SupportElement
|
||||
{
|
||||
using ParentIndices =
|
||||
#ifdef NDEBUG
|
||||
// To reduce memory allocation in release mode.
|
||||
boost::container::small_vector<int32_t, 4>;
|
||||
#else // NDEBUG
|
||||
// To ease debugging.
|
||||
std::vector<int32_t>;
|
||||
#endif // NDEBUG
|
||||
|
||||
// SupportElement(const SupportElementState &state) : SupportElementState(state) {}
|
||||
SupportElement(const SupportElementState &state, Polygons &&influence_area) : state(state), influence_area(std::move(influence_area)) {}
|
||||
SupportElement(const SupportElementState &state, ParentIndices &&parents, Polygons &&influence_area) :
|
||||
state(state), parents(std::move(parents)), influence_area(std::move(influence_area)) {}
|
||||
|
||||
SupportElementState state;
|
||||
|
||||
/*!
|
||||
* \brief All elements in the layer above the current one that are supported by this element
|
||||
*/
|
||||
ParentIndices parents;
|
||||
|
||||
/*!
|
||||
* \brief The resulting influence area.
|
||||
* Will only be set in the results of createLayerPathing, and will be nullptr inside!
|
||||
*/
|
||||
Polygons influence_area;
|
||||
};
|
||||
|
||||
void tree_supports_show_error(std::string_view message, bool critical);
|
||||
|
||||
using SupportElements = std::deque<SupportElement>;
|
||||
|
||||
[[nodiscard]] inline coord_t support_element_radius(const TreeSupportSettings &settings, const SupportElement &elem)
|
||||
{
|
||||
return support_element_radius(settings, elem.state);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline coord_t support_element_collision_radius(const TreeSupportSettings &settings, const SupportElement &elem)
|
||||
{
|
||||
return support_element_collision_radius(settings, elem.state);
|
||||
}
|
||||
|
||||
void create_layer_pathing(const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector<SupportElements>& move_bounds, std::function<void()> throw_on_cancel);
|
||||
|
||||
void create_nodes_from_area(const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector<SupportElements>& move_bounds, std::function<void()> throw_on_cancel);
|
||||
|
||||
void organic_smooth_branches_avoid_collisions(const PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector<std::pair<SupportElement*, int>>& elements_with_link_down, const std::vector<size_t>& linear_data_layers, std::function<void()> throw_on_cancel);
|
||||
|
||||
indexed_triangle_set draw_branches(PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector<SupportElements>& move_bounds, std::function<void()> throw_on_cancel);
|
||||
|
||||
void slice_branches(PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector<Polygons>& overhangs, std::vector<SupportElements>& move_bounds, const indexed_triangle_set& cummulative_mesh, SupportGeneratorLayersPtr& bottom_contacts, SupportGeneratorLayersPtr& top_contacts, SupportGeneratorLayersPtr& intermediate_layers, SupportGeneratorLayerStorage& layer_storage, std::function<void()> throw_on_cancel);
|
||||
|
||||
void generate_initial_areas(const PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector<Polygons>& overhangs, std::vector<SupportElements>& move_bounds, InterfacePlacer& interface_placer, std::function<void()> throw_on_cancel);
|
||||
|
||||
// Organic specific: Smooth branches and produce one cummulative mesh to be sliced.
|
||||
void organic_draw_branches(
|
||||
PrintObject& print_object,
|
||||
TreeModelVolumes& volumes,
|
||||
const TreeSupportSettings& config,
|
||||
std::vector<SupportElements>& move_bounds,
|
||||
|
||||
// I/O:
|
||||
SupportGeneratorLayersPtr& bottom_contacts,
|
||||
SupportGeneratorLayersPtr& top_contacts,
|
||||
InterfacePlacer& interface_placer,
|
||||
|
||||
// Output:
|
||||
SupportGeneratorLayersPtr& intermediate_layers,
|
||||
SupportGeneratorLayerStorage& layer_storage,
|
||||
|
||||
std::function<void()> throw_on_cancel);
|
||||
|
||||
} // namespace TreeSupport3D
|
||||
|
||||
void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_support, std::function<void()> throw_on_cancel = []{});
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_TreeSupport_hpp */
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Point.hpp"
|
||||
#include "Execution/ExecutionTBB.hpp"
|
||||
#include "Execution/ExecutionSeq.hpp"
|
||||
#include "CutUtils.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Format/STL.hpp"
|
||||
#include <libqhullcpp/Qhull.h>
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Slic3r {
|
||||
|
||||
class TriangleMesh;
|
||||
class TriangleMeshSlicer;
|
||||
|
||||
struct Groove;
|
||||
struct RepairedMeshErrors {
|
||||
// How many edges were united by merging their end points with some other end points in epsilon neighborhood?
|
||||
int edges_fixed = 0;
|
||||
@@ -353,6 +353,7 @@ indexed_triangle_set its_make_frustum_dowel(double r, double h, int sectorCou
|
||||
indexed_triangle_set its_make_pyramid(float base, float height);
|
||||
indexed_triangle_set its_make_sphere(double radius, double fa);
|
||||
indexed_triangle_set its_make_snap(double r, double h, float space_proportion = 0.25f, float bulge_proportion = 0.125f);
|
||||
indexed_triangle_set its_make_groove_plane(const Groove &cur_groove, float rotate_radius, std::vector<Vec3d> &cur_groove_vertices);
|
||||
|
||||
indexed_triangle_set its_convex_hull(const std::vector<Vec3f> &pts);
|
||||
inline indexed_triangle_set its_convex_hull(const indexed_triangle_set &its) { return its_convex_hull(its.vertices); }
|
||||
|
||||
@@ -51,9 +51,12 @@ bool is_equal(float lh, float rh)
|
||||
return abs(lh - rh) <= epson;
|
||||
}
|
||||
|
||||
bool is_less(float lh, float rh)
|
||||
{
|
||||
return lh + epson < rh;
|
||||
bool is_equal_for_sort(float lh, float rh) {
|
||||
return abs(lh - rh) <= 1e-8;
|
||||
}
|
||||
|
||||
bool is_equal(const Vec3f &lh, const Vec3f &rh) {
|
||||
return is_equal(lh[0], rh[0]) && is_equal(lh[1], rh[1]) && is_equal(lh[2], rh[2]);
|
||||
}
|
||||
|
||||
class IntersectionReference
|
||||
@@ -174,7 +177,7 @@ static FacetSliceType slice_facet(
|
||||
// (external on the right of the line)
|
||||
for (int j = 0; j < 3; ++ j) { // loop through facet edges
|
||||
int edge_id;
|
||||
const stl_vertex *a, *b;
|
||||
const stl_vertex *a, *b, *c;
|
||||
int a_id, b_id;
|
||||
{
|
||||
int k = (idx_vertex_lowest + j) % 3;
|
||||
@@ -184,6 +187,7 @@ static FacetSliceType slice_facet(
|
||||
a = vertices + k;
|
||||
b_id = indices[l];
|
||||
b = vertices + l;
|
||||
c = vertices + (k + 2) % 3;
|
||||
}
|
||||
|
||||
// Is edge or face aligned with the cutting plane?
|
||||
@@ -319,6 +323,159 @@ static FacetSliceType slice_facet(
|
||||
return FacetSliceType::NoSlice;
|
||||
}
|
||||
|
||||
// Return true, if the facet has been sliced and line_out has been filled.
|
||||
static FacetSliceType slice_facet_for_cut_mesh(
|
||||
// Z height of the slice in XY plane. Scaled or unscaled (same as vertices[].z()).
|
||||
float slice_z,
|
||||
// 3 vertices of the triangle, XY scaled. Z scaled or unscaled (same as slice_z).
|
||||
const stl_vertex * vertices,
|
||||
const stl_triangle_vertex_indices &indices,
|
||||
const Vec3i & edge_ids,
|
||||
const int idx_vertex_lowest,
|
||||
const bool horizontal,
|
||||
IntersectionLine & line_out)
|
||||
{
|
||||
IntersectionPoint points[3];
|
||||
size_t num_points = 0;
|
||||
auto point_on_layer = size_t(-1);
|
||||
|
||||
// Reorder vertices so that the first one is the one with lowest Z.
|
||||
// This is needed to get all intersection lines in a consistent order
|
||||
// (external on the right of the line)
|
||||
for (int j = 0; j < 3; ++j) { // loop through facet edges
|
||||
int edge_id;
|
||||
const stl_vertex *a, *b, *c;
|
||||
int a_id, b_id;
|
||||
{
|
||||
int k = (idx_vertex_lowest + j) % 3;
|
||||
int l = (k + 1) % 3;
|
||||
edge_id = edge_ids(k);
|
||||
a_id = indices[k];
|
||||
a = vertices + k;
|
||||
b_id = indices[l];
|
||||
b = vertices + l;
|
||||
c = vertices + (k + 2) % 3;
|
||||
}
|
||||
|
||||
// Is edge or face aligned with the cutting plane?
|
||||
if (is_equal(a->z(), slice_z) && is_equal(b->z(), slice_z)) {
|
||||
// Edge is horizontal and belongs to the current layer.
|
||||
// The following rotation of the three vertices may not be efficient, but this branch happens rarely.
|
||||
const stl_vertex &v0 = vertices[0];
|
||||
const stl_vertex &v1 = vertices[1];
|
||||
const stl_vertex &v2 = vertices[2];
|
||||
// We may ignore this edge for slicing purposes, but we may still use it for object cutting.
|
||||
FacetSliceType result = FacetSliceType::Slicing;
|
||||
if (horizontal) {
|
||||
// All three vertices are aligned with slice_z.
|
||||
line_out.edge_type = IntersectionLine::FacetEdgeType::Horizontal;
|
||||
result = FacetSliceType::Cutting;
|
||||
double normal = (v1.x() - v0.x()) * (v2.y() - v1.y()) - (v1.y() - v0.y()) * (v2.x() - v1.x());
|
||||
if (normal < 0) {
|
||||
// If normal points downwards this is a bottom horizontal facet so we reverse its point order.
|
||||
std::swap(a, b);
|
||||
std::swap(a_id, b_id);
|
||||
}
|
||||
} else {
|
||||
// Two vertices are aligned with the cutting plane, the third vertex is below or above the cutting plane.
|
||||
// Is the third vertex below the cutting plane?
|
||||
bool third_below = c->z() < slice_z;
|
||||
// Two vertices on the cutting plane, the third vertex is below the plane. Consider the edge to be part of the slice
|
||||
// only if it is the upper edge.
|
||||
// (the bottom most edge resp. vertex of a triangle is not owned by the triangle, but the top most edge resp. vertex is part of the triangle
|
||||
// in respect to the cutting plane).
|
||||
result = third_below ? FacetSliceType::Slicing : FacetSliceType::Cutting;
|
||||
if (third_below) {
|
||||
line_out.edge_type = IntersectionLine::FacetEdgeType::Top;
|
||||
std::swap(a, b);
|
||||
std::swap(a_id, b_id);
|
||||
} else
|
||||
line_out.edge_type = IntersectionLine::FacetEdgeType::Bottom;
|
||||
}
|
||||
line_out.a.x() = a->x();
|
||||
line_out.a.y() = a->y();
|
||||
line_out.b.x() = b->x();
|
||||
line_out.b.y() = b->y();
|
||||
line_out.a_id = a_id;
|
||||
line_out.b_id = b_id;
|
||||
assert(line_out.a != line_out.b);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (is_equal(a->z(), slice_z)) {
|
||||
// Only point a alings with the cutting plane.
|
||||
if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != a_id) {
|
||||
point_on_layer = num_points;
|
||||
IntersectionPoint &point = points[num_points++];
|
||||
point.x() = a->x();
|
||||
point.y() = a->y();
|
||||
point.point_id = a_id;
|
||||
}
|
||||
} else if (is_equal(b->z(), slice_z)) {
|
||||
// Only point b alings with the cutting plane.
|
||||
if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != b_id) {
|
||||
point_on_layer = num_points;
|
||||
IntersectionPoint &point = points[num_points++];
|
||||
point.x() = b->x();
|
||||
point.y() = b->y();
|
||||
point.point_id = b_id;
|
||||
}
|
||||
} else if ((a->z() < slice_z && b->z() > slice_z) || (b->z() < slice_z && a->z() > slice_z)) {
|
||||
// A general case. The face edge intersects the cutting plane. Calculate the intersection point.
|
||||
assert(a_id != b_id);
|
||||
// Sort the edge to give a consistent answer.
|
||||
if (a_id > b_id) {
|
||||
std::swap(a_id, b_id);
|
||||
std::swap(a, b);
|
||||
}
|
||||
IntersectionPoint &point = points[num_points];
|
||||
double t = (double(slice_z) - double(b->z())) / (double(a->z()) - double(b->z()));
|
||||
if (t <= 0.) {
|
||||
if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != a_id) {
|
||||
point.x() = a->x();
|
||||
point.y() = a->y();
|
||||
point_on_layer = num_points++;
|
||||
point.point_id = a_id;
|
||||
}
|
||||
} else if (t >= 1.) {
|
||||
if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != b_id) {
|
||||
point.x() = b->x();
|
||||
point.y() = b->y();
|
||||
point_on_layer = num_points++;
|
||||
point.point_id = b_id;
|
||||
}
|
||||
} else {
|
||||
point.x() = coord_t(floor(double(b->x()) + (double(a->x()) - double(b->x())) * t + 0.5));
|
||||
point.y() = coord_t(floor(double(b->y()) + (double(a->y()) - double(b->y())) * t + 0.5));
|
||||
point.edge_id = edge_id;
|
||||
++num_points;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Facets must intersect each plane 0 or 2 times, or it may touch the plane at a single vertex only.
|
||||
assert(num_points < 3);
|
||||
if (num_points == 2) {
|
||||
line_out.edge_type = IntersectionLine::FacetEdgeType::General;
|
||||
line_out.a = static_cast<const Point &>(points[1]);
|
||||
line_out.b = static_cast<const Point &>(points[0]);
|
||||
line_out.a_id = points[1].point_id;
|
||||
line_out.b_id = points[0].point_id;
|
||||
line_out.edge_a_id = points[1].edge_id;
|
||||
line_out.edge_b_id = points[0].edge_id;
|
||||
// Not a zero lenght edge.
|
||||
// FIXME slice_facet() may create zero length edges due to rounding of doubles into coord_t.
|
||||
// assert(line_out.a != line_out.b);
|
||||
// The plane cuts at least one edge in a general position.
|
||||
assert(line_out.a_id == -1 || line_out.b_id == -1);
|
||||
assert(line_out.edge_a_id != -1 || line_out.edge_b_id != -1);
|
||||
// General slicing position, use the segment for both slicing and object cutting.
|
||||
|
||||
return FacetSliceType::Slicing;
|
||||
}
|
||||
return FacetSliceType::NoSlice;
|
||||
}
|
||||
|
||||
template<typename TransformVertex>
|
||||
void slice_facet_at_zs(
|
||||
// Scaled or unscaled vertices. transform_vertex_fn may scale zs.
|
||||
@@ -336,12 +493,12 @@ void slice_facet_at_zs(
|
||||
// find facet extents
|
||||
const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z()));
|
||||
const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z()));
|
||||
|
||||
|
||||
// find layer extents
|
||||
auto min_layer = std::lower_bound(zs.begin(), zs.end(), min_z); // first layer whose slice_z is >= min_z
|
||||
auto max_layer = std::upper_bound(min_layer, zs.end(), max_z); // first layer whose slice_z is > max_z
|
||||
int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0);
|
||||
|
||||
|
||||
for (auto it = min_layer; it != max_layer; ++ it) {
|
||||
IntersectionLine il;
|
||||
// Ignore horizontal triangles. Any valid horizontal triangle must have a vertical triangle connected, otherwise the part has zero volume.
|
||||
@@ -396,7 +553,7 @@ static inline IntersectionLines slice_make_lines(
|
||||
const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z()));
|
||||
const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z()));
|
||||
assert(min_z <= plane_z && max_z >= plane_z);
|
||||
int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0);
|
||||
int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0);
|
||||
IntersectionLine il;
|
||||
// Ignore horizontal triangles. Any valid horizontal triangle must have a vertical triangle connected, otherwise the part has zero volume.
|
||||
if (min_z != max_z && slice_facet(plane_z, vertices, indices, face_edge_ids[face_idx], idx_vertex_lowest, false, il) == FacetSliceType::Slicing) {
|
||||
@@ -452,7 +609,7 @@ void slice_facet_with_slabs(
|
||||
const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z()));
|
||||
const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z()));
|
||||
const bool horizontal = min_z == max_z;
|
||||
|
||||
|
||||
// find layer extents
|
||||
auto min_layer = std::lower_bound(zs.begin(), zs.end(), min_z); // first layer whose slice_z is >= min_z
|
||||
auto max_layer = std::upper_bound(min_layer, zs.end(), max_z); // first layer whose slice_z is > max_z
|
||||
@@ -2001,15 +2158,16 @@ void slice_mesh_slabs(
|
||||
|
||||
// Remove duplicates of slice_vertices, optionally triangulate the cut.
|
||||
static void triangulate_slice(
|
||||
indexed_triangle_set &its,
|
||||
IntersectionLines &lines,
|
||||
indexed_triangle_set &its,
|
||||
IntersectionLines &lines,
|
||||
std::vector<int> &slice_vertices,
|
||||
// Vertices of the original (unsliced) mesh. Newly added vertices are those on the slice.
|
||||
int num_original_vertices,
|
||||
// Z height of the slice.
|
||||
float z,
|
||||
bool triangulate,
|
||||
bool normals_down)
|
||||
float z,
|
||||
bool triangulate,
|
||||
bool normals_down,
|
||||
const std::map<int, Vec3f*> §ion_vertices_map)
|
||||
{
|
||||
sort_remove_duplicates(slice_vertices);
|
||||
|
||||
@@ -2019,11 +2177,12 @@ static void triangulate_slice(
|
||||
map_vertex_to_index.reserve(slice_vertices.size());
|
||||
for (int i : slice_vertices)
|
||||
map_vertex_to_index.emplace_back(to_2d(its.vertices[i]), i);
|
||||
std::sort(map_vertex_to_index.begin(), map_vertex_to_index.end(),
|
||||
[](const std::pair<Vec2f, int> &l, const std::pair<Vec2f, int> &r) {
|
||||
return is_less(l.first.x(), r.first.x()) ||
|
||||
(is_equal(l.first.x(), r.first.x()) && (is_less(l.first.y(), r.first.y()) ||
|
||||
(is_equal(l.first.y(), r.first.y()) && l.second < r.second))); });
|
||||
std::sort(map_vertex_to_index.begin(), map_vertex_to_index.end(),
|
||||
[](const std::pair<Vec2f, int> &l, const std::pair<Vec2f, int> &r) {
|
||||
return l.first.x() < r.first.x() ||
|
||||
(is_equal_for_sort(l.first.x(), r.first.x()) && (l.first.y()< r.first.y() ||
|
||||
(is_equal_for_sort(l.first.y(), r.first.y()) && l.second < r.second)));
|
||||
});
|
||||
|
||||
// 2) Discover duplicate points on the slice. Remap duplicate vertices to a vertex with a lowest index.
|
||||
// Remove denegerate triangles, if they happen to be created by merging duplicate vertices.
|
||||
@@ -2072,14 +2231,40 @@ static void triangulate_slice(
|
||||
stl_triangle_vertex_indices facet;
|
||||
for (size_t j = 0; j < 3; ++ j) {
|
||||
Vec3f v = triangles[i ++].cast<float>();
|
||||
auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(),
|
||||
auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(),
|
||||
[&v](const std::pair<Vec2f, int> &l) {
|
||||
return is_less(l.first.x(), v.x()) || (is_equal(l.first.x(), v.x()) && is_less(l.first.y(), v.y()));
|
||||
return l.first.x() < v.x() || (is_equal_for_sort(l.first.x(), v.x()) && l.first.y() < v.y());
|
||||
});
|
||||
int idx = -1;
|
||||
if (it != map_vertex_to_index.end() && is_equal(it->first.x(), v.x()) && is_equal(it->first.y(), v.y()))
|
||||
idx = it->second;
|
||||
else {
|
||||
bool exist = false;
|
||||
for (auto iter = section_vertices_map.begin(); iter != section_vertices_map.end(); iter++) {
|
||||
if (is_equal(v, *iter->second)) {
|
||||
idx = iter->first;
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// go on finding
|
||||
if (!exist) {
|
||||
for (; it != map_vertex_to_index.end(); it++) {
|
||||
if (is_equal(it->first.x(), v.x()) && is_equal(it->first.y(), v.y())) {
|
||||
idx = it->second;
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// go on finding
|
||||
if (!exist) {
|
||||
for (; it != map_vertex_to_index.begin(); it--) {
|
||||
if (is_equal(it->first.x(), v.x()) && is_equal(it->first.y(), v.y())) {
|
||||
idx = it->second;
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!exist){
|
||||
// Try to find the vertex in the list of newly added vertices. Those vertices are not matched on the cut and they shall be rare.
|
||||
for (size_t k = idx_vertex_new_first; k < its.vertices.size(); ++ k)
|
||||
if (its.vertices[k] == v) {
|
||||
@@ -2160,16 +2345,22 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u
|
||||
IntersectionLines upper_lines, lower_lines;
|
||||
std::vector<int> upper_slice_vertices, lower_slice_vertices;
|
||||
std::vector<Vec3i> facets_edge_ids = its_face_edge_ids(mesh);
|
||||
std::map<int, Vec3f *> section_vertices_map;
|
||||
|
||||
for (int facet_idx = 0; facet_idx < int(mesh.indices.size()); ++ facet_idx) {
|
||||
const stl_triangle_vertex_indices &facet = mesh.indices[facet_idx];
|
||||
Vec3f vertices[3] { mesh.vertices[facet(0)], mesh.vertices[facet(1)], mesh.vertices[facet(2)] };
|
||||
float min_z = std::min(vertices[0].z(), std::min(vertices[1].z(), vertices[2].z()));
|
||||
float max_z = std::max(vertices[0].z(), std::max(vertices[1].z(), vertices[2].z()));
|
||||
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (is_equal(z, vertices[i].z()) && section_vertices_map[facet(i)] == nullptr) {
|
||||
section_vertices_map[facet(i)] = new Vec3f(vertices[i].x(), vertices[i].y(), vertices[i].z());
|
||||
}
|
||||
}
|
||||
// intersect facet with cutting plane
|
||||
IntersectionLine line;
|
||||
int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0);
|
||||
int idx_vertex_lowest = is_equal(vertices[1].z(), min_z) ? 1 : (is_equal(vertices[2].z() , min_z) ? 2 : 0);
|
||||
FacetSliceType slice_type = FacetSliceType::NoSlice;
|
||||
if (z > min_z - EPSILON && z < max_z + EPSILON) {
|
||||
Vec3f vertices_scaled[3];
|
||||
@@ -2180,7 +2371,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u
|
||||
dst.y() = scale_(src.y());
|
||||
dst.z() = src.z();
|
||||
}
|
||||
slice_type = slice_facet(z, vertices_scaled, mesh.indices[facet_idx], facets_edge_ids[facet_idx], idx_vertex_lowest, min_z == max_z, line);
|
||||
slice_type = slice_facet_for_cut_mesh(z, vertices_scaled, mesh.indices[facet_idx], facets_edge_ids[facet_idx], idx_vertex_lowest, is_equal(min_z, max_z), line);
|
||||
}
|
||||
|
||||
if (slice_type != FacetSliceType::NoSlice) {
|
||||
@@ -2198,12 +2389,12 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u
|
||||
upper_lines.emplace_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (min_z > z || (min_z == z && max_z > z)) {
|
||||
|
||||
if (min_z > z || (is_equal(min_z , z) && max_z > z)) {
|
||||
// facet is above the cut plane and does not belong to it
|
||||
if (upper != nullptr)
|
||||
upper->indices.emplace_back(facet);
|
||||
} else if (max_z < z || (max_z == z && min_z < z)) {
|
||||
} else if (max_z < z || (is_equal(max_z, z) && min_z < z)) {
|
||||
// facet is below the cut plane and does not belong to it
|
||||
if (lower != nullptr)
|
||||
lower->indices.emplace_back(facet);
|
||||
@@ -2215,21 +2406,56 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u
|
||||
assert(line.edge_b_id != -1);
|
||||
|
||||
// look for the vertex on whose side of the slicing plane there are no other vertices
|
||||
int isolated_vertex =
|
||||
(vertices[0].z() > z) == (vertices[1].z() > z) ? 2 :
|
||||
(vertices[1].z() > z) == (vertices[2].z() > z) ? 0 : 1;
|
||||
|
||||
// get vertices starting from the isolated one
|
||||
int iv = isolated_vertex;
|
||||
stl_vertex v0v1, v2v0;
|
||||
assert(facets_edge_ids[facet_idx](iv) == line.edge_a_id || facets_edge_ids[facet_idx](iv) == line.edge_b_id);
|
||||
if (facets_edge_ids[facet_idx](iv) == line.edge_a_id) {
|
||||
// Unscale to doubles first, then to floats to reach the same accuracy as triangulate_expolygons_2d().
|
||||
v0v1 = to_3d(unscaled<double>(line.a).cast<float>().eval(), z);
|
||||
v2v0 = to_3d(unscaled<double>(line.b).cast<float>().eval(), z);
|
||||
int isolated_vertex, isolated_vertex_option = -1;
|
||||
std::vector<int> list{0, 1, 2};
|
||||
auto get_third = [&list](int isolated_vertex, int temp) {// not use vertex data
|
||||
for (size_t i = 0; i < list.size(); i++) {
|
||||
if (list[i] != isolated_vertex && list[i] != temp) {
|
||||
return list[i];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
if (is_equal(vertices[0].z(), z)) {
|
||||
isolated_vertex = vertices[1].z() > z ? 1 : 2;
|
||||
isolated_vertex_option = get_third(isolated_vertex, 0);
|
||||
} else if (is_equal(vertices[1].z(), z)) {
|
||||
isolated_vertex = vertices[2].z() > z ? 2 : 0;
|
||||
isolated_vertex_option = get_third(isolated_vertex, 1);
|
||||
} else if (is_equal(vertices[2].z(), z)) {
|
||||
isolated_vertex = vertices[0].z() > z ? 0 : 1;
|
||||
isolated_vertex_option = get_third(isolated_vertex, 2);
|
||||
} else {
|
||||
v0v1 = to_3d(unscaled<double>(line.b).cast<float>().eval(), z);
|
||||
v2v0 = to_3d(unscaled<double>(line.a).cast<float>().eval(), z);
|
||||
isolated_vertex = (vertices[0].z() > z) == (vertices[1].z() > z) ? 2 : (vertices[1].z() > z) == (vertices[2].z() > z) ? 0 : 1;
|
||||
}
|
||||
// get vertices starting from the isolated one
|
||||
stl_vertex v0v1, v2v0;
|
||||
auto calc_isolated_vertex = [&v0v1, &v2v0, &line, &facet_idx, &facets_edge_ids, &z](int iv, bool &is_find) {
|
||||
assert(facets_edge_ids[facet_idx](iv) == line.edge_a_id || facets_edge_ids[facet_idx](iv) == line.edge_b_id);
|
||||
is_find = true;
|
||||
if (facets_edge_ids[facet_idx](iv) == line.edge_a_id) {
|
||||
// Unscale to doubles first, then to floats to reach the same accuracy as triangulate_expolygons_2d().
|
||||
v0v1 = to_3d(unscaled<double>(line.a).cast<float>().eval(), z);
|
||||
v2v0 = to_3d(unscaled<double>(line.b).cast<float>().eval(), z);
|
||||
} else if (facets_edge_ids[facet_idx](iv) == line.edge_b_id) {
|
||||
v0v1 = to_3d(unscaled<double>(line.b).cast<float>().eval(), z);
|
||||
v2v0 = to_3d(unscaled<double>(line.a).cast<float>().eval(), z);
|
||||
} else {
|
||||
is_find = false;
|
||||
}
|
||||
};
|
||||
bool find_isolated_vertex;
|
||||
int iv;
|
||||
calc_isolated_vertex(isolated_vertex, find_isolated_vertex);
|
||||
if (!find_isolated_vertex && isolated_vertex_option != -1) {
|
||||
calc_isolated_vertex(isolated_vertex_option, find_isolated_vertex);
|
||||
if (!find_isolated_vertex) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "cut_mesh:error:could not find isolated_vertex";
|
||||
continue;
|
||||
}
|
||||
iv = isolated_vertex_option;
|
||||
} else {
|
||||
iv = isolated_vertex;
|
||||
}
|
||||
const stl_vertex &v0 = vertices[iv];
|
||||
const int iv0 = facet[iv];
|
||||
@@ -2243,48 +2469,71 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u
|
||||
const int iv2 = facet[iv];
|
||||
|
||||
// intersect v0-v1 and v2-v0 with cutting plane and make new vertices
|
||||
auto new_vertex = [upper, lower, &upper_slice_vertices, &lower_slice_vertices](const Vec3f &a, const int ia, const Vec3f &b, const int ib, const Vec3f &c) {
|
||||
auto new_vertex = [upper, lower, &upper_slice_vertices, &lower_slice_vertices](const Vec3f &a, const int ia, const Vec3f &b, const int ib, const Vec3f &c,
|
||||
const int ic, const Vec3f &new_pt, bool &is_new_vertex) {
|
||||
int iupper, ilower;
|
||||
if (c == a)
|
||||
is_new_vertex = false;
|
||||
if (is_equal(new_pt, a))
|
||||
iupper = ilower = ia;
|
||||
else if (c == b)
|
||||
else if (is_equal(new_pt, b))
|
||||
iupper = ilower = ib;
|
||||
else if (is_equal(new_pt, c))
|
||||
iupper = ilower = ic;
|
||||
else {
|
||||
// Insert a new vertex into upper / lower.
|
||||
is_new_vertex = true;
|
||||
if (upper) {
|
||||
iupper = int(upper->vertices.size());
|
||||
upper->vertices.emplace_back(c);
|
||||
upper->vertices.emplace_back(new_pt);
|
||||
upper_slice_vertices.emplace_back(iupper);
|
||||
}
|
||||
if (lower) {
|
||||
ilower = int(lower->vertices.size());
|
||||
lower->vertices.emplace_back(c);
|
||||
lower->vertices.emplace_back(new_pt);
|
||||
lower_slice_vertices.emplace_back(ilower);
|
||||
}
|
||||
}
|
||||
return std::make_pair(iupper, ilower);
|
||||
};
|
||||
auto [iv0v1_upper, iv0v1_lower] = new_vertex(v1, iv1, v0, iv0, v0v1);
|
||||
auto [iv2v0_upper, iv2v0_lower] = new_vertex(v2, iv2, v0, iv0, v2v0);
|
||||
auto new_face = [](indexed_triangle_set *its, int i, int j, int k) {
|
||||
if (its != nullptr && i != j && i != k && j != k)
|
||||
its->indices.emplace_back(i, j, k);
|
||||
bool is_new_vertex_v0v1;
|
||||
bool is_new_vertex_v2v0;
|
||||
auto [iv0v1_upper, iv0v1_lower] = new_vertex(v1, iv1, v0, iv0, v2, iv2, v0v1, is_new_vertex_v0v1);
|
||||
auto [iv2v0_upper, iv2v0_lower] = new_vertex(v2, iv2, v0, iv0, v1, iv1, v2v0, is_new_vertex_v2v0);
|
||||
auto new_face = [](indexed_triangle_set *its, int i, int j, int k) {
|
||||
if (its != nullptr && i != j && i != k && j != k) its->indices.emplace_back(i, j, k);
|
||||
};
|
||||
|
||||
if (v0.z() > z) {
|
||||
new_face(upper, iv0, iv0v1_upper, iv2v0_upper);
|
||||
new_face(lower, iv1, iv2, iv0v1_lower);
|
||||
new_face(lower, iv2, iv2v0_lower, iv0v1_lower);
|
||||
} else {
|
||||
new_face(upper, iv1, iv2, iv0v1_upper);
|
||||
new_face(upper, iv2, iv2v0_upper, iv0v1_upper);
|
||||
new_face(lower, iv0, iv0v1_lower, iv2v0_lower);
|
||||
if (is_new_vertex_v0v1 && is_new_vertex_v2v0) {
|
||||
if (v0.z() > z) {
|
||||
new_face(upper, iv0, iv0v1_upper, iv2v0_upper);
|
||||
new_face(lower, iv1, iv2, iv0v1_lower);
|
||||
new_face(lower, iv2, iv2v0_lower, iv0v1_lower);
|
||||
} else {
|
||||
new_face(upper, iv1, iv2, iv0v1_upper);
|
||||
new_face(upper, iv2, iv2v0_upper, iv0v1_upper);
|
||||
new_face(lower, iv0, iv0v1_lower, iv2v0_lower);
|
||||
}
|
||||
} else if (is_new_vertex_v0v1) {
|
||||
if (v0.z() > z) {
|
||||
new_face(upper, iv0, iv0v1_upper, iv2);
|
||||
new_face(lower, iv1, iv2, iv0v1_lower);
|
||||
} else {
|
||||
new_face(lower, iv0, iv0v1_lower, iv2);
|
||||
new_face(upper, iv1, iv2, iv0v1_upper);
|
||||
}
|
||||
} else if (is_new_vertex_v2v0) {
|
||||
if (v0.z() > z) {
|
||||
new_face(upper, iv0, iv1, iv2v0_upper);
|
||||
new_face(lower, iv1, iv2, iv2v0_lower);
|
||||
} else {
|
||||
new_face(lower, iv0, iv1, iv2v0_lower);
|
||||
new_face(upper, iv1, iv2, iv2v0_upper);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (upper != nullptr) {
|
||||
triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_DOWN);
|
||||
triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_DOWN, section_vertices_map);
|
||||
#ifndef NDEBUG
|
||||
if (triangulate_caps) {
|
||||
size_t num_open_edges_new = its_num_open_edges(*upper);
|
||||
@@ -2294,7 +2543,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u
|
||||
}
|
||||
|
||||
if (lower != nullptr) {
|
||||
triangulate_slice(*lower, lower_lines, lower_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_UP);
|
||||
triangulate_slice(*lower, lower_lines, lower_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_UP, section_vertices_map);
|
||||
#ifndef NDEBUG
|
||||
if (triangulate_caps) {
|
||||
size_t num_open_edges_new = its_num_open_edges(*lower);
|
||||
@@ -2302,6 +2551,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u
|
||||
}
|
||||
#endif // NDEBUG
|
||||
}
|
||||
std::map<int, Vec3f*>().swap(section_vertices_map);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -1703,7 +1703,12 @@ void TriangleSelector::deserialize(const std::pair<std::vector<std::pair<int, in
|
||||
{
|
||||
if (needs_reset)
|
||||
reset(); // dump any current state
|
||||
|
||||
for (auto [triangle_id, ibit] : data.first) {
|
||||
if (triangle_id >= int(m_triangles.size())) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "array bound:error:triangle_id >= int(m_triangles.size())";
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Reserve number of triangles as if each triangle was saved with 4 bits.
|
||||
// With MMU painting this estimate may be somehow low, but better than nothing.
|
||||
m_triangles.reserve(std::max(m_mesh.its.indices.size(), data.second.size() / 4));
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#define CLI_PRINTABLE_SIZE_REDUCED -20
|
||||
#define CLI_OBJECT_ARRANGE_FAILED -21
|
||||
#define CLI_OBJECT_ORIENT_FAILED -22
|
||||
#define CLI_MODIFIED_PARAMS_TO_PRINTER -23
|
||||
|
||||
|
||||
#define CLI_NO_SUITABLE_OBJECTS -50
|
||||
@@ -124,8 +125,11 @@ inline std::string convert_to_full_version(std::string short_version)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename DataType>
|
||||
inline DataType round_divide(DataType dividend, DataType divisor) //!< Return dividend divided by divisor rounded to the nearest integer
|
||||
{
|
||||
return (dividend + divisor / 2) / divisor;
|
||||
}
|
||||
|
||||
// Set a path with GUI localization files.
|
||||
void set_local_dir(const std::string &path);
|
||||
|
||||
@@ -67,7 +67,7 @@ static constexpr double RESOLUTION = 0.0125;
|
||||
static constexpr double SPARSE_INFILL_RESOLUTION = 0.04;
|
||||
#define SCALED_SPARSE_INFILL_RESOLUTION (SPARSE_INFILL_RESOLUTION / SCALING_FACTOR)
|
||||
|
||||
static constexpr double SUPPORT_RESOLUTION = 0.05;
|
||||
static constexpr double SUPPORT_RESOLUTION = 0.1;
|
||||
#define SCALED_SUPPORT_RESOLUTION (SUPPORT_RESOLUTION / SCALING_FACTOR)
|
||||
// Maximum perimeter length for the loop to apply the small perimeter speed.
|
||||
#define SMALL_PERIMETER_LENGTH(LENGTH) (((LENGTH) / SCALING_FACTOR) * 2 * PI)
|
||||
@@ -76,6 +76,7 @@ static constexpr double INSET_OVERLAP_TOLERANCE = 0.4;
|
||||
//FIXME This is quite a lot.
|
||||
static constexpr double EXTERNAL_INFILL_MARGIN = 3;
|
||||
static constexpr double BRIDGE_INFILL_MARGIN = 1;
|
||||
static constexpr double WIPE_TOWER_MARGIN = 15.;
|
||||
//FIXME Better to use an inline function with an explicit return type.
|
||||
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
|
||||
#define scale_(val) ((val) / SCALING_FACTOR)
|
||||
|
||||
@@ -208,6 +208,11 @@ const std::string& var_dir()
|
||||
|
||||
std::string var(const std::string &file_name)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
if (boost::filesystem::exists(file_name, ec)) {
|
||||
return file_name;
|
||||
}
|
||||
|
||||
auto file = (boost::filesystem::path(g_var_dir) / file_name).make_preferred();
|
||||
return file.string();
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/AuxiliaryDialog.hpp
|
||||
GUI/Auxiliary.cpp
|
||||
GUI/Auxiliary.hpp
|
||||
GUI/DailyTips.cpp
|
||||
GUI/DailyTips.hpp
|
||||
GUI/Project.cpp
|
||||
GUI/Project.hpp
|
||||
GUI/BackgroundSlicingProcess.cpp
|
||||
@@ -114,6 +116,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/OpenGLManager.cpp
|
||||
GUI/Selection.hpp
|
||||
GUI/Selection.cpp
|
||||
GUI/SlicingProgressNotification.cpp
|
||||
GUI/SlicingProgressNotification.hpp
|
||||
GUI/Gizmos/GLGizmosManager.cpp
|
||||
GUI/Gizmos/GLGizmosManager.hpp
|
||||
GUI/Gizmos/GLGizmosCommon.cpp
|
||||
@@ -288,7 +292,7 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/3DBed.hpp
|
||||
GUI/Camera.cpp
|
||||
GUI/Camera.hpp
|
||||
GUI/CameraUtils.cpp
|
||||
GUI/CameraUtils.cpp
|
||||
GUI/CameraUtils.hpp
|
||||
GUI/wxExtensions.cpp
|
||||
GUI/wxExtensions.hpp
|
||||
@@ -391,7 +395,7 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/DragCanvas.hpp
|
||||
GUI/PublishDialog.cpp
|
||||
GUI/PublishDialog.hpp
|
||||
GUI/RecenterDialog.cpp
|
||||
GUI/RecenterDialog.cpp
|
||||
GUI/RecenterDialog.hpp
|
||||
GUI/PrivacyUpdateDialog.cpp
|
||||
GUI/PrivacyUpdateDialog.hpp
|
||||
@@ -419,13 +423,13 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/CalibrationWizard.cpp
|
||||
GUI/CalibrationWizardPage.cpp
|
||||
GUI/CalibrationWizardPage.hpp
|
||||
GUI/CalibrationWizardStartPage.cpp
|
||||
GUI/CalibrationWizardStartPage.cpp
|
||||
GUI/CalibrationWizardStartPage.hpp
|
||||
GUI/CalibrationWizardPresetPage.cpp
|
||||
GUI/CalibrationWizardPresetPage.cpp
|
||||
GUI/CalibrationWizardPresetPage.hpp
|
||||
GUI/CalibrationWizardCaliPage.cpp
|
||||
GUI/CalibrationWizardCaliPage.cpp
|
||||
GUI/CalibrationWizardCaliPage.hpp
|
||||
GUI/CalibrationWizardSavePage.cpp
|
||||
GUI/CalibrationWizardSavePage.cpp
|
||||
GUI/CalibrationWizardSavePage.hpp
|
||||
GUI/Calibration.hpp
|
||||
GUI/Calibration.cpp
|
||||
@@ -435,6 +439,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/BonjourDialog.cpp
|
||||
GUI/BedShapeDialog.hpp
|
||||
GUI/BedShapeDialog.cpp
|
||||
GUI/CreatePresetsDialog.hpp
|
||||
GUI/CreatePresetsDialog.cpp
|
||||
Utils/json_diff.hpp
|
||||
Utils/json_diff.cpp
|
||||
GUI/KBShortcutsDialog.hpp
|
||||
@@ -445,6 +451,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/FixModelByWin10.hpp
|
||||
Utils/Bonjour.cpp
|
||||
Utils/Bonjour.hpp
|
||||
Utils/FileHelp.cpp
|
||||
Utils/FileHelp.hpp
|
||||
Utils/PresetUpdater.cpp
|
||||
Utils/PresetUpdater.hpp
|
||||
Utils/Process.cpp
|
||||
|
||||
@@ -645,8 +645,12 @@ void Bed3D::update_bed_triangles()
|
||||
(*model_offset_ptr)(1) = m_build_volume.bounding_volume2d().min.y() - bed_ext.min.y();
|
||||
(*model_offset_ptr)(2) = -0.41 + GROUND_Z;
|
||||
|
||||
std::vector<Vec2d> new_bed_shape;
|
||||
for (auto point: m_bed_shape) {
|
||||
std::vector<Vec2d> origin_bed_shape;
|
||||
for (size_t i = 0; i < m_bed_shape.size(); i++) {
|
||||
origin_bed_shape.push_back(m_bed_shape[i] - m_bed_shape[0]);
|
||||
}
|
||||
std::vector<Vec2d> new_bed_shape; // offset to correct origin
|
||||
for (auto point : origin_bed_shape) {
|
||||
Vec2d new_point(point.x() + model_offset_ptr->x(), point.y() + model_offset_ptr->y());
|
||||
new_bed_shape.push_back(new_point);
|
||||
}
|
||||
|
||||
@@ -612,30 +612,38 @@ bool GLWipeTowerVolume::IsTransparent() {
|
||||
}
|
||||
|
||||
std::vector<int> GLVolumeCollection::load_object(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int>& instance_idxs)
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int> &instance_idxs,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized)
|
||||
{
|
||||
std::vector<int> volumes_idx;
|
||||
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
|
||||
for (int instance_idx : instance_idxs)
|
||||
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx));
|
||||
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized));
|
||||
return volumes_idx;
|
||||
}
|
||||
|
||||
|
||||
int GLVolumeCollection::load_object_volume(
|
||||
const ModelObject* model_object,
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized,
|
||||
bool in_assemble_view,
|
||||
bool use_loaded_id)
|
||||
{
|
||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||
const int extruder_id = model_volume->extruder_id();
|
||||
const ModelInstance *instance = model_object->instances[instance_idx];
|
||||
auto color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4];
|
||||
color.a(model_volume->is_model_part() ? 0.7f : 0.4f);
|
||||
|
||||
std::shared_ptr<const TriangleMesh> mesh = model_volume->mesh_ptr();
|
||||
this->volumes.emplace_back(new GLVolume());
|
||||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *this->volumes.back();
|
||||
v.set_color(color_from_model_volume(*model_volume));
|
||||
v.name = model_volume->name;
|
||||
@@ -647,7 +655,9 @@ int GLVolumeCollection::load_object_volume(
|
||||
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
|
||||
if (model_volume->is_model_part()) {
|
||||
|
||||
if (model_volume->is_model_part())
|
||||
{
|
||||
// GLVolume will reference a convex hull from model_volume!
|
||||
v.set_convex_hull(model_volume->get_convex_hull_shared_ptr());
|
||||
if (extruder_id != -1)
|
||||
|
||||
@@ -440,18 +440,21 @@ public:
|
||||
~GLVolumeCollection() { clear(); }
|
||||
|
||||
std::vector<int> load_object(
|
||||
const ModelObject* model_object,
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int>& instance_idxs);
|
||||
const std::vector<int> &instance_idxs,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized);
|
||||
|
||||
int load_object_volume(
|
||||
const ModelObject* model_object,
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized,
|
||||
bool in_assemble_view = false,
|
||||
bool use_loaded_id = false);
|
||||
|
||||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||
void load_object_auxiliary(
|
||||
const SLAPrintObject *print_object,
|
||||
|
||||
@@ -323,12 +323,6 @@ void AMSMaterialsSetting::create_panel_kn(wxWindow* parent)
|
||||
m_n_param->Hide();
|
||||
m_input_n_val->Hide();
|
||||
|
||||
// hide n (P1P old logic)
|
||||
//if (!this->obj || !this->obj->is_high_printer_type()) {
|
||||
// m_n_param->Hide();
|
||||
// m_input_n_val->Hide();
|
||||
//}
|
||||
|
||||
sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
|
||||
sizer->Add(m_ratio_text, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(20));
|
||||
sizer->Add(0, 0, 0, wxTOP, FromDIP(16));
|
||||
@@ -447,7 +441,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) {
|
||||
}
|
||||
|
||||
// set k / n value
|
||||
if (!obj->is_high_printer_type()) {
|
||||
if (obj->get_printer_series() != PrinterSeries::SERIES_X1) {
|
||||
// set extrusion cali ratio
|
||||
int cali_tray_id = ams_id * 4 + tray_id;
|
||||
|
||||
@@ -490,7 +484,9 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
if (preset_bundle) {
|
||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
|
||||
|
||||
if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) {
|
||||
auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()];
|
||||
std::string filament_id = filament_item.filament_id;
|
||||
if (it->filament_id.compare(filament_id) == 0) {
|
||||
|
||||
|
||||
//check is it in the filament blacklist
|
||||
@@ -501,9 +497,12 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
std::string filamnt_type;
|
||||
it->get_filament_type(filamnt_type);
|
||||
|
||||
if (it->vendor) {
|
||||
DeviceManager::check_filaments_in_blacklist(it->vendor->name, filamnt_type, in_blacklist, action, info);
|
||||
auto vendor = dynamic_cast<ConfigOptionStrings*> (it->config.option("filament_vendor"));
|
||||
if (vendor && (vendor->values.size() > 0)) {
|
||||
std::string vendor_name = vendor->values[0];
|
||||
DeviceManager::check_filaments_in_blacklist(vendor_name, filamnt_type, in_blacklist, action, info);
|
||||
}
|
||||
|
||||
|
||||
if (in_blacklist) {
|
||||
if (action == "prohibition") {
|
||||
@@ -545,12 +544,6 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ams_filament_id.empty() || nozzle_temp_min.empty() || nozzle_temp_max.empty() || m_filament_type.empty()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Invalid Setting id";
|
||||
MessageDialog msg_dlg(nullptr, _L("You need to select the material type and color first."), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
// set filament
|
||||
if (m_is_third) {
|
||||
@@ -566,9 +559,9 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
wxString k_text = m_input_k_val->GetTextCtrl()->GetValue();
|
||||
wxString n_text = m_input_n_val->GetTextCtrl()->GetValue();
|
||||
|
||||
if (!obj->is_high_printer_type() && !ExtrusionCalibration::check_k_validation(k_text)) {
|
||||
wxString k_tips = _L("Please input a valid value (K in 0~0.5)");
|
||||
wxString kn_tips = _L("Please input a valid value (K in 0~0.5, N in 0.6~2.0)");
|
||||
if ((obj->get_printer_series() != PrinterSeries::SERIES_X1) && !ExtrusionCalibration::check_k_validation(k_text)) {
|
||||
wxString k_tips = _L("Please input a valid value (K in 0~0.3)");
|
||||
wxString kn_tips = _L("Please input a valid value (K in 0~0.3, N in 0.6~2.0)");
|
||||
MessageDialog msg_dlg(nullptr, k_tips, wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
@@ -591,7 +584,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
;
|
||||
}
|
||||
|
||||
if (obj->is_high_printer_type()) {
|
||||
if (obj->get_printer_series() == PrinterSeries::SERIES_X1) {
|
||||
PACalibIndexInfo select_index_info;
|
||||
select_index_info.tray_id = tray_id;
|
||||
select_index_info.nozzle_diameter = obj->nozzle_diameter;
|
||||
@@ -630,7 +623,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
;
|
||||
}
|
||||
|
||||
if (obj->is_high_printer_type()) {
|
||||
if (obj->get_printer_series() == PrinterSeries::SERIES_X1) {
|
||||
PACalibIndexInfo select_index_info;
|
||||
select_index_info.tray_id = cali_tray_id;
|
||||
select_index_info.nozzle_diameter = obj->nozzle_diameter;
|
||||
@@ -729,7 +722,7 @@ void AMSMaterialsSetting::update_widgets()
|
||||
else
|
||||
m_panel_normal->Hide();
|
||||
m_panel_kn->Show();
|
||||
} else if (obj && (obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_TYAY) || obj->is_high_printer_type())) {
|
||||
} else if (obj && (obj->ams_support_virtual_tray || (obj->get_printer_series() == PrinterSeries::SERIES_X1))) {
|
||||
m_panel_normal->Show();
|
||||
m_panel_kn->Show();
|
||||
} else {
|
||||
@@ -759,6 +752,7 @@ bool AMSMaterialsSetting::Show(bool show)
|
||||
|
||||
void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_min, wxString temp_max, wxString k, wxString n)
|
||||
{
|
||||
if (!obj) return;
|
||||
update_widgets();
|
||||
// set default value
|
||||
if (k.IsEmpty())
|
||||
@@ -771,14 +765,22 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
|
||||
int selection_idx = -1, idx = 0;
|
||||
wxArrayString filament_items;
|
||||
|
||||
|
||||
std::set<std::string> filament_id_set;
|
||||
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
if (preset_bundle) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
|
||||
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
|
||||
// filter by system preset
|
||||
if (!filament_it->is_system) continue;
|
||||
//filter by system preset
|
||||
Preset& preset = *filament_it;
|
||||
/*The situation where the user preset is not displayed is as follows:
|
||||
1. Not a root preset
|
||||
2. Not system preset and the printer firmware does not support user preset */
|
||||
if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) {
|
||||
// filter by system preset
|
||||
@@ -786,7 +788,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
// get printer_model
|
||||
ConfigOption* printer_model_opt = printer_it->config.option("printer_model");
|
||||
ConfigOptionString* printer_model_str = dynamic_cast<ConfigOptionString*>(printer_model_opt);
|
||||
if (!printer_model_str || !obj)
|
||||
if (!printer_model_str )
|
||||
continue;
|
||||
|
||||
// use printer_model as printer type
|
||||
@@ -802,7 +804,30 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
else {
|
||||
filament_id_set.insert(filament_it->filament_id);
|
||||
// name matched
|
||||
filament_items.push_back(filament_it->alias);
|
||||
if (filament_it->is_system) {
|
||||
filament_items.push_back(filament_it->alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[filament_it->alias] = filament_infos;
|
||||
}
|
||||
else {
|
||||
char target = '@';
|
||||
size_t pos = filament_it->name.find(target);
|
||||
if (pos != std::string::npos) {
|
||||
std::string user_preset_alias = filament_it->name.substr(0, pos-1);
|
||||
wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8);
|
||||
user_preset_alias = wx_user_preset_alias.ToStdString();
|
||||
|
||||
filament_items.push_back(user_preset_alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[user_preset_alias] = filament_infos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (filament_it->filament_id == ams_filament_id) {
|
||||
selection_idx = idx;
|
||||
|
||||
@@ -853,7 +878,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
m_readonly_filament->Hide();
|
||||
}
|
||||
|
||||
if (obj->is_high_printer_type()) {
|
||||
if (obj->get_printer_series() == PrinterSeries::SERIES_X1) {
|
||||
m_title_pa_profile->Show();
|
||||
m_comboBox_cali_result->Show();
|
||||
m_input_k_val->Disable();
|
||||
@@ -913,40 +938,44 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
if (preset_bundle) {
|
||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
|
||||
if (!m_comboBox_filament->GetValue().IsEmpty() && it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) {
|
||||
if (!m_comboBox_filament->GetValue().IsEmpty()) {
|
||||
auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()];
|
||||
std::string filament_id = filament_item.filament_id;
|
||||
if (it->filament_id.compare(filament_id) == 0) {
|
||||
|
||||
// ) if nozzle_temperature_range is found
|
||||
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
// ) if nozzle_temperature_range is found
|
||||
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_type = it->config.option("filament_type");
|
||||
bool found_filament_type = false;
|
||||
if (opt_type) {
|
||||
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
|
||||
if (opt_type_strs) {
|
||||
found_filament_type = true;
|
||||
//m_filament_type = opt_type_strs->get_at(0);
|
||||
std::string display_filament_type;
|
||||
m_filament_type = it->config.get_filament_type(display_filament_type);
|
||||
ConfigOption* opt_type = it->config.option("filament_type");
|
||||
bool found_filament_type = false;
|
||||
if (opt_type) {
|
||||
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
|
||||
if (opt_type_strs) {
|
||||
found_filament_type = true;
|
||||
//m_filament_type = opt_type_strs->get_at(0);
|
||||
std::string display_filament_type;
|
||||
m_filament_type = it->config.get_filament_type(display_filament_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found_filament_type)
|
||||
m_filament_type = "";
|
||||
if (!found_filament_type)
|
||||
m_filament_type = "";
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -985,6 +1014,13 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
|
||||
|
||||
if (preset_bundle) {
|
||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
|
||||
auto itor = map_filament_items.find(m_comboBox_filament->GetValue().ToStdString());
|
||||
if ( itor != map_filament_items.end()) {
|
||||
ams_filament_id = itor->second.filament_id;
|
||||
ams_setting_id = itor->second.setting_id;
|
||||
break;
|
||||
}
|
||||
|
||||
if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) {
|
||||
ams_filament_id = it->filament_id;
|
||||
ams_setting_id = it->setting_id;
|
||||
@@ -997,7 +1033,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
|
||||
m_pa_profile_items.clear();
|
||||
m_comboBox_cali_result->SetValue(wxEmptyString);
|
||||
|
||||
if (this->obj->is_high_printer_type()) {
|
||||
if (obj->get_printer_series() == PrinterSeries::SERIES_X1) {
|
||||
m_input_k_val->GetTextCtrl()->SetValue(wxEmptyString);
|
||||
std::vector<PACalibResult> cali_history = this->obj->pa_calib_tab;
|
||||
for (auto cali_item : cali_history) {
|
||||
|
||||
@@ -180,6 +180,12 @@ protected:
|
||||
#endif
|
||||
ComboBox * m_comboBox_cali_result;
|
||||
TextInput* m_readonly_filament;
|
||||
|
||||
struct FilamentInfos {
|
||||
std::string filament_id;
|
||||
std::string setting_id;
|
||||
};
|
||||
std::map<std::string, FilamentInfos> map_filament_items;
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_SELECTED_COLOR, wxCommandEvent);
|
||||
|
||||
@@ -192,8 +192,8 @@ void AMSSetting::create()
|
||||
wxPanel* m_panel_img = new wxPanel(m_panel_body, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||
m_panel_img->SetBackgroundColour(AMS_SETTING_GREY200);
|
||||
wxBoxSizer *m_sizer_img = new wxBoxSizer(wxVERTICAL);
|
||||
ams_img = new wxStaticBitmap(m_panel_img, wxID_ANY, create_scaled_bitmap("ams_icon", nullptr, 126), wxDefaultPosition, wxDefaultSize);
|
||||
m_sizer_img->Add(ams_img, 0, wxALIGN_CENTER | wxTOP, 26);
|
||||
m_am_img = new wxStaticBitmap(m_panel_img, wxID_ANY, create_scaled_bitmap("ams_icon", nullptr, 126), wxDefaultPosition, wxDefaultSize);
|
||||
m_sizer_img->Add(m_am_img, 0, wxALIGN_CENTER | wxTOP, 26);
|
||||
m_sizer_img->Add(0, 0, 0, wxTOP, 18);
|
||||
m_panel_img->SetSizer(m_sizer_img);
|
||||
m_panel_img->Layout();
|
||||
@@ -262,17 +262,9 @@ void AMSSetting::update_insert_material_read_mode(bool selected)
|
||||
Fit();
|
||||
}
|
||||
|
||||
void AMSSetting::update_image(std::string ams_type)
|
||||
void AMSSetting::update_ams_img(std::string ams_icon_str)
|
||||
{
|
||||
if (ams_type == m_current_ams_type) return;
|
||||
if (ams_type == "generic") {
|
||||
ams_img->SetBitmap(create_scaled_bitmap("monitor_upgrade_f1", nullptr, 126));
|
||||
}
|
||||
else {
|
||||
ams_img->SetBitmap(create_scaled_bitmap("ams_icon", nullptr, 126));
|
||||
}
|
||||
m_current_ams_type = ams_type;
|
||||
Layout();
|
||||
m_am_img->SetBitmap(create_scaled_bitmap(ams_icon_str, nullptr, 126));
|
||||
}
|
||||
|
||||
void AMSSetting::update_starting_read_mode(bool selected)
|
||||
@@ -292,12 +284,24 @@ void AMSSetting::update_starting_read_mode(bool selected)
|
||||
|
||||
void AMSSetting::update_remain_mode(bool selected)
|
||||
{
|
||||
if (obj->is_support_update_remain) {
|
||||
m_checkbox_remain->Show();
|
||||
m_title_remain->Show();
|
||||
m_tip_remain_line1->Show();
|
||||
Layout();
|
||||
}
|
||||
else {
|
||||
m_checkbox_remain->Hide();
|
||||
m_title_remain->Hide();
|
||||
m_tip_remain_line1->Hide();
|
||||
Layout();
|
||||
}
|
||||
m_checkbox_remain->SetValue(selected);
|
||||
}
|
||||
|
||||
void AMSSetting::update_switch_filament(bool selected)
|
||||
{
|
||||
if (obj->is_function_supported(PrinterFunction::FUNC_AUTO_SWITCH_FILAMENT)) {
|
||||
if (obj->is_support_filament_backup) {
|
||||
m_checkbox_switch_filament->Show();
|
||||
m_title_switch_filament->Show();
|
||||
m_tip_switch_filament_line1->Show();
|
||||
|
||||
@@ -27,8 +27,8 @@ public:
|
||||
~AMSSetting();
|
||||
void create();
|
||||
|
||||
void update_insert_material_read_mode(bool selected);
|
||||
void update_image(std::string ams_type);
|
||||
void update_insert_material_read_mode(bool selected);
|
||||
void update_ams_img(std::string ams_icon_str);
|
||||
void update_starting_read_mode(bool selected);
|
||||
void update_remain_mode(bool selected);
|
||||
void update_switch_filament(bool selected);
|
||||
@@ -41,13 +41,13 @@ public:
|
||||
wxStaticText *append_text(wxString text);
|
||||
MachineObject *obj{nullptr};
|
||||
bool ams_support_remain{false};
|
||||
wxStaticBitmap* m_am_img;
|
||||
int ams_id { 0 };
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
|
||||
protected:
|
||||
std::string m_current_ams_type;
|
||||
wxPanel * m_panel_body;
|
||||
CheckBox * m_checkbox_Insert_material_auto_read;
|
||||
wxStaticText *m_title_Insert_material_auto_read;
|
||||
@@ -70,7 +70,7 @@ protected:
|
||||
|
||||
wxStaticText *m_tip_ams_img;
|
||||
Button * m_button_auto_demarcate;
|
||||
wxStaticBitmap* ams_img;
|
||||
|
||||
wxBoxSizer *m_sizer_Insert_material_tip_inline;
|
||||
wxBoxSizer *m_sizer_starting_tip_inline;
|
||||
wxBoxSizer *m_sizer_remain_inline;
|
||||
|
||||
@@ -186,7 +186,7 @@ void MaterialItem::doRender(wxDC &dc)
|
||||
auto mcolor = m_material_coloul;
|
||||
auto acolor = m_ams_coloul;
|
||||
|
||||
if (mcolor.Alpha() == 0) {
|
||||
if (mcolor.Alpha() == 0 || acolor.Alpha() == 0) {
|
||||
dc.DrawBitmap(m_transparent_mitem.get_bitmap(), FromDIP(1), FromDIP(1));
|
||||
}
|
||||
|
||||
@@ -1332,7 +1332,7 @@ void AmsReplaceMaterialDialog::update_machine_obj(MachineObject* obj)
|
||||
m_scrollview_groups->SetMinSize(wxSize(FromDIP(400), height));
|
||||
m_scrollview_groups->SetMaxSize(wxSize(FromDIP(400), height));
|
||||
} else {
|
||||
if (!obj->is_function_supported(PrinterFunction::FUNC_FILAMENT_BACKUP)) {
|
||||
if (!obj->is_support_filament_backup) {
|
||||
label_txt->SetLabel(_L("The printer does not currently support auto refill."));
|
||||
}
|
||||
else if (!obj->ams_auto_switch_filament_flag) {
|
||||
@@ -1345,6 +1345,7 @@ void AmsReplaceMaterialDialog::update_machine_obj(MachineObject* obj)
|
||||
label_txt->SetMinSize(wxSize(FromDIP(380), -1));
|
||||
label_txt->SetMaxSize(wxSize(FromDIP(380), -1));
|
||||
label_txt->Wrap(FromDIP(380));
|
||||
|
||||
}
|
||||
|
||||
m_scrollview_groups->Layout();
|
||||
@@ -1548,10 +1549,13 @@ void AmsRMGroup::doRender(wxDC& dc)
|
||||
dc.SetFont(::Label::Body_12);
|
||||
auto text_size = dc.GetTextExtent(tray_name);
|
||||
dc.SetTextForeground(tray_color.GetLuminance() < 0.6 ? *wxWHITE : wxColour(0x262E30));
|
||||
if (tray_color.Alpha() == 0) {dc.SetTextForeground(wxColour(0x262E30));}
|
||||
|
||||
dc.DrawText(tray_name, x_center - text_size.x / 2, size.y - y_center - text_size.y / 2);
|
||||
|
||||
//draw split line
|
||||
dc.SetPen(wxPen(*wxWHITE, 2));
|
||||
if (tray_color.Alpha() == 0) {dc.SetPen(wxPen(wxColour(0xCECECE), 2));}
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
auto pos_sp_start = CalculateEndpoint(wxPoint(x, y), (360 - startAngle), size.x / 2 - FromDIP(3));
|
||||
dc.DrawLine(wxPoint(x, y), pos_sp_start);
|
||||
|
||||
@@ -575,7 +575,7 @@ void BBLTopbar::OnFileToolItem(wxAuiToolBarEvent& evt)
|
||||
tb->SetToolSticky(evt.GetId(), true);
|
||||
|
||||
if (!m_skip_popup_file_menu) {
|
||||
this->PopupMenu(m_file_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2));
|
||||
GetParent()->PopupMenu(m_file_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2));
|
||||
}
|
||||
else {
|
||||
m_skip_popup_file_menu = false;
|
||||
@@ -592,7 +592,7 @@ void BBLTopbar::OnDropdownToolItem(wxAuiToolBarEvent& evt)
|
||||
tb->SetToolSticky(evt.GetId(), true);
|
||||
|
||||
if (!m_skip_popup_dropdown_menu) {
|
||||
PopupMenu(&m_top_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2));
|
||||
GetParent()->PopupMenu(&m_top_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2));
|
||||
}
|
||||
else {
|
||||
m_skip_popup_dropdown_menu = false;
|
||||
@@ -610,7 +610,7 @@ void BBLTopbar::OnCalibToolItem(wxAuiToolBarEvent &evt)
|
||||
|
||||
if (!m_skip_popup_calib_menu) {
|
||||
auto rec = this->GetToolRect(ID_CALIB);
|
||||
PopupMenu(&m_calib_menu, wxPoint(rec.GetLeft(), this->GetSize().GetHeight() - 2));
|
||||
GetParent()->PopupMenu(&m_calib_menu, wxPoint(rec.GetLeft(), this->GetSize().GetHeight() - 2));
|
||||
} else {
|
||||
m_skip_popup_calib_menu = false;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ wxString get_fail_reason(int code)
|
||||
SetDoubleBuffered(true);
|
||||
#endif //__WINDOWS__
|
||||
|
||||
m_tocken.reset(new int(0));
|
||||
|
||||
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
|
||||
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
|
||||
|
||||
@@ -296,8 +298,7 @@ wxString get_fail_reason(int code)
|
||||
wxBoxSizer* m_sizer_bind_failed_info = new wxBoxSizer(wxVERTICAL);
|
||||
m_sw_bind_failed_info->SetSizer( m_sizer_bind_failed_info );
|
||||
|
||||
m_link_network_state = new Label(m_sw_bind_failed_info, _L("Check the status of current system services"));
|
||||
m_link_network_state->SetForegroundColour(0x009688);
|
||||
m_link_network_state = new wxHyperlinkCtrl(m_sw_bind_failed_info, wxID_ANY,_L("Check the status of current system services"),"");
|
||||
m_link_network_state->SetFont(::Label::Body_12);
|
||||
m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); });
|
||||
m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); });
|
||||
@@ -433,26 +434,6 @@ wxString get_fail_reason(int code)
|
||||
|
||||
Bind(wxEVT_SHOW, &BindMachineDialog::on_show, this);
|
||||
Bind(wxEVT_CLOSE_WINDOW, &BindMachineDialog::on_close, this);
|
||||
Bind(wxEVT_WEBREQUEST_STATE, [this](wxWebRequestEvent& evt) {
|
||||
switch (evt.GetState()) {
|
||||
// Request completed
|
||||
case wxWebRequest::State_Completed: {
|
||||
wxImage avatar_stream = *evt.GetResponse().GetStream();
|
||||
if (avatar_stream.IsOk()) {
|
||||
avatar_stream.Rescale(FromDIP(60), FromDIP(60));
|
||||
auto bitmap = new wxBitmap(avatar_stream);
|
||||
//bitmap->SetSize(wxSize(FromDIP(60), FromDIP(60)));
|
||||
m_avatar->SetBitmap(*bitmap);
|
||||
Layout();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Request failed
|
||||
case wxWebRequest::State_Failed: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m_button_bind->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BindMachineDialog::on_bind_printer), NULL, this);
|
||||
m_button_cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BindMachineDialog::on_cancel), NULL, this);
|
||||
@@ -536,10 +517,6 @@ wxString get_fail_reason(int code)
|
||||
m_bind_job->cancel();
|
||||
m_bind_job->join();
|
||||
}
|
||||
|
||||
if (web_request.IsOk()) {
|
||||
web_request.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void BindMachineDialog::on_close(wxCloseEvent &event)
|
||||
@@ -597,7 +574,7 @@ wxString get_fail_reason(int code)
|
||||
m_simplebook->SetSelection(0);
|
||||
m_bind_job = std::make_shared<BindJob>(m_status_bar, wxGetApp().plater(), m_machine_info->dev_id, m_machine_info->dev_ip, m_machine_info->bind_sec_link);
|
||||
|
||||
if (m_machine_info && (m_machine_info->printer_type == "BL-P001" || m_machine_info->printer_type == "BL-P002")) {
|
||||
if (m_machine_info && (m_machine_info->get_printer_series() == PrinterSeries::SERIES_X1)) {
|
||||
m_bind_job->set_improved(false);
|
||||
}
|
||||
else {
|
||||
@@ -617,7 +594,7 @@ void BindMachineDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||
void BindMachineDialog::update_machine_info(MachineObject* info)
|
||||
{
|
||||
m_machine_info = info;
|
||||
if (m_machine_info && (m_machine_info->printer_type == "BL-P001" || m_machine_info->printer_type == "BL-P002")) {
|
||||
if (m_machine_info && (m_machine_info->get_printer_series() == PrinterSeries::SERIES_X1)) {
|
||||
m_button_bind->Enable(true);
|
||||
m_panel_agreement->Hide();
|
||||
}
|
||||
@@ -650,14 +627,30 @@ void BindMachineDialog::on_show(wxShowEvent &event)
|
||||
if (wxGetApp().is_user_login()) {
|
||||
wxString username_text = from_u8(wxGetApp().getAgent()->get_user_nickanme());
|
||||
m_user_name->SetLabelText(username_text);
|
||||
web_request = wxWebSession::GetDefault().CreateRequest(this, wxGetApp().getAgent()->get_user_avatar());
|
||||
if (!web_request.IsOk()) {
|
||||
// todo request fail
|
||||
}
|
||||
// Start the request
|
||||
web_request.Start();
|
||||
}
|
||||
|
||||
std::string avatar_url = wxGetApp().getAgent()->get_user_avatar();
|
||||
Slic3r::Http http = Slic3r::Http::get(avatar_url);
|
||||
std::string suffix = avatar_url.substr(avatar_url.find_last_of(".") + 1);
|
||||
http.header("accept", "image/" + suffix)
|
||||
.on_complete([this, time = std::weak_ptr<int>(m_tocken)](std::string body, unsigned int status) {
|
||||
if (time.expired()) return;
|
||||
wxMemoryInputStream stream(body.data(), body.size());
|
||||
wxImage avatar_image;
|
||||
if (avatar_image.LoadFile(stream, wxBITMAP_TYPE_ANY)) {
|
||||
if (avatar_image.IsOk() && m_avatar) {
|
||||
avatar_image.Rescale(this->FromDIP(60), this->FromDIP(60));
|
||||
CallAfter([this, avatar_image]() {
|
||||
auto bitmap = new wxBitmap(avatar_image);
|
||||
m_avatar->SetBitmap(*bitmap);
|
||||
Layout();
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_error([this](std::string body, std::string error, unsigned status) {
|
||||
//BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error;
|
||||
}).perform();
|
||||
}
|
||||
Layout();
|
||||
event.Skip();
|
||||
}
|
||||
@@ -667,7 +660,8 @@ void BindMachineDialog::on_show(wxShowEvent &event)
|
||||
UnBindMachineDialog::UnBindMachineDialog(Plater *plater /*= nullptr*/)
|
||||
: DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, _L("Log out printer"), wxDefaultPosition, wxDefaultSize, wxCAPTION)
|
||||
{
|
||||
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
|
||||
m_tocken.reset(new int(0));
|
||||
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
|
||||
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
|
||||
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
@@ -779,33 +773,12 @@ UnBindMachineDialog::UnBindMachineDialog(Plater *plater /*= nullptr*/)
|
||||
m_button_unbind->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_unbind_printer), NULL, this);
|
||||
m_button_cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_cancel), NULL, this);
|
||||
|
||||
Bind(wxEVT_WEBREQUEST_STATE, [this](wxWebRequestEvent& evt) {
|
||||
switch (evt.GetState()) {
|
||||
// Request completed
|
||||
case wxWebRequest::State_Completed: {
|
||||
wxImage avatar_stream = *evt.GetResponse().GetStream();
|
||||
if (avatar_stream.IsOk()) {
|
||||
avatar_stream.Rescale(FromDIP(60), FromDIP(60));
|
||||
auto bitmap = new wxBitmap(avatar_stream);
|
||||
//bitmap->SetSize(wxSize(FromDIP(60), FromDIP(60)));
|
||||
m_avatar->SetBitmap(*bitmap);
|
||||
Layout();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Request failed
|
||||
case wxWebRequest::State_Failed: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
}
|
||||
|
||||
UnBindMachineDialog::~UnBindMachineDialog()
|
||||
{
|
||||
web_request.Cancel();
|
||||
m_button_unbind->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_unbind_printer), NULL, this);
|
||||
m_button_cancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_cancel), NULL, this);
|
||||
}
|
||||
@@ -874,12 +847,30 @@ void UnBindMachineDialog::on_show(wxShowEvent &event)
|
||||
if (wxGetApp().is_user_login()) {
|
||||
wxString username_text = from_u8(wxGetApp().getAgent()->get_user_name());
|
||||
m_user_name->SetLabelText(username_text);
|
||||
wxString avatar_url = wxGetApp().getAgent()->get_user_avatar();
|
||||
web_request = wxWebSession::GetDefault().CreateRequest(this, avatar_url);
|
||||
if (!web_request.IsOk()) {
|
||||
// todo request fail
|
||||
}
|
||||
web_request.Start();
|
||||
|
||||
std::string avatar_url = wxGetApp().getAgent()->get_user_avatar();
|
||||
Slic3r::Http http = Slic3r::Http::get(avatar_url);
|
||||
std::string suffix = avatar_url.substr(avatar_url.find_last_of(".") + 1);
|
||||
http.header("accept", "image/" + suffix)
|
||||
.on_complete([this, time = std::weak_ptr<int>(m_tocken)](std::string body, unsigned int status) {
|
||||
if (time.expired()) return;
|
||||
wxMemoryInputStream stream(body.data(), body.size());
|
||||
wxImage avatar_image;
|
||||
if (avatar_image.LoadFile(stream, wxBITMAP_TYPE_ANY)) {
|
||||
if (avatar_image.IsOk() && m_avatar) {
|
||||
avatar_image.Rescale(this->FromDIP(60), this->FromDIP(60));
|
||||
CallAfter([this, avatar_image]() {
|
||||
auto bitmap = new wxBitmap(avatar_image);
|
||||
m_avatar->SetBitmap(*bitmap);
|
||||
Layout();
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_error([this](std::string body, std::string error, unsigned status) {
|
||||
//BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error;
|
||||
}).perform();
|
||||
|
||||
}
|
||||
|
||||
Layout();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <wx/dialog.h>
|
||||
#include <curl/curl.h>
|
||||
#include <wx/webrequest.h>
|
||||
#include <wx/hyperlink.h>
|
||||
#include "wxExtensions.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "Widgets/StepCtrl.hpp"
|
||||
@@ -61,19 +62,19 @@ private:
|
||||
wxStaticBitmap *m_static_bitmap_show_error;
|
||||
wxBitmap m_bitmap_show_error_close;
|
||||
wxBitmap m_bitmap_show_error_open;
|
||||
wxWebRequest web_request;
|
||||
wxScrolledWindow* m_sw_bind_failed_info;
|
||||
Label* m_bind_failed_info;
|
||||
Label* m_st_txt_error_code{ nullptr };
|
||||
Label* m_st_txt_error_desc{ nullptr };
|
||||
Label* m_st_txt_extra_info{ nullptr };
|
||||
Label* m_link_network_state{ nullptr };
|
||||
wxHyperlinkCtrl* m_link_network_state{ nullptr };
|
||||
wxString m_result_info;
|
||||
wxString m_result_extra;
|
||||
bool m_show_error_info_state = true;
|
||||
bool m_allow_privacy{false};
|
||||
bool m_allow_notice{false};
|
||||
int m_result_code;
|
||||
std::shared_ptr<int> m_tocken;
|
||||
|
||||
MachineObject * m_machine_info{nullptr};
|
||||
std::shared_ptr<BindJob> m_bind_job;
|
||||
@@ -108,7 +109,7 @@ protected:
|
||||
MachineObject *m_machine_info{nullptr};
|
||||
wxStaticBitmap *m_avatar;
|
||||
wxStaticBitmap *m_printer_img;
|
||||
wxWebRequest web_request;
|
||||
std::shared_ptr<int> m_tocken;
|
||||
|
||||
public:
|
||||
UnBindMachineDialog(Plater *plater = nullptr);
|
||||
|
||||
@@ -502,10 +502,9 @@ wxBitmapBundle* BitmapCache::from_svg(const std::string& bitmap_name, unsigned t
|
||||
+ (dark_mode ? "-dm" : "")
|
||||
+ new_color;
|
||||
|
||||
// Orca: disable to match load_svg function
|
||||
/*auto it = m_bndl_map.find(bitmap_key);
|
||||
auto it = m_bndl_map.find(bitmap_key);
|
||||
if (it != m_bndl_map.end())
|
||||
return it->second;*/
|
||||
return it->second;
|
||||
|
||||
// map of color replaces
|
||||
//Orca: use replaces from load_svg function
|
||||
@@ -568,9 +567,9 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
|
||||
+ (grayscale ? "-gs" : "")
|
||||
+ new_color;
|
||||
|
||||
/*auto it = m_map.find(bitmap_key);
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it != m_map.end())
|
||||
return it->second;*/
|
||||
return it->second;
|
||||
|
||||
// map of color replaces
|
||||
std::map<std::string, std::string> replaces;
|
||||
@@ -762,5 +761,46 @@ wxBitmapBundle* BitmapCache::mksolid_bndl(size_t width, size_t height, const std
|
||||
return bndl;
|
||||
}
|
||||
|
||||
bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
|
||||
{
|
||||
if (scolor.size() == 9) {
|
||||
unsigned char rgba[4];
|
||||
parse_color4(scolor, rgba);
|
||||
rgb_out[0] = rgba[0];
|
||||
rgb_out[1] = rgba[1];
|
||||
rgb_out[2] = rgba[2];
|
||||
return true;
|
||||
}
|
||||
rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
|
||||
if (scolor.size() != 7 || scolor.front() != '#')
|
||||
return false;
|
||||
const char* c = scolor.data() + 1;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
int digit1 = hex_digit_to_int(*c++);
|
||||
int digit2 = hex_digit_to_int(*c++);
|
||||
if (digit1 == -1 || digit2 == -1)
|
||||
return false;
|
||||
rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitmapCache::parse_color4(const std::string& scolor, unsigned char* rgba_out)
|
||||
{
|
||||
rgba_out[0] = rgba_out[1] = rgba_out[2] = 0; rgba_out[3] = 255;
|
||||
if ((scolor.size() != 7 && scolor.size() != 9) || scolor.front() != '#')
|
||||
return false;
|
||||
const char* c = scolor.data() + 1;
|
||||
for (size_t i = 0; i < scolor.size() / 2; ++i) {
|
||||
int digit1 = hex_digit_to_int(*c++);
|
||||
int digit2 = hex_digit_to_int(*c++);
|
||||
if (digit1 == -1 || digit2 == -1)
|
||||
return false;
|
||||
rgba_out[i] = (unsigned char)(digit1 * 16 + digit2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -59,12 +59,16 @@ public:
|
||||
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false, const std::string& new_color = "", const float scale_in_center = 0.f);
|
||||
|
||||
wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false);
|
||||
wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); }
|
||||
wxBitmap mksolid(size_t width, size_t height, const ColorRGB& rgb, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar(), wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); }
|
||||
wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT, true, 0); }
|
||||
wxBitmapBundle mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, size_t border_width = 0, bool dark_mode = false);
|
||||
wxBitmapBundle* mksolid_bndl(size_t width, size_t height, const std::string& color = std::string(), size_t border_width = 0, bool dark_mode = false);
|
||||
wxBitmapBundle* mkclear_bndl(size_t width, size_t height) { return mksolid_bndl(width, height); }
|
||||
|
||||
static bool parse_color(const std::string& scolor, unsigned char* rgb_out);
|
||||
static bool parse_color4(const std::string& scolor, unsigned char* rgba_out);
|
||||
|
||||
private:
|
||||
std::map<std::string, wxBitmap*> m_map;
|
||||
std::map<std::string, wxBitmapBundle*> m_bndl_map;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace GUI {
|
||||
#define HISTORY_WINDOW_SIZE wxSize(FromDIP(700), FromDIP(600))
|
||||
#define EDIT_HISTORY_DIALOG_INPUT_SIZE wxSize(FromDIP(160), FromDIP(24))
|
||||
#define HISTORY_WINDOW_ITEMS_COUNT 5
|
||||
static const wxString k_tips = "Please input a valid value (K in 0~0.3)";
|
||||
|
||||
static wxString get_preset_name_by_filament_id(std::string filament_id)
|
||||
{
|
||||
@@ -351,18 +352,10 @@ EditCalibrationHistoryDialog::EditCalibrationHistoryDialog(wxWindow* parent, con
|
||||
flex_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
|
||||
|
||||
Label* name_title = new Label(top_panel, _L("Name"));
|
||||
TextInput* name_value = new TextInput(top_panel, from_u8(m_new_result.name), "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER);
|
||||
name_value->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this, name_value](auto& e) {
|
||||
if (!name_value->GetTextCtrl()->GetValue().IsEmpty())
|
||||
m_new_result.name = name_value->GetTextCtrl()->GetValue().ToUTF8().data();
|
||||
});
|
||||
name_value->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this, name_value](auto& e) {
|
||||
if (!name_value->GetTextCtrl()->GetValue().IsEmpty())
|
||||
m_new_result.name = name_value->GetTextCtrl()->GetValue().ToUTF8().data();
|
||||
e.Skip();
|
||||
});
|
||||
m_name_value = new TextInput(top_panel, from_u8(m_new_result.name), "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER);
|
||||
|
||||
flex_sizer->Add(name_title);
|
||||
flex_sizer->Add(name_value);
|
||||
flex_sizer->Add(m_name_value);
|
||||
|
||||
Label* preset_name_title = new Label(top_panel, _L("Filament"));
|
||||
wxString preset_name = get_preset_name_by_filament_id(result.filament_id);
|
||||
@@ -372,30 +365,9 @@ EditCalibrationHistoryDialog::EditCalibrationHistoryDialog(wxWindow* parent, con
|
||||
|
||||
Label* k_title = new Label(top_panel, _L("Factor K"));
|
||||
auto k_str = wxString::Format("%.3f", m_new_result.k_value);
|
||||
TextInput* k_value = new TextInput(top_panel, k_str, "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER);
|
||||
k_value->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this, k_value](auto& e) {
|
||||
float k = 0.0f;
|
||||
if (!CalibUtils::validate_input_k_value(k_value->GetTextCtrl()->GetValue(), &k)) {
|
||||
MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
}
|
||||
wxString k_str = wxString::Format("%.3f", k);
|
||||
k_value->GetTextCtrl()->SetValue(k_str);
|
||||
m_new_result.k_value = k;
|
||||
});
|
||||
k_value->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this, k_value](auto& e) {
|
||||
float k = 0.0f;
|
||||
if (!CalibUtils::validate_input_k_value(k_value->GetTextCtrl()->GetValue(), &k)) {
|
||||
MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
}
|
||||
wxString k_str = wxString::Format("%.3f", k);
|
||||
k_value->GetTextCtrl()->SetValue(k_str);
|
||||
m_new_result.k_value = k;
|
||||
e.Skip();
|
||||
});
|
||||
m_k_value = new TextInput(top_panel, k_str, "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER);
|
||||
flex_sizer->Add(k_title);
|
||||
flex_sizer->Add(k_value);
|
||||
flex_sizer->Add(m_k_value);
|
||||
|
||||
// Hide:
|
||||
//Label* n_title = new Label(top_panel, _L("Factor N"));
|
||||
@@ -449,6 +421,27 @@ PACalibResult EditCalibrationHistoryDialog::get_result() {
|
||||
}
|
||||
|
||||
void EditCalibrationHistoryDialog::on_save(wxCommandEvent& event) {
|
||||
wxString name = m_name_value->GetTextCtrl()->GetValue();
|
||||
if (name.IsEmpty())
|
||||
return;
|
||||
if (name.Length() > 40) {
|
||||
MessageDialog msg_dlg(nullptr, _L("The name cannot exceed 40 characters."), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
m_new_result.name = m_name_value->GetTextCtrl()->GetValue().ToUTF8().data();
|
||||
|
||||
float k = 0.0f;
|
||||
if (!CalibUtils::validate_input_k_value(m_k_value->GetTextCtrl()->GetValue(), &k)) {
|
||||
MessageDialog msg_dlg(nullptr, _L(k_tips), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
wxString k_str = wxString::Format("%.3f", k);
|
||||
m_k_value->GetTextCtrl()->SetValue(k_str);
|
||||
m_new_result.k_value = k;
|
||||
|
||||
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,9 @@ protected:
|
||||
|
||||
protected:
|
||||
PACalibResult m_new_result;
|
||||
|
||||
TextInput* m_name_value{ nullptr };
|
||||
TextInput* m_k_value{ nullptr };
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
||||
@@ -215,36 +215,27 @@ wxWindow* CalibrationDialog::create_check_option(wxString title, wxWindow* paren
|
||||
void CalibrationDialog::update_cali(MachineObject *obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
if (obj->is_function_supported(PrinterFunction::FUNC_AI_MONITORING)
|
||||
&& obj->is_function_supported(PrinterFunction::FUNC_LIDAR_CALIBRATION)) {
|
||||
if (obj->is_support_ai_monitoring && obj->is_support_lidar_calibration) {
|
||||
select_xcam_cali->Show();
|
||||
} else {
|
||||
select_xcam_cali->Hide();
|
||||
m_checkbox_list["xcam_cali"]->SetValue(false);
|
||||
}
|
||||
|
||||
if(obj->is_function_supported(PrinterFunction::FUNC_AUTO_LEVELING)){
|
||||
if(obj->is_support_auto_leveling){
|
||||
select_bed_leveling->Show();
|
||||
}else{
|
||||
select_bed_leveling->Hide();
|
||||
m_checkbox_list["bed_leveling"]->SetValue(false);
|
||||
}
|
||||
|
||||
if (obj->is_function_supported(PrinterFunction::FUNC_MOTOR_NOISE_CALI)) {
|
||||
if (obj->is_support_motor_noise_cali) {
|
||||
select_motor_noise->Show();
|
||||
} else {
|
||||
select_motor_noise->Hide();
|
||||
m_checkbox_list["motor_noise"]->SetValue(false);
|
||||
}
|
||||
|
||||
if (!m_checkbox_list["vibration"]->GetValue() && !m_checkbox_list["bed_leveling"]->GetValue() && !m_checkbox_list["xcam_cali"]->GetValue() &&
|
||||
!m_checkbox_list["motor_noise"]->GetValue()) {
|
||||
m_calibration_btn->Disable();
|
||||
m_calibration_btn->SetLabel(_L("No step selected"));
|
||||
return ;
|
||||
} else {
|
||||
m_calibration_btn->Enable();
|
||||
}
|
||||
|
||||
if (obj->is_calibration_running() || obj->is_calibration_done()) {
|
||||
if (obj->is_calibration_done()) {
|
||||
@@ -282,6 +273,14 @@ void CalibrationDialog::update_cali(MachineObject *obj)
|
||||
m_calibration_flow->DeleteAllItems();
|
||||
m_calibration_btn->SetLabel(_L("Start Calibration"));
|
||||
}
|
||||
if (!obj->is_calibration_running() && !m_checkbox_list["vibration"]->GetValue() && !m_checkbox_list["bed_leveling"]->GetValue() &&
|
||||
!m_checkbox_list["xcam_cali"]->GetValue() && !m_checkbox_list["motor_noise"]->GetValue()) {
|
||||
m_calibration_btn->Disable();
|
||||
m_calibration_btn->SetLabel(_L("No step selected"));
|
||||
}
|
||||
else if(!obj->is_calibration_running()){
|
||||
m_calibration_btn->Enable();
|
||||
}
|
||||
}
|
||||
|
||||
bool CalibrationDialog::is_stage_list_info_changed(MachineObject *obj)
|
||||
|
||||
@@ -242,21 +242,26 @@ void SelectMObjectPopup::Popup(wxWindow* WXUNUSED(focus))
|
||||
|
||||
if (wxGetApp().is_user_login()) {
|
||||
if (!get_print_info_thread) {
|
||||
get_print_info_thread = new boost::thread(Slic3r::create_thread([&] {
|
||||
get_print_info_thread = new boost::thread(Slic3r::create_thread([this, token = std::weak_ptr(m_token)] {
|
||||
NetworkAgent* agent = wxGetApp().getAgent();
|
||||
unsigned int http_code;
|
||||
std::string body;
|
||||
int result = agent->get_user_print_info(&http_code, &body);
|
||||
if (result == 0) {
|
||||
m_print_info = body;
|
||||
}
|
||||
else {
|
||||
m_print_info = "";
|
||||
}
|
||||
wxCommandEvent event(EVT_UPDATE_USER_MLIST);
|
||||
event.SetEventObject(this);
|
||||
wxPostEvent(this, event);
|
||||
}));
|
||||
|
||||
wxGetApp().CallAfter([token, this, result, body]() {
|
||||
if (token.expired()) {return;}
|
||||
if (result == 0) {
|
||||
m_print_info = body;
|
||||
}
|
||||
else {
|
||||
m_print_info = "";
|
||||
}
|
||||
|
||||
wxCommandEvent event(EVT_UPDATE_USER_MLIST);
|
||||
event.SetEventObject(this);
|
||||
wxPostEvent(this, event);
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,10 +515,15 @@ void CalibrationPanel::update_print_error_info(int code, std::string msg, std::s
|
||||
if (curr_selected >= 0 && curr_selected < CALI_MODE_COUNT) {
|
||||
if (m_cali_panels[curr_selected]) {
|
||||
auto page = m_cali_panels[curr_selected]->get_curr_step()->page;
|
||||
if(page && page->get_page_type() == CaliPageType::CALI_PAGE_PRESET){
|
||||
auto preset_page = static_cast<CalibrationPresetPage*>(page);
|
||||
if (preset_page->get_page_status() == CaliPresetPageStatus::CaliPresetStatusSending)
|
||||
if (page) {
|
||||
if (page->get_page_type() == CaliPageType::CALI_PAGE_PRESET) {
|
||||
auto preset_page = static_cast<CalibrationPresetPage*>(page);
|
||||
preset_page->update_print_error_info(code, msg, extra);
|
||||
}
|
||||
if (page->get_page_type() == CaliPageType::CALI_PAGE_COARSE_SAVE) {
|
||||
auto corase_page = static_cast<CalibrationFlowCoarseSavePage*>(page);
|
||||
corase_page->update_print_error_info(code, msg, extra);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ private:
|
||||
std::vector<MPanel*> m_user_list_machine_panel;
|
||||
boost::thread* get_print_info_thread{ nullptr };
|
||||
std::string m_print_info;
|
||||
std::shared_ptr<int> m_token = std::make_shared<int>(0);
|
||||
std::map<std::string, MachineObject*> m_bind_machine_list;
|
||||
|
||||
private:
|
||||
|
||||
@@ -16,7 +16,7 @@ wxDEFINE_EVENT(EVT_CALIBRATION_JOB_FINISHED, wxCommandEvent);
|
||||
|
||||
static const wxString NA_STR = _L("N/A");
|
||||
static const float MIN_PA_K_VALUE = 0.0;
|
||||
static const float MAX_PA_K_VALUE = 0.5;
|
||||
static const float MAX_PA_K_VALUE = 0.3;
|
||||
static const float MIN_PA_K_VALUE_STEP = 0.001;
|
||||
|
||||
bool check_preset_name_valid(const wxString& name) {
|
||||
@@ -185,17 +185,17 @@ void CalibrationWizard::set_cali_method(CalibrationMethod method)
|
||||
}
|
||||
}
|
||||
|
||||
bool CalibrationWizard::save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map<std::string, ConfigOption *> &key_values, std::string& message)
|
||||
bool CalibrationWizard::save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map<std::string, ConfigOption *> &key_values, wxString& message)
|
||||
{
|
||||
if (new_preset_name.empty()) {
|
||||
message = _u8L("The name cannot be empty.");
|
||||
message = _L("The name cannot be empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PresetCollection *filament_presets = &wxGetApp().preset_bundle->filaments;
|
||||
Preset* preset = filament_presets->find_preset(old_preset_name);
|
||||
if (!preset) {
|
||||
message = (boost::format(_u8L("The selected preset: %1% is not found.")) % old_preset_name).str();
|
||||
message = wxString::Format(_L("The selected preset: %s is not found."), old_preset_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -207,12 +207,12 @@ bool CalibrationWizard::save_preset(const std::string &old_preset_name, const st
|
||||
Preset *new_preset = filament_presets->find_preset(new_name);
|
||||
if (new_preset) {
|
||||
if (new_preset->is_system) {
|
||||
message = _u8L("The name cannot be the same as the system preset name.");
|
||||
message = _L("The name cannot be the same as the system preset name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new_preset != preset) {
|
||||
message = _u8L("The name is the same as another existing preset name");
|
||||
message = _L("The name is the same as another existing preset name");
|
||||
return false;
|
||||
}
|
||||
if (new_preset != &filament_presets->get_edited_preset()) new_preset = &temp_preset;
|
||||
@@ -233,7 +233,7 @@ bool CalibrationWizard::save_preset(const std::string &old_preset_name, const st
|
||||
// Preset* preset = &m_presets.preset(it - m_presets.begin(), true);
|
||||
if (!new_preset) {
|
||||
BOOST_LOG_TRIVIAL(info) << "create new preset failed";
|
||||
message = _u8L("create new preset failed.");
|
||||
message = _L("create new preset failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -299,14 +299,14 @@ void CalibrationWizard::recover_preset_info(MachineObject *obj)
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationWizard::back_preset_info(MachineObject *obj, bool cali_finish)
|
||||
void CalibrationWizard::back_preset_info(MachineObject *obj, bool cali_finish, bool back_cali_flag)
|
||||
{
|
||||
PrinterCaliInfo printer_cali_info;
|
||||
printer_cali_info.dev_id = obj->dev_id;
|
||||
printer_cali_info.cali_finished = cali_finish;
|
||||
printer_cali_info.cache_flow_ratio = obj->cache_flow_ratio;
|
||||
printer_cali_info.selected_presets = obj->selected_cali_preset;
|
||||
wxGetApp().app_config->save_printer_cali_infos(printer_cali_info);
|
||||
wxGetApp().app_config->save_printer_cali_infos(printer_cali_info, back_cali_flag);
|
||||
}
|
||||
|
||||
void CalibrationWizard::msw_rescale()
|
||||
@@ -361,7 +361,7 @@ void CalibrationWizard::on_cali_go_home()
|
||||
go_home_dialog->on_show();
|
||||
} else {
|
||||
if (!m_page_steps.empty()) {
|
||||
back_preset_info(curr_obj, true);
|
||||
back_preset_info(curr_obj, true, obj_cali_mode == m_mode);
|
||||
show_step(m_page_steps.front());
|
||||
}
|
||||
}
|
||||
@@ -951,6 +951,7 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow
|
||||
cali_page->clear_last_job_status();
|
||||
}
|
||||
else if (m_cali_method == CalibrationMethod::CALI_METHOD_MANUAL) {
|
||||
CalibrationFlowCoarseSavePage* coarse_page = (static_cast<CalibrationFlowCoarseSavePage*>(coarse_save_step->page));
|
||||
CalibInfo calib_info;
|
||||
calib_info.dev_id = curr_obj->dev_id;
|
||||
Preset* temp_filament_preset = nullptr;
|
||||
@@ -979,17 +980,23 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow
|
||||
temp_filament_preset->config = preset->config;
|
||||
|
||||
calib_info.bed_type = plate_type;
|
||||
calib_info.process_bar = preset_page->get_sending_progress_bar();
|
||||
calib_info.printer_prest = preset_page->get_printer_preset(curr_obj, nozzle_dia);
|
||||
calib_info.print_prest = preset_page->get_print_preset();
|
||||
calib_info.params.mode = CalibMode::Calib_Flow_Rate;
|
||||
|
||||
if (stage == CaliPresetStage::CALI_MANUAL_STAGE_1) {
|
||||
cali_stage = 1;
|
||||
calib_info.process_bar = preset_page->get_sending_progress_bar();
|
||||
}
|
||||
else if (stage == CaliPresetStage::CALI_MANUAL_STAGE_2) {
|
||||
cali_stage = 2;
|
||||
temp_filament_preset->config.set_key_value("filament_flow_ratio", new ConfigOptionFloats{ cali_value });
|
||||
if (from_page == FlowRatioCaliSource::FROM_PRESET_PAGE) {
|
||||
calib_info.process_bar = preset_page->get_sending_progress_bar();
|
||||
}
|
||||
else if (from_page == FlowRatioCaliSource::FROM_COARSE_PAGE) {
|
||||
calib_info.process_bar = coarse_page->get_sending_progress_bar();
|
||||
}
|
||||
}
|
||||
calib_info.filament_prest = temp_filament_preset;
|
||||
|
||||
@@ -1008,17 +1015,23 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
preset_page->on_cali_start_job();
|
||||
if (temp_filament_preset)
|
||||
delete temp_filament_preset;
|
||||
|
||||
if (cali_stage == 1) {
|
||||
CalibrationCaliPage *cali_coarse_page = (static_cast<CalibrationCaliPage *>(cali_coarse_step->page));
|
||||
cali_coarse_page->clear_last_job_status();
|
||||
preset_page->on_cali_start_job();
|
||||
}
|
||||
else if (cali_stage == 2) {
|
||||
CalibrationCaliPage *cali_fine_page = (static_cast<CalibrationCaliPage *>(cali_fine_step->page));
|
||||
cali_fine_page->clear_last_job_status();
|
||||
if (from_page == FlowRatioCaliSource::FROM_PRESET_PAGE) {
|
||||
preset_page->on_cali_start_job();
|
||||
}
|
||||
else if (from_page == FlowRatioCaliSource::FROM_COARSE_PAGE) {
|
||||
coarse_page->on_cali_start_job();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
@@ -1050,7 +1063,7 @@ void FlowRateWizard::on_cali_save()
|
||||
for (int i = 0; i < new_results.size(); i++) {
|
||||
std::map<std::string, ConfigOption*> key_value_map;
|
||||
key_value_map.insert(std::make_pair("filament_flow_ratio", new ConfigOptionFloats{ new_results[i].second }));
|
||||
std::string message;
|
||||
wxString message;
|
||||
if (!save_preset(old_preset_name, into_u8(new_results[i].first), key_value_map, message)) {
|
||||
MessageDialog error_msg_dlg(nullptr, message, wxEmptyString, wxICON_WARNING | wxOK);
|
||||
error_msg_dlg.ShowModal();
|
||||
@@ -1097,9 +1110,9 @@ void FlowRateWizard::on_cali_save()
|
||||
std::map<std::string, ConfigOption*> key_value_map;
|
||||
key_value_map.insert(std::make_pair("filament_flow_ratio", new ConfigOptionFloats{ new_flow_ratio }));
|
||||
|
||||
std::string message;
|
||||
wxString message;
|
||||
if (!save_preset(old_preset_name, into_u8(new_preset_name), key_value_map, message)) {
|
||||
MessageDialog error_msg_dlg(nullptr, from_u8(message), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
MessageDialog error_msg_dlg(nullptr, message, wxEmptyString, wxICON_WARNING | wxOK);
|
||||
error_msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
@@ -1197,17 +1210,20 @@ void FlowRateWizard::on_cali_job_finished(wxString evt_data)
|
||||
if (cali_stage == 1) {
|
||||
if (m_curr_step != cali_coarse_step)
|
||||
show_step(cali_coarse_step);
|
||||
// change ui, hide
|
||||
static_cast<CalibrationPresetPage*>(preset_step->page)->on_cali_finished_job();
|
||||
}
|
||||
else if (cali_stage == 2) {
|
||||
if (m_curr_step != cali_fine_step) {
|
||||
show_step(cali_fine_step);
|
||||
}
|
||||
// change ui, hide
|
||||
static_cast<CalibrationPresetPage*>(preset_step->page)->on_cali_finished_job();
|
||||
static_cast<CalibrationFlowCoarseSavePage*>(coarse_save_step->page)->on_cali_finished_job();
|
||||
}
|
||||
else
|
||||
show_step(cali_coarse_step);
|
||||
}
|
||||
// change ui, hide
|
||||
static_cast<CalibrationPresetPage*>(preset_step->page)->on_cali_finished_job();
|
||||
}
|
||||
|
||||
void FlowRateWizard::cache_coarse_info(MachineObject *obj)
|
||||
@@ -1375,9 +1391,9 @@ void MaxVolumetricSpeedWizard::on_cali_save()
|
||||
std::map<std::string, ConfigOption *> key_value_map;
|
||||
key_value_map.insert(std::make_pair("filament_max_volumetric_speed", new ConfigOptionFloats{ value }));
|
||||
|
||||
std::string message;
|
||||
wxString message;
|
||||
if (!save_preset(old_preset_name, new_preset_name, key_value_map, message)) {
|
||||
MessageDialog error_msg_dlg(nullptr, from_u8(message), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
MessageDialog error_msg_dlg(nullptr, message, wxEmptyString, wxICON_WARNING | wxOK);
|
||||
error_msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,11 +60,11 @@ public:
|
||||
|
||||
CalibMode get_calibration_mode() { return m_mode; }
|
||||
|
||||
bool save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map<std::string, ConfigOption *> &key_values, std::string& message);
|
||||
bool save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map<std::string, ConfigOption *> &key_values, wxString& message);
|
||||
|
||||
virtual void cache_preset_info(MachineObject* obj, float nozzle_dia);
|
||||
virtual void recover_preset_info(MachineObject *obj);
|
||||
virtual void back_preset_info(MachineObject *obj, bool cali_finish);
|
||||
virtual void back_preset_info(MachineObject *obj, bool cali_finish, bool back_cali_flag = true);
|
||||
|
||||
void msw_rescale();
|
||||
void on_sys_color_changed();
|
||||
|
||||
@@ -101,27 +101,27 @@ void CalibrationCaliPage::set_cali_img()
|
||||
{
|
||||
if (m_cali_mode == CalibMode::Calib_PA_Line) {
|
||||
if (m_cali_method == CalibrationMethod::CALI_METHOD_MANUAL) {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual", 400));
|
||||
}
|
||||
else if (m_cali_method == CalibrationMethod::CALI_METHOD_AUTO) {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_auto", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_auto", 400));
|
||||
}
|
||||
}
|
||||
else if (m_cali_mode == CalibMode::Calib_Flow_Rate) {
|
||||
if (m_cali_method == CalibrationMethod::CALI_METHOD_MANUAL) {
|
||||
if (m_page_type == CaliPageType::CALI_PAGE_CALI)
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse", 400));
|
||||
if (m_page_type == CaliPageType::CALI_PAGE_FINE_CALI)
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_fine", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine", 400));
|
||||
else
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse", 400));
|
||||
}
|
||||
else if (m_cali_method == CalibrationMethod::CALI_METHOD_AUTO) {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_auto", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_auto", 400));
|
||||
}
|
||||
}
|
||||
else if (m_cali_mode == CalibMode::Calib_Vol_speed_Tower) {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("max_volumetric_speed_calibration", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "max_volumetric_speed_calibration", 400));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +129,9 @@ void CalibrationCaliPage::set_pa_cali_image(int stage)
|
||||
{
|
||||
if (m_cali_mode == CalibMode::Calib_PA_Line && m_cali_method == CALI_METHOD_MANUAL) {
|
||||
if (stage == 0) {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual", 400));
|
||||
} else if (stage == 1) {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual", nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual", 400));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,7 +428,7 @@ void CalibrationCaliPage::reset_printing_values()
|
||||
|
||||
void CalibrationCaliPage::on_device_connected(MachineObject* obj)
|
||||
{
|
||||
;
|
||||
reset_printing_values();
|
||||
}
|
||||
|
||||
void CalibrationCaliPage::set_cali_method(CalibrationMethod method)
|
||||
@@ -473,6 +473,20 @@ void CalibrationCaliPage::set_cali_method(CalibrationMethod method)
|
||||
}
|
||||
}
|
||||
|
||||
bool CalibrationCaliPage::Show(bool show /*= true*/)
|
||||
{
|
||||
if (true) {
|
||||
reset_printing_values();
|
||||
}
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void CalibrationCaliPage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
m_picture_panel->msw_rescale();
|
||||
}
|
||||
|
||||
float CalibrationCaliPage::get_selected_calibration_nozzle_dia(MachineObject* obj)
|
||||
{
|
||||
// return selected if this is set
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
void on_device_connected(MachineObject* obj) override;
|
||||
|
||||
void set_cali_method(CalibrationMethod method) override;
|
||||
virtual bool Show(bool show = true) override;
|
||||
void msw_rescale() override;
|
||||
|
||||
protected:
|
||||
float get_selected_calibration_nozzle_dia(MachineObject* obj);
|
||||
|
||||
@@ -249,6 +249,13 @@ CaliPageButton::CaliPageButton(wxWindow* parent, CaliPageActionType type, wxStri
|
||||
SetCornerRadius(FromDIP(12));
|
||||
}
|
||||
|
||||
void CaliPageButton::msw_rescale()
|
||||
{
|
||||
SetMinSize(wxSize(-1, FromDIP(24)));
|
||||
SetCornerRadius(FromDIP(12));
|
||||
Rescale();
|
||||
}
|
||||
|
||||
|
||||
FilamentComboBox::FilamentComboBox(wxWindow* parent, const wxPoint& pos, const wxSize& size)
|
||||
: wxPanel(parent, wxID_ANY, pos, size, wxTAB_TRAVERSAL)
|
||||
@@ -343,6 +350,14 @@ void FilamentComboBox::SetValue(bool value, bool send_event) {
|
||||
m_checkBox->SetValue(value);
|
||||
}
|
||||
|
||||
void FilamentComboBox::msw_rescale()
|
||||
{
|
||||
//m_checkBox->Rescale();
|
||||
m_comboBox->SetSize(CALIBRATION_FILAMENT_COMBOX_SIZE);
|
||||
m_comboBox->SetMinSize(CALIBRATION_FILAMENT_COMBOX_SIZE);
|
||||
m_comboBox->msw_rescale();
|
||||
}
|
||||
|
||||
|
||||
|
||||
CaliPageCaption::CaliPageCaption(wxWindow* parent, CalibMode cali_mode,
|
||||
@@ -460,6 +475,11 @@ void CaliPageCaption::on_sys_color_changed()
|
||||
m_prev_btn->msw_rescale();
|
||||
}
|
||||
|
||||
void CaliPageCaption::msw_rescale()
|
||||
{
|
||||
m_prev_btn->msw_rescale();
|
||||
}
|
||||
|
||||
CaliPageStepGuide::CaliPageStepGuide(wxWindow* parent, wxArrayString steps,
|
||||
wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: wxPanel(parent, id, pos, size, style),
|
||||
@@ -541,9 +561,16 @@ CaliPagePicture::CaliPagePicture(wxWindow* parent, wxWindowID id, const wxPoint&
|
||||
top_sizer->Fit(this);
|
||||
}
|
||||
|
||||
void CaliPagePicture::set_img(const wxBitmap& bmp)
|
||||
void CaliPagePicture::set_bmp(const ScalableBitmap& bmp)
|
||||
{
|
||||
m_img->SetBitmap(bmp);
|
||||
m_bmp = bmp;
|
||||
m_img->SetBitmap(m_bmp.bmp());
|
||||
}
|
||||
|
||||
void CaliPagePicture::msw_rescale()
|
||||
{
|
||||
m_bmp.msw_rescale();
|
||||
m_img->SetBitmap(m_bmp.bmp());
|
||||
}
|
||||
|
||||
|
||||
@@ -582,6 +609,13 @@ PAPageHelpPanel::PAPageHelpPanel(wxWindow* parent, bool ground_panel, wxWindowID
|
||||
top_sizer->Fit(this);
|
||||
}
|
||||
|
||||
void PAPageHelpPanel::msw_rescale()
|
||||
{
|
||||
m_help_btn->msw_rescale();
|
||||
m_bmp.msw_rescale();
|
||||
m_img->SetBitmap(m_bmp.bmp());
|
||||
}
|
||||
|
||||
void PAPageHelpPanel::create_pop_window()
|
||||
{
|
||||
m_pop_win = new PopupWindow(this);
|
||||
@@ -589,13 +623,10 @@ void PAPageHelpPanel::create_pop_window()
|
||||
wxBoxSizer* pop_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_pop_win->SetSizer(pop_sizer);
|
||||
|
||||
wxStaticBitmap* img = new wxStaticBitmap(m_pop_win, wxID_ANY, wxNullBitmap);
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
img->SetBitmap(ScalableBitmap(this, "cali_fdc_editing_diagram_CN", 206).bmp());
|
||||
} else {
|
||||
img->SetBitmap(ScalableBitmap(this, "cali_fdc_editing_diagram", 206).bmp());
|
||||
}
|
||||
pop_sizer->Add(img, 1, wxEXPAND | wxALL, FromDIP(20));
|
||||
m_img = new wxStaticBitmap(m_pop_win, wxID_ANY, wxNullBitmap);
|
||||
m_bmp = ScalableBitmap(this, "cali_fdc_editing_diagram", 206);
|
||||
m_img->SetBitmap(m_bmp.bmp());
|
||||
pop_sizer->Add(m_img, 1, wxEXPAND | wxALL, FromDIP(20));
|
||||
|
||||
m_pop_win->Layout();
|
||||
m_pop_win->Fit();
|
||||
@@ -754,6 +785,163 @@ void CaliPageActionPanel::enable_button(CaliPageActionType action_type, bool ena
|
||||
}
|
||||
}
|
||||
|
||||
void CaliPageActionPanel::msw_rescale()
|
||||
{
|
||||
for (int i = 0; i < m_action_btns.size(); i++) {
|
||||
m_action_btns[i]->msw_rescale();
|
||||
}
|
||||
}
|
||||
|
||||
CaliPageSendingPanel::CaliPageSendingPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: wxPanel(parent, id, pos, size, style)
|
||||
{
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
SetMinSize({ FromDIP(475), FromDIP(200) });
|
||||
SetMaxSize({ FromDIP(475), FromDIP(200) });
|
||||
|
||||
create(this);
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
|
||||
Bind(EVT_SHOW_ERROR_INFO, [this](auto& e) {
|
||||
show_send_failed_info(true);
|
||||
});
|
||||
}
|
||||
|
||||
void CaliPageSendingPanel::create(wxWindow* parent)
|
||||
{
|
||||
auto panel_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
parent->SetSizer(panel_sizer);
|
||||
|
||||
m_send_progress_bar = std::shared_ptr<BBLStatusBarSend>(new BBLStatusBarSend(parent));
|
||||
panel_sizer->Add(m_send_progress_bar->get_panel(), 0, wxEXPAND);
|
||||
|
||||
m_sw_print_failed_info = new wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(380), FromDIP(125)), wxVSCROLL);
|
||||
m_sw_print_failed_info->SetBackgroundColour(*wxWHITE);
|
||||
m_sw_print_failed_info->SetScrollRate(0, 5);
|
||||
m_sw_print_failed_info->SetMinSize(wxSize(FromDIP(380), FromDIP(125)));
|
||||
m_sw_print_failed_info->SetMaxSize(wxSize(FromDIP(380), FromDIP(125)));
|
||||
|
||||
m_sw_print_failed_info->Hide();
|
||||
|
||||
panel_sizer->Add(m_sw_print_failed_info, 0, wxEXPAND);
|
||||
|
||||
// create error info panel
|
||||
wxBoxSizer* sizer_print_failed_info = new wxBoxSizer(wxVERTICAL);
|
||||
m_sw_print_failed_info->SetSizer(sizer_print_failed_info);
|
||||
|
||||
wxBoxSizer* sizer_error_code = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* sizer_extra_info = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto st_title_error_code = new Label(m_sw_print_failed_info, _L("Error code"));
|
||||
auto st_title_error_code_doc = new Label(m_sw_print_failed_info, ": ");
|
||||
m_st_txt_error_code = new Label(m_sw_print_failed_info, wxEmptyString);
|
||||
st_title_error_code->SetForegroundColour(0x909090);
|
||||
st_title_error_code_doc->SetForegroundColour(0x909090);
|
||||
m_st_txt_error_code->SetForegroundColour(0x909090);
|
||||
st_title_error_code->SetFont(::Label::Body_13);
|
||||
st_title_error_code_doc->SetFont(::Label::Body_13);
|
||||
m_st_txt_error_code->SetFont(::Label::Body_13);
|
||||
st_title_error_code->SetMinSize(wxSize(FromDIP(74), -1));
|
||||
st_title_error_code->SetMaxSize(wxSize(FromDIP(74), -1));
|
||||
m_st_txt_error_code->SetMinSize(wxSize(FromDIP(260), -1));
|
||||
m_st_txt_error_code->SetMaxSize(wxSize(FromDIP(260), -1));
|
||||
sizer_error_code->Add(st_title_error_code, 0, wxALL, 0);
|
||||
sizer_error_code->Add(st_title_error_code_doc, 0, wxALL, 0);
|
||||
sizer_error_code->Add(m_st_txt_error_code, 0, wxALL, 0);
|
||||
|
||||
auto st_title_error_desc = new Label(m_sw_print_failed_info, _L("Error desc"));
|
||||
auto st_title_error_desc_doc = new Label(m_sw_print_failed_info, ": ");
|
||||
m_st_txt_error_desc = new Label(m_sw_print_failed_info, wxEmptyString);
|
||||
st_title_error_desc->SetForegroundColour(0x909090);
|
||||
st_title_error_desc_doc->SetForegroundColour(0x909090);
|
||||
m_st_txt_error_desc->SetForegroundColour(0x909090);
|
||||
st_title_error_desc->SetFont(::Label::Body_13);
|
||||
st_title_error_desc_doc->SetFont(::Label::Body_13);
|
||||
m_st_txt_error_desc->SetFont(::Label::Body_13);
|
||||
st_title_error_desc->SetMinSize(wxSize(FromDIP(74), -1));
|
||||
st_title_error_desc->SetMaxSize(wxSize(FromDIP(74), -1));
|
||||
m_st_txt_error_desc->SetMinSize(wxSize(FromDIP(260), -1));
|
||||
m_st_txt_error_desc->SetMaxSize(wxSize(FromDIP(260), -1));
|
||||
sizer_error_desc->Add(st_title_error_desc, 0, wxALL, 0);
|
||||
sizer_error_desc->Add(st_title_error_desc_doc, 0, wxALL, 0);
|
||||
sizer_error_desc->Add(m_st_txt_error_desc, 0, wxALL, 0);
|
||||
|
||||
auto st_title_extra_info = new Label(m_sw_print_failed_info, _L("Extra info"));
|
||||
auto st_title_extra_info_doc = new Label(m_sw_print_failed_info, ": ");
|
||||
m_st_txt_extra_info = new Label(m_sw_print_failed_info, wxEmptyString);
|
||||
st_title_extra_info->SetForegroundColour(0x909090);
|
||||
st_title_extra_info_doc->SetForegroundColour(0x909090);
|
||||
m_st_txt_extra_info->SetForegroundColour(0x909090);
|
||||
st_title_extra_info->SetFont(::Label::Body_13);
|
||||
st_title_extra_info_doc->SetFont(::Label::Body_13);
|
||||
m_st_txt_extra_info->SetFont(::Label::Body_13);
|
||||
st_title_extra_info->SetMinSize(wxSize(FromDIP(74), -1));
|
||||
st_title_extra_info->SetMaxSize(wxSize(FromDIP(74), -1));
|
||||
m_st_txt_extra_info->SetMinSize(wxSize(FromDIP(260), -1));
|
||||
m_st_txt_extra_info->SetMaxSize(wxSize(FromDIP(260), -1));
|
||||
sizer_extra_info->Add(st_title_extra_info, 0, wxALL, 0);
|
||||
sizer_extra_info->Add(st_title_extra_info_doc, 0, wxALL, 0);
|
||||
sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0);
|
||||
|
||||
sizer_print_failed_info->Add(sizer_error_code, 0, wxLEFT, 5);
|
||||
sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3));
|
||||
sizer_print_failed_info->Add(sizer_error_desc, 0, wxLEFT, 5);
|
||||
sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3));
|
||||
sizer_print_failed_info->Add(sizer_extra_info, 0, wxLEFT, 5);
|
||||
}
|
||||
|
||||
void CaliPageSendingPanel::update_print_error_info(int code, const std::string& msg, const std::string& extra)
|
||||
{
|
||||
m_print_error_code = code;
|
||||
m_print_error_msg = msg;
|
||||
m_print_error_extra = extra;
|
||||
}
|
||||
|
||||
void CaliPageSendingPanel::show_send_failed_info(bool show, int code, wxString description, wxString extra)
|
||||
{
|
||||
if (show) {
|
||||
if (!m_sw_print_failed_info->IsShown()) {
|
||||
m_sw_print_failed_info->Show(true);
|
||||
|
||||
m_st_txt_error_code->SetLabelText(wxString::Format("%d", m_print_error_code));
|
||||
m_st_txt_error_desc->SetLabelText(wxGetApp().filter_string(m_print_error_msg));
|
||||
m_st_txt_extra_info->SetLabelText(wxGetApp().filter_string(m_print_error_extra));
|
||||
|
||||
m_st_txt_error_code->Wrap(FromDIP(260));
|
||||
m_st_txt_error_desc->Wrap(FromDIP(260));
|
||||
m_st_txt_extra_info->Wrap(FromDIP(260));
|
||||
}
|
||||
else {
|
||||
m_sw_print_failed_info->Show(false);
|
||||
}
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
else {
|
||||
if (!m_sw_print_failed_info->IsShown()) { return; }
|
||||
m_sw_print_failed_info->Show(false);
|
||||
m_st_txt_error_code->SetLabelText(wxEmptyString);
|
||||
m_st_txt_error_desc->SetLabelText(wxEmptyString);
|
||||
m_st_txt_extra_info->SetLabelText(wxEmptyString);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BBLStatusBarSend> CaliPageSendingPanel::get_sending_progress_bar()
|
||||
{
|
||||
return m_send_progress_bar;
|
||||
}
|
||||
|
||||
void CaliPageSendingPanel::reset()
|
||||
{
|
||||
m_send_progress_bar->reset();
|
||||
m_sw_print_failed_info->Show(false);
|
||||
}
|
||||
|
||||
CalibrationWizardPage::CalibrationWizardPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: wxPanel(parent, id, pos, size, style)
|
||||
, m_parent(parent)
|
||||
@@ -764,6 +952,8 @@ CalibrationWizardPage::CalibrationWizardPage(wxWindow* parent, wxWindowID id, co
|
||||
|
||||
void CalibrationWizardPage::msw_rescale()
|
||||
{
|
||||
m_page_caption->msw_rescale();
|
||||
m_action_panel->msw_rescale();
|
||||
}
|
||||
|
||||
void CalibrationWizardPage::on_sys_color_changed()
|
||||
@@ -771,4 +961,5 @@ void CalibrationWizardPage::on_sys_color_changed()
|
||||
m_page_caption->on_sys_color_changed();
|
||||
}
|
||||
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ public:
|
||||
virtual bool Show(bool show = true);
|
||||
virtual bool Enable(bool enable);
|
||||
virtual void SetValue(bool value, bool send_event = true);
|
||||
void msw_rescale();
|
||||
|
||||
protected:
|
||||
int m_tray_id { -1 };
|
||||
@@ -123,6 +124,7 @@ public:
|
||||
void show_prev_btn(bool show = true);
|
||||
void show_help_icon(bool show = true);
|
||||
void on_sys_color_changed();
|
||||
void msw_rescale();
|
||||
|
||||
protected:
|
||||
ScalableButton* m_prev_btn;
|
||||
@@ -167,9 +169,12 @@ public:
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL);
|
||||
|
||||
void set_img(const wxBitmap& bmp);
|
||||
void set_bmp(const ScalableBitmap& bmp);
|
||||
void paint_on_img();
|
||||
void msw_rescale();
|
||||
|
||||
protected:
|
||||
ScalableBitmap m_bmp;
|
||||
wxStaticBitmap* m_img;
|
||||
};
|
||||
|
||||
@@ -182,12 +187,14 @@ public:
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL);
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
protected:
|
||||
void create_pop_window();
|
||||
|
||||
ScalableButton* m_help_btn;
|
||||
PopupWindow* m_pop_win;
|
||||
ScalableBitmap m_bmp;
|
||||
wxStaticBitmap* m_img;
|
||||
};
|
||||
|
||||
@@ -218,10 +225,38 @@ public:
|
||||
CaliPageButton(wxWindow* parent, CaliPageActionType type, wxString text = wxEmptyString);
|
||||
|
||||
CaliPageActionType get_action_type() { return m_action_type; }
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
private:
|
||||
CaliPageActionType m_action_type;
|
||||
};
|
||||
|
||||
class CaliPageSendingPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
CaliPageSendingPanel(wxWindow* parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL);
|
||||
void create(wxWindow* parent);
|
||||
void update_print_error_info(int code, const std::string& msg, const std::string& extra);
|
||||
void show_send_failed_info(bool show, int code = 0, wxString description = wxEmptyString, wxString extra = wxEmptyString);
|
||||
std::shared_ptr<BBLStatusBarSend> get_sending_progress_bar();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
std::shared_ptr<BBLStatusBarSend> m_send_progress_bar;
|
||||
wxScrolledWindow* m_sw_print_failed_info{ nullptr };
|
||||
Label* m_st_txt_error_code{ nullptr };
|
||||
Label* m_st_txt_error_desc{ nullptr };
|
||||
Label* m_st_txt_extra_info{ nullptr };
|
||||
int m_print_error_code;
|
||||
std::string m_print_error_msg;
|
||||
std::string m_print_error_extra;
|
||||
};
|
||||
|
||||
class CaliPageActionPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
@@ -236,6 +271,7 @@ public:
|
||||
void bind_button(CaliPageActionType action_type, bool is_block);
|
||||
void show_button(CaliPageActionType action_type, bool show = true);
|
||||
void enable_button(CaliPageActionType action_type, bool enable = true);
|
||||
void msw_rescale();
|
||||
|
||||
protected:
|
||||
std::vector<CaliPageButton*> m_action_btns;
|
||||
@@ -277,8 +313,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void msw_rescale();
|
||||
void on_sys_color_changed();
|
||||
virtual void msw_rescale();
|
||||
virtual void on_sys_color_changed();
|
||||
|
||||
protected:
|
||||
CalibMode m_cali_mode;
|
||||
|
||||
@@ -445,6 +445,22 @@ CalibrationPresetPage::CalibrationPresetPage(
|
||||
m_top_sizer->Fit(this);
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
m_ams_sync_button->msw_rescale();
|
||||
m_virtual_tray_comboBox->msw_rescale();
|
||||
for (auto& comboBox : m_filament_comboBox_list) {
|
||||
comboBox->msw_rescale();
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::on_sys_color_changed()
|
||||
{
|
||||
CalibrationWizardPage::on_sys_color_changed();
|
||||
m_ams_sync_button->msw_rescale();
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::create_selection_panel(wxWindow* parent)
|
||||
{
|
||||
auto panel_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
@@ -633,108 +649,6 @@ void CalibrationPresetPage::create_ext_spool_panel(wxWindow* parent)
|
||||
});
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::create_sending_panel(wxWindow* parent)
|
||||
{
|
||||
parent->SetMinSize({ FromDIP(475), FromDIP(200) });
|
||||
parent->SetMaxSize({ FromDIP(475), FromDIP(200) });
|
||||
|
||||
auto panel_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
parent->SetSizer(panel_sizer);
|
||||
|
||||
m_send_progress_bar = std::shared_ptr<BBLStatusBarSend>(new BBLStatusBarSend(parent));
|
||||
m_send_progress_bar->set_cancel_callback_fina([this]() {
|
||||
BOOST_LOG_TRIVIAL(info) << "CalibrationWizard::print_job: enter canceled";
|
||||
if (CalibUtils::print_job) {
|
||||
if (CalibUtils::print_job->is_running()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled";
|
||||
CalibUtils::print_job->cancel();
|
||||
}
|
||||
CalibUtils::print_job->join();
|
||||
}
|
||||
show_status(CaliPresetStatusNormal);
|
||||
});
|
||||
panel_sizer->Add(m_send_progress_bar->get_panel(), 0, wxEXPAND);
|
||||
|
||||
m_sw_print_failed_info = new wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(380), FromDIP(125)), wxVSCROLL);
|
||||
m_sw_print_failed_info->SetBackgroundColour(*wxWHITE);
|
||||
m_sw_print_failed_info->SetScrollRate(0, 5);
|
||||
m_sw_print_failed_info->SetMinSize(wxSize(FromDIP(380), FromDIP(125)));
|
||||
m_sw_print_failed_info->SetMaxSize(wxSize(FromDIP(380), FromDIP(125)));
|
||||
|
||||
m_sw_print_failed_info->Hide();
|
||||
|
||||
panel_sizer->Add(m_sw_print_failed_info, 0, wxEXPAND);
|
||||
|
||||
// create error info panel
|
||||
wxBoxSizer* sizer_print_failed_info = new wxBoxSizer(wxVERTICAL);
|
||||
m_sw_print_failed_info->SetSizer(sizer_print_failed_info);
|
||||
|
||||
wxBoxSizer* sizer_error_code = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer* sizer_extra_info = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto st_title_error_code = new Label(m_sw_print_failed_info, _L("Error code"));
|
||||
auto st_title_error_code_doc = new Label(m_sw_print_failed_info, ": ");
|
||||
m_st_txt_error_code = new Label(m_sw_print_failed_info, wxEmptyString);
|
||||
st_title_error_code->SetForegroundColour(0x909090);
|
||||
st_title_error_code_doc->SetForegroundColour(0x909090);
|
||||
m_st_txt_error_code->SetForegroundColour(0x909090);
|
||||
st_title_error_code->SetFont(::Label::Body_13);
|
||||
st_title_error_code_doc->SetFont(::Label::Body_13);
|
||||
m_st_txt_error_code->SetFont(::Label::Body_13);
|
||||
st_title_error_code->SetMinSize(wxSize(FromDIP(74), -1));
|
||||
st_title_error_code->SetMaxSize(wxSize(FromDIP(74), -1));
|
||||
m_st_txt_error_code->SetMinSize(wxSize(FromDIP(260), -1));
|
||||
m_st_txt_error_code->SetMaxSize(wxSize(FromDIP(260), -1));
|
||||
sizer_error_code->Add(st_title_error_code, 0, wxALL, 0);
|
||||
sizer_error_code->Add(st_title_error_code_doc, 0, wxALL, 0);
|
||||
sizer_error_code->Add(m_st_txt_error_code, 0, wxALL, 0);
|
||||
|
||||
auto st_title_error_desc = new Label(m_sw_print_failed_info, _L("Error desc"));
|
||||
auto st_title_error_desc_doc = new Label(m_sw_print_failed_info, ": ");
|
||||
m_st_txt_error_desc = new Label(m_sw_print_failed_info, wxEmptyString);
|
||||
st_title_error_desc->SetForegroundColour(0x909090);
|
||||
st_title_error_desc_doc->SetForegroundColour(0x909090);
|
||||
m_st_txt_error_desc->SetForegroundColour(0x909090);
|
||||
st_title_error_desc->SetFont(::Label::Body_13);
|
||||
st_title_error_desc_doc->SetFont(::Label::Body_13);
|
||||
m_st_txt_error_desc->SetFont(::Label::Body_13);
|
||||
st_title_error_desc->SetMinSize(wxSize(FromDIP(74), -1));
|
||||
st_title_error_desc->SetMaxSize(wxSize(FromDIP(74), -1));
|
||||
m_st_txt_error_desc->SetMinSize(wxSize(FromDIP(260), -1));
|
||||
m_st_txt_error_desc->SetMaxSize(wxSize(FromDIP(260), -1));
|
||||
sizer_error_desc->Add(st_title_error_desc, 0, wxALL, 0);
|
||||
sizer_error_desc->Add(st_title_error_desc_doc, 0, wxALL, 0);
|
||||
sizer_error_desc->Add(m_st_txt_error_desc, 0, wxALL, 0);
|
||||
|
||||
auto st_title_extra_info = new Label(m_sw_print_failed_info, _L("Extra info"));
|
||||
auto st_title_extra_info_doc = new Label(m_sw_print_failed_info, ": ");
|
||||
m_st_txt_extra_info = new Label(m_sw_print_failed_info, wxEmptyString);
|
||||
st_title_extra_info->SetForegroundColour(0x909090);
|
||||
st_title_extra_info_doc->SetForegroundColour(0x909090);
|
||||
m_st_txt_extra_info->SetForegroundColour(0x909090);
|
||||
st_title_extra_info->SetFont(::Label::Body_13);
|
||||
st_title_extra_info_doc->SetFont(::Label::Body_13);
|
||||
m_st_txt_extra_info->SetFont(::Label::Body_13);
|
||||
st_title_extra_info->SetMinSize(wxSize(FromDIP(74), -1));
|
||||
st_title_extra_info->SetMaxSize(wxSize(FromDIP(74), -1));
|
||||
m_st_txt_extra_info->SetMinSize(wxSize(FromDIP(260), -1));
|
||||
m_st_txt_extra_info->SetMaxSize(wxSize(FromDIP(260), -1));
|
||||
sizer_extra_info->Add(st_title_extra_info, 0, wxALL, 0);
|
||||
sizer_extra_info->Add(st_title_extra_info_doc, 0, wxALL, 0);
|
||||
sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0);
|
||||
|
||||
sizer_print_failed_info->Add(sizer_error_code, 0, wxLEFT, 5);
|
||||
sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3));
|
||||
sizer_print_failed_info->Add(sizer_error_desc, 0, wxLEFT, 5);
|
||||
sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3));
|
||||
sizer_print_failed_info->Add(sizer_extra_info, 0, wxLEFT, 5);
|
||||
|
||||
Bind(EVT_SHOW_ERROR_INFO, [this](auto& e) {
|
||||
show_send_failed_info(true);
|
||||
});
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::create_page(wxWindow* parent)
|
||||
{
|
||||
m_page_caption = new CaliPageCaption(parent, m_cali_mode);
|
||||
@@ -788,10 +702,10 @@ void CalibrationPresetPage::create_page(wxWindow* parent)
|
||||
|
||||
m_tips_panel = new CaliPresetTipsPanel(parent);
|
||||
|
||||
m_sending_panel = new wxPanel(parent);
|
||||
m_sending_panel->SetBackgroundColour(*wxWHITE);
|
||||
create_sending_panel(m_sending_panel);
|
||||
|
||||
m_sending_panel = new CaliPageSendingPanel(parent);
|
||||
m_sending_panel->get_sending_progress_bar()->set_cancel_callback_fina([this]() {
|
||||
on_cali_cancel_job();
|
||||
});
|
||||
m_sending_panel->Hide();
|
||||
|
||||
m_custom_range_panel = new CaliPresetCustomRangePanel(parent);
|
||||
@@ -1038,8 +952,10 @@ bool CalibrationPresetPage::is_filament_in_blacklist(Preset* preset, std::string
|
||||
std::string filamnt_type;
|
||||
preset->get_filament_type(filamnt_type);
|
||||
|
||||
if (preset->vendor) {
|
||||
DeviceManager::check_filaments_in_blacklist(preset->vendor->name, filamnt_type, in_blacklist, action, info);
|
||||
auto vendor = dynamic_cast<ConfigOptionStrings*> (preset->config.option("filament_vendor"));
|
||||
if (vendor && (vendor->values.size() > 0)) {
|
||||
std::string vendor_name = vendor->values[0];
|
||||
DeviceManager::check_filaments_in_blacklist(vendor_name, filamnt_type, in_blacklist, action, info);
|
||||
}
|
||||
|
||||
if (in_blacklist) {
|
||||
@@ -1189,12 +1105,6 @@ bool CalibrationPresetPage::is_blocking_printing()
|
||||
|
||||
void CalibrationPresetPage::update_show_status()
|
||||
{
|
||||
if (get_status() == CaliPresetPageStatus::CaliPresetStatusSending)
|
||||
return;
|
||||
|
||||
if (get_status() == CaliPresetPageStatus::CaliPresetStatusSendingCanceled)
|
||||
return;
|
||||
|
||||
NetworkAgent* agent = Slic3r::GUI::wxGetApp().getAgent();
|
||||
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
if (!agent) {return;}
|
||||
@@ -1307,12 +1217,8 @@ bool CalibrationPresetPage::need_check_sdcard(MachineObject* obj)
|
||||
|
||||
void CalibrationPresetPage::show_status(CaliPresetPageStatus status)
|
||||
{
|
||||
if (status == CaliPresetPageStatus::CaliPresetStatusSending) {
|
||||
sending_mode();
|
||||
}
|
||||
else {
|
||||
prepare_mode();
|
||||
}
|
||||
if (m_stop_update_page_status)
|
||||
return;
|
||||
|
||||
if (m_page_status != status)
|
||||
//BOOST_LOG_TRIVIAL(info) << "CalibrationPresetPage: show_status = " << status << "(" << get_print_status_info(status) << ")";
|
||||
@@ -1324,7 +1230,6 @@ void CalibrationPresetPage::show_status(CaliPresetPageStatus status)
|
||||
Enable_Send_Button(false);
|
||||
}
|
||||
else if (status == CaliPresetPageStatus::CaliPresetStatusNormal) {
|
||||
m_sending_panel->Show(false);
|
||||
update_print_status_msg(wxEmptyString, false);
|
||||
Enable_Send_Button(true);
|
||||
Layout();
|
||||
@@ -1359,15 +1264,6 @@ void CalibrationPresetPage::show_status(CaliPresetPageStatus status)
|
||||
update_print_status_msg(msg_text, true);
|
||||
Enable_Send_Button(false);
|
||||
}
|
||||
else if (status == CaliPresetPageStatus::CaliPresetStatusSending) {
|
||||
m_sending_panel->Show();
|
||||
Enable_Send_Button(false);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
else if (status == CaliPresetPageStatus::CaliPresetStatusSendingCanceled) {
|
||||
Enable_Send_Button(true);
|
||||
}
|
||||
else if (status == CaliPresetPageStatus::CaliPresetStatusLanModeNoSdcard) {
|
||||
wxString msg_text = _L("An SD card needs to be inserted before printing via LAN.");
|
||||
update_print_status_msg(msg_text, true);
|
||||
@@ -1406,19 +1302,6 @@ void CalibrationPresetPage::Enable_Send_Button(bool enable)
|
||||
m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_CALI, enable);
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::prepare_mode()
|
||||
{
|
||||
Enable_Send_Button(true);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, true);
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::sending_mode()
|
||||
{
|
||||
Enable_Send_Button(false);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, false);
|
||||
}
|
||||
|
||||
|
||||
float CalibrationPresetPage::get_nozzle_value()
|
||||
{
|
||||
double nozzle_value = 0.0;
|
||||
@@ -1448,44 +1331,6 @@ void CalibrationPresetPage::on_device_connected(MachineObject* obj)
|
||||
update_combobox_filaments(obj);
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::update_print_error_info(int code, const std::string& msg, const std::string& extra)
|
||||
{
|
||||
m_print_error_code = code;
|
||||
m_print_error_msg = msg;
|
||||
m_print_error_extra = extra;
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::show_send_failed_info(bool show, int code, wxString description, wxString extra)
|
||||
{
|
||||
if (show) {
|
||||
if (!m_sw_print_failed_info->IsShown()) {
|
||||
m_sw_print_failed_info->Show(true);
|
||||
|
||||
m_st_txt_error_code->SetLabelText(wxString::Format("%d", m_print_error_code));
|
||||
m_st_txt_error_desc->SetLabelText(wxGetApp().filter_string(m_print_error_msg));
|
||||
m_st_txt_extra_info->SetLabelText(wxGetApp().filter_string(m_print_error_extra));
|
||||
|
||||
m_st_txt_error_code->Wrap(FromDIP(260));
|
||||
m_st_txt_error_desc->Wrap(FromDIP(260));
|
||||
m_st_txt_extra_info->Wrap(FromDIP(260));
|
||||
}
|
||||
else {
|
||||
m_sw_print_failed_info->Show(false);
|
||||
}
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
else {
|
||||
if (!m_sw_print_failed_info->IsShown()) { return; }
|
||||
m_sw_print_failed_info->Show(false);
|
||||
m_st_txt_error_code->SetLabelText(wxEmptyString);
|
||||
m_st_txt_error_desc->SetLabelText(wxEmptyString);
|
||||
m_st_txt_extra_info->SetLabelText(wxEmptyString);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::set_cali_filament_mode(CalibrationFilamentMode mode)
|
||||
{
|
||||
CalibrationWizardPage::set_cali_filament_mode(mode);
|
||||
@@ -1539,9 +1384,9 @@ void CalibrationPresetPage::set_cali_method(CalibrationMethod method)
|
||||
|
||||
wxArrayString values;
|
||||
values.push_back(_L("0"));
|
||||
values.push_back(_L("0.5"));
|
||||
values.push_back(_L("0.5"));
|
||||
values.push_back(_L("0.005"));
|
||||
m_custom_range_panel->set_values(values);
|
||||
m_custom_range_panel->set_values(values);
|
||||
|
||||
m_custom_range_panel->set_unit("");
|
||||
m_custom_range_panel->Show();
|
||||
@@ -1566,14 +1411,49 @@ void CalibrationPresetPage::set_cali_method(CalibrationMethod method)
|
||||
|
||||
void CalibrationPresetPage::on_cali_start_job()
|
||||
{
|
||||
m_send_progress_bar->reset();
|
||||
m_sw_print_failed_info->Show(false);
|
||||
show_status(CaliPresetPageStatus::CaliPresetStatusSending);
|
||||
m_sending_panel->reset();
|
||||
m_sending_panel->Show();
|
||||
Enable_Send_Button(false);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, false);
|
||||
Layout();
|
||||
Fit();
|
||||
|
||||
m_stop_update_page_status = true;
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::on_cali_finished_job()
|
||||
{
|
||||
show_status(CaliPresetPageStatus::CaliPresetStatusNormal);
|
||||
m_sending_panel->reset();
|
||||
m_sending_panel->Show(false);
|
||||
update_print_status_msg(wxEmptyString, false);
|
||||
Enable_Send_Button(true);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, true);
|
||||
Layout();
|
||||
Fit();
|
||||
|
||||
m_stop_update_page_status = false;
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::on_cali_cancel_job()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "CalibrationWizard::print_job: enter canceled";
|
||||
if (CalibUtils::print_job) {
|
||||
if (CalibUtils::print_job->is_running()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled";
|
||||
CalibUtils::print_job->cancel();
|
||||
}
|
||||
CalibUtils::print_job->join();
|
||||
}
|
||||
|
||||
m_sending_panel->reset();
|
||||
m_sending_panel->Show(false);
|
||||
update_print_status_msg(wxEmptyString, false);
|
||||
Enable_Send_Button(true);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, true);
|
||||
Layout();
|
||||
Fit();
|
||||
|
||||
m_stop_update_page_status = false;
|
||||
}
|
||||
|
||||
void CalibrationPresetPage::init_with_machine(MachineObject* obj)
|
||||
@@ -1986,7 +1866,7 @@ MaxVolumetricSpeedPresetPage::MaxVolumetricSpeedPresetPage(
|
||||
wxArrayString titles;
|
||||
titles.push_back(_L("From Volumetric Speed"));
|
||||
titles.push_back(_L("To Volumetric Speed"));
|
||||
titles.push_back(_L("Step value"));
|
||||
titles.push_back(_L("Step"));
|
||||
m_custom_range_panel->set_titles(titles);
|
||||
|
||||
m_custom_range_panel->set_unit(_L("mm\u00B3/s"));
|
||||
|
||||
@@ -129,14 +129,12 @@ enum CaliPresetPageStatus
|
||||
{
|
||||
CaliPresetStatusInit = 0,
|
||||
CaliPresetStatusNormal,
|
||||
CaliPresetStatusSending,
|
||||
CaliPresetStatusNoUserLogin,
|
||||
CaliPresetStatusInvalidPrinter,
|
||||
CaliPresetStatusConnectingServer,
|
||||
CaliPresetStatusInUpgrading,
|
||||
CaliPresetStatusInSystemPrinting,
|
||||
CaliPresetStatusInPrinting,
|
||||
CaliPresetStatusSendingCanceled,
|
||||
CaliPresetStatusLanModeNoSdcard,
|
||||
CaliPresetStatusNoSdcard,
|
||||
CaliPresetStatusNeedForceUpgrading,
|
||||
@@ -167,9 +165,7 @@ public:
|
||||
|
||||
void on_device_connected(MachineObject* obj) override;
|
||||
|
||||
void update_print_error_info(int code, const std::string& msg, const std::string& extra);
|
||||
|
||||
void show_send_failed_info(bool show, int code = 0, wxString description = wxEmptyString, wxString extra = wxEmptyString);
|
||||
void update_print_error_info(int code, const std::string& msg, const std::string& extra) { m_sending_panel->update_print_error_info(code, msg, extra); }
|
||||
|
||||
void set_cali_filament_mode(CalibrationFilamentMode mode) override;
|
||||
|
||||
@@ -179,6 +175,8 @@ public:
|
||||
|
||||
void on_cali_finished_job();
|
||||
|
||||
void on_cali_cancel_job();
|
||||
|
||||
void init_with_machine(MachineObject* obj);
|
||||
|
||||
void sync_ams_info(MachineObject* obj);
|
||||
@@ -197,7 +195,7 @@ public:
|
||||
void get_cali_stage(CaliPresetStage& stage, float& value);
|
||||
|
||||
std::shared_ptr<ProgressIndicator> get_sending_progress_bar() {
|
||||
return m_send_progress_bar;
|
||||
return m_sending_panel->get_sending_progress_bar();
|
||||
}
|
||||
|
||||
Preset* get_printer_preset(MachineObject* obj, float nozzle_value);
|
||||
@@ -208,11 +206,14 @@ public:
|
||||
CalibMode get_pa_cali_method();
|
||||
|
||||
CaliPresetPageStatus get_page_status() { return m_page_status; }
|
||||
|
||||
void msw_rescale() override;
|
||||
void on_sys_color_changed() override;
|
||||
|
||||
protected:
|
||||
void create_selection_panel(wxWindow* parent);
|
||||
void create_filament_list_panel(wxWindow* parent);
|
||||
void create_ext_spool_panel(wxWindow* parent);
|
||||
void create_sending_panel(wxWindow* parent);
|
||||
|
||||
void init_selection_values();
|
||||
void update_filament_combobox(std::string ams_id = "");
|
||||
@@ -244,8 +245,6 @@ protected:
|
||||
void update_show_status();
|
||||
void show_status(CaliPresetPageStatus status);
|
||||
void Enable_Send_Button(bool enable);
|
||||
void prepare_mode();
|
||||
void sending_mode();
|
||||
bool is_blocking_printing();
|
||||
bool need_check_sdcard(MachineObject* obj);
|
||||
|
||||
@@ -263,7 +262,7 @@ protected:
|
||||
CaliPresetWarningPanel* m_warning_panel { nullptr };
|
||||
CaliPresetCustomRangePanel* m_custom_range_panel { nullptr };
|
||||
CaliPresetTipsPanel* m_tips_panel { nullptr };
|
||||
wxPanel* m_sending_panel { nullptr };
|
||||
CaliPageSendingPanel* m_sending_panel { nullptr };
|
||||
|
||||
wxBoxSizer* m_top_sizer;
|
||||
|
||||
@@ -279,15 +278,6 @@ protected:
|
||||
FilamentComboBoxList m_filament_comboBox_list;
|
||||
FilamentComboBox* m_virtual_tray_comboBox;
|
||||
|
||||
// m_sending panel widgets
|
||||
std::shared_ptr<BBLStatusBarSend> m_send_progress_bar;
|
||||
wxScrolledWindow* m_sw_print_failed_info { nullptr };
|
||||
Label* m_st_txt_error_code { nullptr };
|
||||
Label* m_st_txt_error_desc { nullptr };
|
||||
Label* m_st_txt_extra_info { nullptr };
|
||||
int m_print_error_code;
|
||||
std::string m_print_error_msg;
|
||||
std::string m_print_error_extra;
|
||||
|
||||
std::vector<AMSItem*> m_ams_item_list;
|
||||
|
||||
@@ -295,6 +285,7 @@ protected:
|
||||
std::map<int, DynamicPrintConfig> filament_ams_list;
|
||||
|
||||
CaliPresetPageStatus m_page_status { CaliPresetPageStatus::CaliPresetStatusInit };
|
||||
bool m_stop_update_page_status{ false };
|
||||
|
||||
bool m_show_custom_range { false };
|
||||
bool m_has_filament_incompatible { false };
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Slic3r { namespace GUI {
|
||||
|
||||
#define CALIBRATION_SAVE_INPUT_SIZE wxSize(FromDIP(240), FromDIP(24))
|
||||
#define FLOW_RATE_MAX_VALUE 1.15
|
||||
static const wxString k_tips = "Please input a valid value (K in 0~0.3)";
|
||||
|
||||
static wxString get_default_name(wxString filament_name, CalibMode mode){
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
@@ -363,10 +364,11 @@ void CaliPASaveAutoPanel::save_to_result_from_widgets(wxWindow* window, bool* ou
|
||||
if (input->get_type() == GridTextInputType::K) {
|
||||
float k = 0.0f;
|
||||
if (!CalibUtils::validate_input_k_value(input->GetTextCtrl()->GetValue(), &k)) {
|
||||
*out_msg = _L("Please input a valid value (K in 0~0.5)");
|
||||
*out_msg = _L("Please input a valid value (K in 0~0.3)");
|
||||
*out_is_valid = false;
|
||||
}
|
||||
m_calib_results[tray_id].k_value = k;
|
||||
else
|
||||
m_calib_results[tray_id].k_value = k;
|
||||
}
|
||||
else if (input->get_type() == GridTextInputType::N) {
|
||||
}
|
||||
@@ -517,9 +519,9 @@ void CaliPASaveManualPanel::create_panel(wxWindow* parent)
|
||||
|
||||
void CaliPASaveManualPanel::set_save_img() {
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result_CN", nullptr, 330));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result_CN", 330));
|
||||
} else {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result", nullptr, 330));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result", 330));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,9 +533,9 @@ void CaliPASaveManualPanel::set_pa_cali_method(ManualPaCaliMethod method)
|
||||
} else if (method == ManualPaCaliMethod::PA_PATTERN) {
|
||||
m_complete_text->SetLabel(_L("Please find the cornor with perfect degree of extrusion"));
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result_CN", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result_CN", 350));
|
||||
} else {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result", 350));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,7 +548,7 @@ bool CaliPASaveManualPanel::get_result(PACalibResult& out_result) {
|
||||
// Check if the value is valid
|
||||
float k;
|
||||
if (!CalibUtils::validate_input_k_value(m_k_val->GetTextCtrl()->GetValue(), &k)) {
|
||||
MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
MessageDialog msg_dlg(nullptr, _L(k_tips), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return false;
|
||||
}
|
||||
@@ -593,6 +595,8 @@ bool CaliPASaveManualPanel::Show(bool show) {
|
||||
if (!m_obj->selected_cali_preset.empty()) {
|
||||
wxString default_name = get_default_name(m_obj->selected_cali_preset[0].name, CalibMode::Calib_PA_Line);
|
||||
set_default_name(default_name);
|
||||
m_k_val->GetTextCtrl()->SetLabel("");
|
||||
m_n_val->GetTextCtrl()->SetLabel("");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -602,6 +606,11 @@ bool CaliPASaveManualPanel::Show(bool show) {
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void CaliPASaveManualPanel::msw_rescale()
|
||||
{
|
||||
m_picture_panel->msw_rescale();
|
||||
}
|
||||
|
||||
CaliPASaveP1PPanel::CaliPASaveP1PPanel(
|
||||
wxWindow* parent,
|
||||
wxWindowID id,
|
||||
@@ -671,9 +680,9 @@ void CaliPASaveP1PPanel::create_panel(wxWindow* parent)
|
||||
|
||||
void CaliPASaveP1PPanel::set_save_img() {
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result_CN", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result_CN", 350));
|
||||
} else {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result", 350));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,9 +695,9 @@ void CaliPASaveP1PPanel::set_pa_cali_method(ManualPaCaliMethod method)
|
||||
else if (method == ManualPaCaliMethod::PA_PATTERN) {
|
||||
m_complete_text->SetLabel(_L("Please find the cornor with perfect degree of extrusion"));
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result_CN", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result_CN", 350));
|
||||
} else {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result", 350));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -696,13 +705,26 @@ void CaliPASaveP1PPanel::set_pa_cali_method(ManualPaCaliMethod method)
|
||||
bool CaliPASaveP1PPanel::get_result(float* out_k, float* out_n){
|
||||
// Check if the value is valid
|
||||
if (!CalibUtils::validate_input_k_value(m_k_val->GetTextCtrl()->GetValue(), out_k)) {
|
||||
MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
MessageDialog msg_dlg(nullptr, _L(k_tips), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CaliPASaveP1PPanel::Show(bool show) {
|
||||
if (show) {
|
||||
m_k_val->GetTextCtrl()->SetLabel("");
|
||||
m_n_val->GetTextCtrl()->SetLabel("");
|
||||
}
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void CaliPASaveP1PPanel::msw_rescale()
|
||||
{
|
||||
m_picture_panel->msw_rescale();
|
||||
}
|
||||
|
||||
CaliSavePresetValuePanel::CaliSavePresetValuePanel(
|
||||
wxWindow *parent,
|
||||
wxWindowID id,
|
||||
@@ -751,7 +773,7 @@ void CaliSavePresetValuePanel::create_panel(wxWindow *parent)
|
||||
|
||||
void CaliSavePresetValuePanel::set_img(const std::string& bmp_name_in)
|
||||
{
|
||||
m_picture_panel->set_img(create_scaled_bitmap(bmp_name_in, nullptr, 400));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, bmp_name_in, 400));
|
||||
}
|
||||
|
||||
void CaliSavePresetValuePanel::set_value_title(const wxString& title) {
|
||||
@@ -777,6 +799,11 @@ void CaliSavePresetValuePanel::set_save_name(const std::string& name)
|
||||
m_input_name->GetTextCtrl()->SetValue(name);
|
||||
}
|
||||
|
||||
void CaliSavePresetValuePanel::msw_rescale()
|
||||
{
|
||||
m_picture_panel->msw_rescale();
|
||||
}
|
||||
|
||||
CalibrationPASavePage::CalibrationPASavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: CalibrationCommonSavePage(parent, id, pos, size, style)
|
||||
{
|
||||
@@ -875,6 +902,8 @@ void CalibrationPASavePage::set_cali_method(CalibrationMethod method)
|
||||
void CalibrationPASavePage::on_device_connected(MachineObject* obj)
|
||||
{
|
||||
curr_obj = obj;
|
||||
m_auto_panel->set_machine_obj(curr_obj);
|
||||
m_manual_panel->set_machine_obj(curr_obj);
|
||||
if (curr_obj)
|
||||
show_panels(m_cali_method, curr_obj->get_printer_series());
|
||||
}
|
||||
@@ -899,6 +928,14 @@ bool CalibrationPASavePage::Show(bool show) {
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void CalibrationPASavePage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
m_manual_panel->msw_rescale();
|
||||
m_p1p_panel->msw_rescale();
|
||||
m_help_panel->msw_rescale();
|
||||
}
|
||||
|
||||
CalibrationFlowX1SavePage::CalibrationFlowX1SavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: CalibrationCommonSavePage(parent, id, pos, size, style)
|
||||
{
|
||||
@@ -1138,6 +1175,11 @@ bool CalibrationFlowX1SavePage::Show(bool show) {
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void CalibrationFlowX1SavePage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
}
|
||||
|
||||
CalibrationFlowCoarseSavePage::CalibrationFlowCoarseSavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: CalibrationCommonSavePage(parent, id, pos, size, style)
|
||||
{
|
||||
@@ -1258,6 +1300,13 @@ void CalibrationFlowCoarseSavePage::create_page(wxWindow* parent)
|
||||
m_coarse_calc_result_text->SetLabel(wxString::Format(_L("flow ratio : %s "), std::to_string(m_coarse_flow_ratio)));
|
||||
});
|
||||
|
||||
m_sending_panel = new CaliPageSendingPanel(parent);
|
||||
m_sending_panel->get_sending_progress_bar()->set_cancel_callback_fina([this]() {
|
||||
on_cali_cancel_job();
|
||||
});
|
||||
m_sending_panel->Hide();
|
||||
m_top_sizer->Add(m_sending_panel, 0, wxALIGN_CENTER);
|
||||
|
||||
m_action_panel = new CaliPageActionPanel(parent, m_cali_mode, CaliPageType::CALI_PAGE_COARSE_SAVE);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_COARSE_SAVE, false);
|
||||
m_top_sizer->Add(m_action_panel, 0, wxEXPAND, 0);
|
||||
@@ -1265,9 +1314,9 @@ void CalibrationFlowCoarseSavePage::create_page(wxWindow* parent)
|
||||
|
||||
void CalibrationFlowCoarseSavePage::set_save_img() {
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse_result_CN", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse_result_CN", 350));
|
||||
} else {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse_result", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse_result", 350));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1324,6 +1373,51 @@ bool CalibrationFlowCoarseSavePage::Show(bool show) {
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void CalibrationFlowCoarseSavePage::on_cali_start_job()
|
||||
{
|
||||
m_sending_panel->reset();
|
||||
m_sending_panel->Show();
|
||||
m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, false);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, false);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
void CalibrationFlowCoarseSavePage::on_cali_finished_job()
|
||||
{
|
||||
m_sending_panel->reset();
|
||||
m_sending_panel->Show(false);
|
||||
m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
void CalibrationFlowCoarseSavePage::on_cali_cancel_job()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "CalibrationWizard::print_job: enter canceled";
|
||||
if (CalibUtils::print_job) {
|
||||
if (CalibUtils::print_job->is_running()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled";
|
||||
CalibUtils::print_job->cancel();
|
||||
}
|
||||
CalibUtils::print_job->join();
|
||||
}
|
||||
|
||||
m_sending_panel->reset();
|
||||
m_sending_panel->Show(false);
|
||||
m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true);
|
||||
m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
void CalibrationFlowCoarseSavePage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
m_picture_panel->msw_rescale();
|
||||
}
|
||||
|
||||
CalibrationFlowFineSavePage::CalibrationFlowFineSavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: CalibrationCommonSavePage(parent, id, pos, size, style)
|
||||
{
|
||||
@@ -1406,9 +1500,9 @@ void CalibrationFlowFineSavePage::create_page(wxWindow* parent)
|
||||
|
||||
void CalibrationFlowFineSavePage::set_save_img() {
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_fine_result_CN", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine_result_CN", 350));
|
||||
} else {
|
||||
m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_fine_result", nullptr, 350));
|
||||
m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine_result", 350));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1456,6 +1550,12 @@ bool CalibrationFlowFineSavePage::Show(bool show) {
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void CalibrationFlowFineSavePage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
m_picture_panel->msw_rescale();
|
||||
}
|
||||
|
||||
CalibrationMaxVolumetricSpeedSavePage::CalibrationMaxVolumetricSpeedSavePage(
|
||||
wxWindow *parent,
|
||||
wxWindowID id,
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
void get_value(double& value);
|
||||
void get_save_name(std::string& name);
|
||||
void set_save_name(const std::string& name);
|
||||
void msw_rescale();
|
||||
};
|
||||
|
||||
|
||||
@@ -129,6 +130,8 @@ public:
|
||||
|
||||
virtual bool Show(bool show = true) override;
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
protected:
|
||||
wxBoxSizer* m_top_sizer;
|
||||
Label * m_complete_text;
|
||||
@@ -155,6 +158,10 @@ public:
|
||||
|
||||
bool get_result(float* out_k, float* out_n);
|
||||
|
||||
virtual bool Show(bool show = true) override;
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
protected:
|
||||
wxBoxSizer* m_top_sizer;
|
||||
Label * m_complete_text;
|
||||
@@ -185,12 +192,14 @@ public:
|
||||
|
||||
virtual bool Show(bool show = true) override;
|
||||
|
||||
void msw_rescale() override;
|
||||
|
||||
protected:
|
||||
CaliPageStepGuide* m_step_panel { nullptr };
|
||||
CaliPASaveAutoPanel* m_auto_panel { nullptr };
|
||||
CaliPASaveManualPanel* m_manual_panel { nullptr };
|
||||
CaliPASaveP1PPanel* m_p1p_panel{ nullptr };
|
||||
PAPageHelpPanel* m_help_panel;
|
||||
PAPageHelpPanel* m_help_panel{ nullptr };
|
||||
|
||||
CaliSaveStyle m_save_style;
|
||||
};
|
||||
@@ -209,6 +218,8 @@ public:
|
||||
bool is_all_failed() { return m_is_all_failed; }
|
||||
|
||||
virtual bool Show(bool show = true) override;
|
||||
|
||||
void msw_rescale() override;
|
||||
|
||||
protected:
|
||||
CaliPageStepGuide* m_step_panel{ nullptr };
|
||||
@@ -237,6 +248,20 @@ public:
|
||||
|
||||
virtual bool Show(bool show = true) override;
|
||||
|
||||
void update_print_error_info(int code, const std::string& msg, const std::string& extra) { m_sending_panel->update_print_error_info(code, msg, extra); }
|
||||
|
||||
void on_cali_start_job();
|
||||
|
||||
void on_cali_finished_job();
|
||||
|
||||
void on_cali_cancel_job();
|
||||
|
||||
std::shared_ptr<ProgressIndicator> get_sending_progress_bar() {
|
||||
return m_sending_panel->get_sending_progress_bar();
|
||||
}
|
||||
|
||||
void msw_rescale() override;
|
||||
|
||||
protected:
|
||||
CaliPageStepGuide* m_step_panel{ nullptr };
|
||||
CaliPagePicture* m_picture_panel;
|
||||
@@ -249,6 +274,8 @@ protected:
|
||||
bool m_skip_fine_calibration = false;
|
||||
float m_curr_flow_ratio;
|
||||
float m_coarse_flow_ratio;
|
||||
|
||||
CaliPageSendingPanel* m_sending_panel{ nullptr };
|
||||
};
|
||||
|
||||
class CalibrationFlowFineSavePage : public CalibrationCommonSavePage
|
||||
@@ -267,6 +294,8 @@ public:
|
||||
|
||||
virtual bool Show(bool show = true) override;
|
||||
|
||||
void msw_rescale() override;
|
||||
|
||||
protected:
|
||||
CaliPageStepGuide* m_step_panel{ nullptr };
|
||||
CaliPagePicture* m_picture_panel;
|
||||
|
||||
@@ -35,30 +35,37 @@ void CalibrationStartPage::create_about(wxWindow* parent, wxString title, wxStri
|
||||
|
||||
void CalibrationStartPage::create_bitmap(wxWindow* parent, const wxBitmap& before_img, const wxBitmap& after_img)
|
||||
{
|
||||
m_images_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_before_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0);
|
||||
if (!m_before_bmp)
|
||||
m_before_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_before_bmp->SetBitmap(before_img);
|
||||
m_images_sizer->Add(m_before_bmp, 0, wxALL, 0);
|
||||
m_images_sizer->AddSpacer(FromDIP(20));
|
||||
m_after_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0);
|
||||
if (!m_after_bmp)
|
||||
m_after_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_after_bmp->SetBitmap(after_img);
|
||||
m_images_sizer->Add(m_after_bmp, 0, wxALL, 0);
|
||||
if (!m_images_sizer) {
|
||||
m_images_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_images_sizer->Add(m_before_bmp, 0, wxALL, 0);
|
||||
m_images_sizer->AddSpacer(FromDIP(20));
|
||||
m_images_sizer->Add(m_after_bmp, 0, wxALL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationStartPage::create_bitmap(wxWindow* parent, std::string before_img, std::string after_img)
|
||||
{
|
||||
wxBitmap before_bmp = create_scaled_bitmap(before_img, nullptr, 350);
|
||||
wxBitmap after_bmp = create_scaled_bitmap(after_img, nullptr, 350);
|
||||
wxBitmap before_bmp = create_scaled_bitmap(before_img, this, 350);
|
||||
wxBitmap after_bmp = create_scaled_bitmap(after_img, this, 350);
|
||||
|
||||
create_bitmap(parent, before_bmp, after_bmp);
|
||||
}
|
||||
|
||||
void CalibrationStartPage::create_bitmap(wxWindow* parent, std::string img) {
|
||||
wxBitmap before_bmp = create_scaled_bitmap(img, nullptr, 350);
|
||||
m_images_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_bmp_intro = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0);
|
||||
wxBitmap before_bmp = create_scaled_bitmap(img, this, 350);
|
||||
if (!m_bmp_intro)
|
||||
m_bmp_intro = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_bmp_intro->SetBitmap(before_bmp);
|
||||
m_images_sizer->Add(m_bmp_intro, 0, wxALL, 0);
|
||||
if (!m_images_sizer) {
|
||||
m_images_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_images_sizer->Add(m_bmp_intro, 0, wxALL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
CalibrationPAStartPage::CalibrationPAStartPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
@@ -97,7 +104,7 @@ void CalibrationPAStartPage::create_page(wxWindow* parent)
|
||||
m_top_sizer->Add(m_images_sizer, 0, wxALL, 0);
|
||||
m_top_sizer->AddSpacer(PRESET_GAP);
|
||||
|
||||
PAPageHelpPanel* m_help_panel = new PAPageHelpPanel(parent, false);
|
||||
m_help_panel = new PAPageHelpPanel(parent, false);
|
||||
m_top_sizer->Add(m_help_panel, 0, wxALL, 0);
|
||||
m_top_sizer->AddSpacer(PRESET_GAP);
|
||||
|
||||
@@ -169,6 +176,17 @@ void CalibrationPAStartPage::on_device_connected(MachineObject* obj)
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationPAStartPage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
m_help_panel->msw_rescale();
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
create_bitmap(this, "cali_page_before_pa_CN", "cali_page_after_pa_CN");
|
||||
} else {
|
||||
create_bitmap(this, "cali_page_before_pa", "cali_page_after_pa");
|
||||
}
|
||||
}
|
||||
|
||||
CalibrationFlowRateStartPage::CalibrationFlowRateStartPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: CalibrationStartPage(parent, id, pos, size, style)
|
||||
{
|
||||
@@ -291,6 +309,16 @@ void CalibrationFlowRateStartPage::on_device_connected(MachineObject* obj)
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationFlowRateStartPage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
create_bitmap(this, "cali_page_flow_introduction_CN");
|
||||
} else {
|
||||
create_bitmap(this, "cali_page_flow_introduction");
|
||||
}
|
||||
}
|
||||
|
||||
CalibrationMaxVolumetricSpeedStartPage::CalibrationMaxVolumetricSpeedStartPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: CalibrationStartPage(parent, id, pos, size, style)
|
||||
{
|
||||
@@ -343,4 +371,14 @@ void CalibrationMaxVolumetricSpeedStartPage::create_page(wxWindow* parent)
|
||||
m_top_sizer->Add(m_action_panel, 0, wxEXPAND, 0);
|
||||
}
|
||||
|
||||
void CalibrationMaxVolumetricSpeedStartPage::msw_rescale()
|
||||
{
|
||||
CalibrationWizardPage::msw_rescale();
|
||||
if (wxGetApp().app_config->get_language_code() == "zh-cn") {
|
||||
create_bitmap(this, "cali_page_before_pa_CN", "cali_page_after_pa_CN");
|
||||
} else {
|
||||
create_bitmap(this, "cali_page_before_pa", "cali_page_after_pa");
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -19,15 +19,16 @@ public:
|
||||
protected:
|
||||
CalibMode m_cali_mode;
|
||||
|
||||
wxBoxSizer* m_top_sizer;
|
||||
wxBoxSizer* m_images_sizer;
|
||||
Label* m_when_title;
|
||||
Label* m_when_content;
|
||||
Label* m_about_title;
|
||||
Label* m_about_content;
|
||||
wxBoxSizer* m_top_sizer{ nullptr };
|
||||
wxBoxSizer* m_images_sizer{ nullptr };
|
||||
Label* m_when_title{ nullptr };
|
||||
Label* m_when_content{ nullptr };
|
||||
Label* m_about_title{ nullptr };
|
||||
Label* m_about_content{ nullptr };
|
||||
wxStaticBitmap* m_before_bmp{ nullptr };
|
||||
wxStaticBitmap* m_after_bmp{ nullptr };
|
||||
wxStaticBitmap* m_bmp_intro{ nullptr };
|
||||
PAPageHelpPanel* m_help_panel{ nullptr };
|
||||
|
||||
void create_when(wxWindow* parent, wxString title, wxString content);
|
||||
void create_about(wxWindow* parent, wxString title, wxString content);
|
||||
@@ -49,6 +50,7 @@ public:
|
||||
|
||||
void on_reset_page();
|
||||
void on_device_connected(MachineObject* obj);
|
||||
void msw_rescale() override;
|
||||
};
|
||||
|
||||
class CalibrationFlowRateStartPage : public CalibrationStartPage
|
||||
@@ -63,6 +65,7 @@ public:
|
||||
void create_page(wxWindow* parent);
|
||||
void on_reset_page();
|
||||
void on_device_connected(MachineObject* obj);
|
||||
void msw_rescale() override;
|
||||
};
|
||||
|
||||
class CalibrationMaxVolumetricSpeedStartPage : public CalibrationStartPage
|
||||
@@ -75,6 +78,7 @@ public:
|
||||
long style = wxTAB_TRAVERSAL);
|
||||
|
||||
void create_page(wxWindow* parent);
|
||||
void msw_rescale() override;
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
@@ -260,7 +260,7 @@ void CameraPopup::check_func_supported(MachineObject *obj2)
|
||||
if (m_obj == nullptr)
|
||||
return;
|
||||
// function supported
|
||||
if (m_obj->is_function_supported(PrinterFunction::FUNC_RECORDING) && m_obj->has_ipcam) {
|
||||
if (m_obj->has_ipcam) {
|
||||
m_text_recording->Show();
|
||||
m_switch_recording->Show();
|
||||
} else {
|
||||
@@ -268,7 +268,7 @@ void CameraPopup::check_func_supported(MachineObject *obj2)
|
||||
m_switch_recording->Hide();
|
||||
}
|
||||
|
||||
if (m_obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_CAMERA) && m_obj->has_ipcam) {
|
||||
if (m_obj->virtual_camera && m_obj->has_ipcam) {
|
||||
m_text_vcamera->Show();
|
||||
m_switch_vcamera->Show();
|
||||
if (is_vcamera_show) {
|
||||
@@ -282,7 +282,7 @@ void CameraPopup::check_func_supported(MachineObject *obj2)
|
||||
link_underline->Hide();
|
||||
}
|
||||
|
||||
allow_alter_resolution = (m_obj->is_function_supported(PrinterFunction::FUNC_ALTER_RESOLUTION) && m_obj->has_ipcam);
|
||||
allow_alter_resolution = ( (m_obj->camera_resolution_supported.size() > 1?true:false) && m_obj->has_ipcam);
|
||||
|
||||
//check u2 version
|
||||
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
|
||||
@@ -409,8 +409,8 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
if (config->opt_bool("enable_support")) {
|
||||
auto support_type = config->opt_enum<SupportType>("support_type");
|
||||
auto support_style = config->opt_enum<SupportMaterialStyle>("support_style");
|
||||
std::set<int> enum_set_normal = {0, 1, 2};
|
||||
std::set<int> enum_set_tree = {0, 3, 4, 5, 6};
|
||||
std::set<int> enum_set_normal = { smsDefault, smsGrid, smsSnug };
|
||||
std::set<int> enum_set_tree = { smsDefault, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsOrganic };
|
||||
auto & set = is_tree(support_type) ? enum_set_tree : enum_set_normal;
|
||||
if (set.find(support_style) == set.end()) {
|
||||
DynamicPrintConfig new_conf = *config;
|
||||
@@ -490,7 +490,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
|
||||
bool have_perimeters = config->opt_int("wall_loops") > 0;
|
||||
for (auto el : { "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall",
|
||||
"seam_position", "staggered_inner_seams", "wall_infill_order", "outer_wall_line_width",
|
||||
"seam_position", "staggered_inner_seams", "wall_sequence", "outer_wall_line_width",
|
||||
"inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" })
|
||||
toggle_field(el, have_perimeters);
|
||||
|
||||
@@ -571,8 +571,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
"support_base_pattern_spacing", "support_expansion", "support_angle",
|
||||
"support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers",
|
||||
"bridge_no_support", "max_bridge_length", "support_top_z_distance", "support_bottom_z_distance",
|
||||
//BBS: add more support params to dependent of enable_support
|
||||
"support_type", "support_on_build_plate_only", "support_critical_regions_only",
|
||||
"support_type", "support_on_build_plate_only", "support_critical_regions_only","support_interface_not_for_body",
|
||||
"support_object_xy_distance"/*, "independent_support_layer_height"*/})
|
||||
toggle_field(el, have_support_material);
|
||||
toggle_field("support_threshold_angle", have_support_material && is_auto(support_type));
|
||||
@@ -663,7 +662,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
toggle_line("slowdown_for_curled_perimeters",!has_overhang_speed_classic && has_overhang_speed);
|
||||
|
||||
toggle_line("flush_into_objects", !is_global_config);
|
||||
|
||||
|
||||
toggle_line("support_interface_not_for_body",config->opt_int("support_interface_filament")&&!config->opt_int("support_filament"));
|
||||
|
||||
bool has_fuzzy_skin = (config->opt_enum<FuzzySkinType>("fuzzy_skin") != FuzzySkinType::None);
|
||||
for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer"})
|
||||
toggle_line(el, has_fuzzy_skin);
|
||||
|
||||
@@ -118,32 +118,22 @@ void ConnectPrinterDialog::init_bitmap()
|
||||
std::string language = config->get("language");
|
||||
|
||||
if (m_obj) {
|
||||
if (m_obj->printer_type == "C11" || m_obj->printer_type == "C12") {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_accesscode_help2", nullptr, 190);
|
||||
}
|
||||
else if (m_obj->printer_type == "BL-P001" || m_obj->printer_type == "BL-P002" || m_obj->printer_type == "C13") {
|
||||
if (language == "zh_CN") {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_cn", nullptr, 190);
|
||||
}
|
||||
else {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_en", nullptr, 190);
|
||||
}
|
||||
}
|
||||
else if (m_obj->printer_type == "N1") {
|
||||
if (language == "zh_CN") {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_n1_cn", nullptr, 250);
|
||||
}
|
||||
else {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_n1_en", nullptr, 250);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string img_str = DeviceManager::get_printer_diagram_img(m_obj->printer_type);
|
||||
if(img_str.empty()){img_str = "input_access_code_x1"; }
|
||||
|
||||
if (language == "zh_CN") {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_cn", nullptr, 190);
|
||||
m_diagram_bmp = create_scaled_bitmap(img_str+"_cn", nullptr, 190);
|
||||
}
|
||||
else {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_en", nullptr, 190);
|
||||
m_diagram_bmp = create_scaled_bitmap(img_str+"_en", nullptr, 190);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (language == "zh_CN") {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_x1_cn", nullptr, 190);
|
||||
}
|
||||
else {
|
||||
m_diagram_bmp = create_scaled_bitmap("input_access_code_x1_en", nullptr, 190);
|
||||
}
|
||||
}
|
||||
m_diagram_img = m_diagram_bmp.ConvertToImage();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,398 @@
|
||||
#ifndef slic3r_CreatePresetsDialog_hpp_
|
||||
#define slic3r_CreatePresetsDialog_hpp_
|
||||
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "Widgets/Label.hpp"
|
||||
#include "Widgets/TextInput.hpp"
|
||||
#include "Widgets/Button.hpp"
|
||||
#include "Widgets/RadioBox.hpp"
|
||||
#include "Widgets/CheckBox.hpp"
|
||||
#include "Widgets/ComboBox.hpp"
|
||||
#include "miniz.h"
|
||||
#include "ParamsDialog.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class CreateFilamentPresetDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
CreateFilamentPresetDialog(wxWindow *parent);
|
||||
~CreateFilamentPresetDialog();
|
||||
|
||||
protected:
|
||||
enum FilamentOptionType {
|
||||
VENDOR = 0,
|
||||
TYPE,
|
||||
SERIAL,
|
||||
FILAMENT_PRESET,
|
||||
PRESET_FOR_PRINTER,
|
||||
FILAMENT_NAME_COUNT
|
||||
};
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
bool is_check_box_selected();
|
||||
wxBoxSizer *create_item(FilamentOptionType option_type);
|
||||
wxBoxSizer *create_vendor_item();
|
||||
wxBoxSizer *create_type_item();
|
||||
wxBoxSizer *create_serial_item();
|
||||
wxBoxSizer *create_filament_preset_item();
|
||||
wxBoxSizer *create_filament_preset_for_printer_item();
|
||||
wxBoxSizer *create_button_item();
|
||||
|
||||
private:
|
||||
void clear_filament_preset_map();
|
||||
wxArrayString get_filament_preset_choices();
|
||||
wxBoxSizer * create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector<std::pair<RadioBox *, wxString>> &radiobox_list);
|
||||
void select_curr_radiobox(std::vector<std::pair<RadioBox *, wxString>> &radiobox_list, int btn_idx);
|
||||
wxString curr_create_filament_type();
|
||||
void get_filament_presets_by_machine();
|
||||
void get_all_filament_presets();
|
||||
void get_all_visible_printer_name();
|
||||
void update_dialog_size();
|
||||
template<typename T>
|
||||
void sort_printer_by_nozzle(std::vector<std::pair<std::string, T>> &printer_name_to_filament_preset);
|
||||
|
||||
private:
|
||||
struct CreateType
|
||||
{
|
||||
wxString base_filament;
|
||||
wxString base_filament_preset;
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<std::pair<RadioBox *, wxString>> m_create_type_btns;
|
||||
std::unordered_map<::CheckBox *, std::pair<std::string, Preset *>> m_filament_preset;
|
||||
std::unordered_map<::CheckBox *, std::pair<std::string, Preset *>> m_machint_filament_preset;
|
||||
std::unordered_map<std::string, std::vector<Preset *>> m_filament_choice_map;
|
||||
std::unordered_map<wxString, std::string> m_public_name_to_filament_id_map;
|
||||
std::unordered_map<std::string, Preset *> m_all_presets_map;
|
||||
std::set<std::string> m_visible_printers;
|
||||
CreateType m_create_type;
|
||||
Button * m_button_create = nullptr;
|
||||
Button * m_button_cancel = nullptr;
|
||||
ComboBox * m_filament_vendor_combobox = nullptr;
|
||||
::CheckBox * m_can_not_find_vendor_checkbox = nullptr;
|
||||
ComboBox * m_filament_type_combobox = nullptr;
|
||||
ComboBox * m_exist_vendor_combobox = nullptr;
|
||||
ComboBox * m_filament_preset_combobox = nullptr;
|
||||
TextInput * m_filament_custom_vendor_input = nullptr;
|
||||
wxGridSizer * m_filament_presets_sizer = nullptr;
|
||||
wxPanel * m_filament_preset_panel = nullptr;
|
||||
wxScrolledWindow * m_scrolled_preset_panel = nullptr;
|
||||
TextInput * m_filament_serial_input = nullptr;
|
||||
wxBoxSizer * m_scrolled_sizer = nullptr;
|
||||
wxStaticText * m_filament_preset_text = nullptr;
|
||||
|
||||
};
|
||||
|
||||
class CreatePrinterPresetDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
CreatePrinterPresetDialog(wxWindow *parent);
|
||||
~CreatePrinterPresetDialog();
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
|
||||
/******************************************************** Control Construction *****************************************************/
|
||||
wxBoxSizer *create_step_switch_item();
|
||||
//Create Printer Page1
|
||||
void create_printer_page1(wxWindow *parent);
|
||||
wxBoxSizer *create_type_item(wxWindow *parent);
|
||||
wxBoxSizer *create_printer_item(wxWindow *parent);
|
||||
wxBoxSizer *create_nozzle_diameter_item(wxWindow *parent);
|
||||
wxBoxSizer *create_bed_shape_item(wxWindow *parent);
|
||||
wxBoxSizer *create_bed_size_item(wxWindow *parent);
|
||||
wxBoxSizer *create_origin_item(wxWindow *parent);
|
||||
wxBoxSizer *create_hot_bed_stl_item(wxWindow *parent);
|
||||
wxBoxSizer *create_hot_bed_svg_item(wxWindow *parent);
|
||||
wxBoxSizer *create_max_print_height_item(wxWindow *parent);
|
||||
wxBoxSizer *create_page1_btns_item(wxWindow *parent);
|
||||
//Improt Presets Page2
|
||||
void create_printer_page2(wxWindow *parent);
|
||||
wxBoxSizer *create_printer_preset_item(wxWindow *parent);
|
||||
wxBoxSizer *create_presets_item(wxWindow *parent);
|
||||
wxBoxSizer *create_presets_template_item(wxWindow *parent);
|
||||
wxBoxSizer *create_page2_btns_item(wxWindow *parent);
|
||||
|
||||
void show_page1();
|
||||
void show_page2();
|
||||
|
||||
/********************************************************** Data Interaction *******************************************************/
|
||||
bool data_init();
|
||||
void set_current_visible_printer();
|
||||
void select_curr_radiobox(std::vector<std::pair<RadioBox *, wxString>> &radiobox_list, int btn_idx);
|
||||
void select_all_preset_template(std::vector<std::pair<::CheckBox *, Preset *>> &preset_templates);
|
||||
void deselect_all_preset_template(std::vector<std::pair<::CheckBox *, Preset *>> &preset_templates);
|
||||
void update_presets_list(bool jast_template = false);
|
||||
void on_preset_model_value_change(wxCommandEvent &e);
|
||||
void clear_preset_combobox();
|
||||
bool save_printable_area_config(Preset *preset);
|
||||
bool check_printable_area();
|
||||
bool validate_input_valid();
|
||||
void load_texture();
|
||||
void load_model_stl();
|
||||
bool load_system_and_user_presets_with_curr_model(PresetBundle &temp_preset_bundle, bool just_template = false);
|
||||
void generate_process_presets_data(std::vector<Preset const *> presets, std::string nozzle);
|
||||
void update_preset_list_size();
|
||||
wxArrayString printer_preset_sort_with_nozzle_diameter(const VendorProfile &vendor_profile, float nozzle_diameter);
|
||||
|
||||
wxBoxSizer *create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector<std::pair<RadioBox *, wxString>> &radiobox_list);
|
||||
|
||||
wxString curr_create_preset_type();
|
||||
wxString curr_create_printer_type();
|
||||
|
||||
private:
|
||||
struct CreatePrinterType
|
||||
{
|
||||
wxString create_printer;
|
||||
wxString create_nozzle;
|
||||
wxString base_template;
|
||||
wxString base_curr_printer;
|
||||
};
|
||||
|
||||
CreatePrinterType m_create_type;
|
||||
std::vector<std::pair<RadioBox *, wxString>> m_create_type_btns;
|
||||
std::vector<std::pair<RadioBox *, wxString>> m_create_presets_btns;
|
||||
std::vector<std::pair<::CheckBox *, Preset *>> m_filament_preset;
|
||||
std::vector<std::pair<::CheckBox *, Preset *>> m_process_preset;
|
||||
std::unordered_map<std::string, std::shared_ptr<Preset>> m_printer_name_to_preset;
|
||||
VendorProfile m_printer_preset_vendor_selected;
|
||||
Slic3r::VendorProfile::PrinterModel m_printer_preset_model_selected;
|
||||
bool rewritten = false;
|
||||
Preset * m_printer_preset = nullptr;
|
||||
wxStaticBitmap * m_step_1 = nullptr;
|
||||
wxStaticBitmap * m_step_2 = nullptr;
|
||||
Button * m_button_OK = nullptr;
|
||||
Button * m_button_create = nullptr;
|
||||
Button * m_button_page1_cancel = nullptr;
|
||||
Button * m_button_page2_cancel = nullptr;
|
||||
Button * m_button_page2_back = nullptr;
|
||||
Button * m_button_bed_stl = nullptr;
|
||||
Button * m_button_bed_svg = nullptr;
|
||||
wxScrolledWindow * m_page1 = nullptr;
|
||||
wxPanel * m_page2 = nullptr;
|
||||
wxScrolledWindow * m_scrolled_preset_window = nullptr;
|
||||
wxBoxSizer * m_scrooled_preset_sizer = nullptr;
|
||||
ComboBox * m_select_vendor = nullptr;
|
||||
ComboBox * m_select_model = nullptr;
|
||||
ComboBox * m_select_printer = nullptr;
|
||||
::CheckBox * m_can_not_find_vendor_combox = nullptr;
|
||||
wxStaticText * m_can_not_find_vendor_text = nullptr;
|
||||
wxTextCtrl * m_custom_vendor_text_ctrl = nullptr;
|
||||
wxTextCtrl * m_custom_model_text_ctrl = nullptr;
|
||||
ComboBox * m_nozzle_diameter = nullptr;
|
||||
ComboBox * m_printer_vendor = nullptr;
|
||||
ComboBox * m_printer_model = nullptr;
|
||||
TextInput * m_bed_size_x_input = nullptr;
|
||||
TextInput * m_bed_size_y_input = nullptr;
|
||||
TextInput * m_bed_origin_x_input = nullptr;
|
||||
TextInput * m_bed_origin_y_input = nullptr;
|
||||
TextInput * m_print_height_input = nullptr;
|
||||
wxGridSizer * m_filament_preset_template_sizer = nullptr;
|
||||
wxGridSizer * m_process_preset_template_sizer = nullptr;
|
||||
wxPanel * m_filament_preset_panel = nullptr;
|
||||
wxPanel * m_process_preset_panel = nullptr;
|
||||
wxPanel * m_preset_template_panel = nullptr;
|
||||
wxBoxSizer * m_filament_sizer = nullptr;
|
||||
wxPanel * m_printer_info_panel = nullptr;
|
||||
wxBoxSizer * m_page1_sizer = nullptr;
|
||||
wxBoxSizer * m_printer_info_sizer = nullptr;
|
||||
wxBoxSizer * m_page2_sizer = nullptr;
|
||||
wxStaticText * m_upload_stl_tip_text = nullptr;
|
||||
wxStaticText * m_upload_svg_tip_text = nullptr;
|
||||
std::string m_custom_texture;
|
||||
std::string m_custom_model;
|
||||
};
|
||||
|
||||
enum SuccessType {
|
||||
PRINTER = 0,
|
||||
FILAMENT
|
||||
};
|
||||
|
||||
class CreatePresetSuccessfulDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
CreatePresetSuccessfulDialog(wxWindow *parent, const SuccessType &create_success_type);
|
||||
~CreatePresetSuccessfulDialog();
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
|
||||
private:
|
||||
Button *m_button_ok = nullptr;
|
||||
Button *m_button_cancel = nullptr;
|
||||
};
|
||||
|
||||
class ExportConfigsDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
ExportConfigsDialog(wxWindow *parent);
|
||||
~ExportConfigsDialog();//to do: delete preset
|
||||
|
||||
protected:
|
||||
|
||||
struct ExportType
|
||||
{
|
||||
wxString preset_bundle;
|
||||
wxString filament_bundle;
|
||||
wxString printer_preset;
|
||||
wxString filament_preset;
|
||||
wxString process_preset;
|
||||
};
|
||||
|
||||
enum ExportCase {
|
||||
INITIALIZE_FAIL = 0,
|
||||
ADD_FILE_FAIL,
|
||||
ADD_BUNDLE_STRUCTURE_FAIL,
|
||||
FINALIZE_FAIL,
|
||||
OPEN_ZIP_WRITTEN_FILE,
|
||||
EXPORT_CANCEL,
|
||||
EXPORT_SUCCESS,
|
||||
CASE_COUNT,
|
||||
};
|
||||
|
||||
private:
|
||||
void data_init();
|
||||
void select_curr_radiobox(std::vector<std::pair<RadioBox *, wxString>> &radiobox_list, int btn_idx);
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
void show_export_result(const ExportCase &export_case);
|
||||
bool has_check_box_selected();
|
||||
bool preset_is_not_compatible_bbl_printer(Preset *preset);
|
||||
std::string initial_file_path(const wxString &path, const std::string &sub_file_path);
|
||||
std::string initial_file_name(const wxString &path, const std::string file_name);
|
||||
wxBoxSizer *create_export_config_item(wxWindow *parent);
|
||||
wxBoxSizer *create_button_item(wxWindow *parent);
|
||||
wxBoxSizer *create_select_printer(wxWindow *parent);
|
||||
wxBoxSizer *create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector<std::pair<RadioBox *, wxString>> &radiobox_list);
|
||||
int initial_zip_archive(mz_zip_archive &zip_archive, const std::string &file_path);
|
||||
ExportCase save_zip_archive_to_file(mz_zip_archive &zip_archive);
|
||||
ExportCase save_presets_to_zip(const std::string &export_file, const std::vector<std::pair<std::string, std::string>> &config_paths);
|
||||
ExportCase archive_preset_bundle_to_file(const wxString &path);
|
||||
ExportCase archive_filament_bundle_to_file(const wxString &path);
|
||||
ExportCase archive_printer_preset_to_file(const wxString &path);
|
||||
ExportCase archive_filament_preset_to_file(const wxString &path);
|
||||
ExportCase archive_process_preset_to_file(const wxString &path);
|
||||
|
||||
private:
|
||||
std::vector<std::pair<RadioBox *, wxString>> m_export_type_btns;
|
||||
std::vector<std::pair<::CheckBox *, Preset *>> m_preset; // for printer preset bundle,printer preset, process preset export
|
||||
std::vector<std::pair<::CheckBox *, std::string>> m_printer_name; // for filament and peocess preset export, collaborate with m_filament_name_to_presets
|
||||
std::unordered_map<std::string, Preset *> m_printer_presets;//first: printer name, second: printer presets have same printer name
|
||||
std::unordered_map<std::string, std::vector<Preset *>> m_filament_presets;//first: printer name, second: filament presets have same printer name
|
||||
std::unordered_map<std::string, std::vector<Preset *>> m_process_presets;//first: printer name, second: filament presets have same printer name
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::string, Preset *>>> m_filament_name_to_presets;//first: filament name, second presets have same filament name and printer name in vector
|
||||
ExportType m_exprot_type;
|
||||
wxBoxSizer * m_main_sizer = nullptr;
|
||||
wxScrolledWindow * m_scrolled_preset_window = nullptr;
|
||||
wxGridSizer * m_preset_sizer = nullptr;
|
||||
wxPanel * m_presets_window = nullptr;
|
||||
Button * m_button_ok = nullptr;
|
||||
Button * m_button_cancel = nullptr;
|
||||
wxStaticText * m_serial_text = nullptr;
|
||||
};
|
||||
|
||||
class CreatePresetForPrinterDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
CreatePresetForPrinterDialog(wxWindow *parent, std::string filament_type, std::string filament_id, std::string filament_vendor, std::string filament_name);
|
||||
~CreatePresetForPrinterDialog();
|
||||
|
||||
private:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
void get_visible_printer_and_compatible_filament_presets();
|
||||
wxBoxSizer *create_selected_printer_preset_sizer();
|
||||
wxBoxSizer *create_selected_filament_preset_sizer();
|
||||
wxBoxSizer *create_button_sizer();
|
||||
|
||||
private:
|
||||
std::string m_filament_id;
|
||||
std::string m_filament_name;
|
||||
std::string m_filament_vendor;
|
||||
std::string m_filament_type;
|
||||
std::shared_ptr<PresetBundle> m_preset_bundle;
|
||||
std::string m_filamnt_type;
|
||||
ComboBox * m_selected_printer = nullptr;
|
||||
ComboBox * m_selected_filament = nullptr;
|
||||
Button * m_ok_btn = nullptr;
|
||||
Button * m_cancel_btn = nullptr;
|
||||
std::unordered_map<wxString, std::shared_ptr<Preset>> filament_choice_to_filament_preset;
|
||||
std::unordered_map<std::string, std::vector<std::shared_ptr<Preset>>> m_printer_compatible_filament_presets; // need be used when add presets
|
||||
|
||||
};
|
||||
|
||||
class EditFilamentPresetDialog;
|
||||
|
||||
class PresetTree
|
||||
{
|
||||
public:
|
||||
PresetTree(EditFilamentPresetDialog *dialog);
|
||||
|
||||
wxPanel *get_preset_tree(std::pair<std::string, std::vector<std::shared_ptr<Preset>>> printer_and_presets);
|
||||
|
||||
private:
|
||||
wxPanel *get_root_item(wxPanel *parent, const std::string &printer_name);
|
||||
|
||||
wxPanel *get_child_item(wxPanel *parent, std::shared_ptr<Preset> preset, std::string printer_name, int preset_index, bool is_last = false);
|
||||
|
||||
void delete_preset(std::string printer_name, int need_delete_preset_index);
|
||||
|
||||
void edit_preset(std::string printer_name, int need_edit_preset_index);
|
||||
|
||||
private:
|
||||
EditFilamentPresetDialog * m_parent_dialog = nullptr;
|
||||
std::pair<std::string, std::vector<std::shared_ptr<Preset>>> m_printer_and_presets;
|
||||
|
||||
};
|
||||
|
||||
class EditFilamentPresetDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
EditFilamentPresetDialog(wxWindow *parent, FilamentInfomation *filament_info);
|
||||
~EditFilamentPresetDialog();
|
||||
|
||||
wxPanel *get_preset_tree_panel() { return m_preset_tree_panel; }
|
||||
void set_printer_name(const std::string &printer_name) { m_selected_printer = printer_name; }
|
||||
void set_need_delete_preset_index(int need_delete_preset_index) { m_need_delete_preset_index = need_delete_preset_index; }
|
||||
void set_need_edit_preset_index(int need_edit_preset_index) { m_need_edit_preset_index = need_edit_preset_index; }
|
||||
void delete_preset();
|
||||
void edit_preset();
|
||||
|
||||
private:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
bool get_same_filament_id_presets(std::string filament_id);
|
||||
void update_preset_tree();
|
||||
wxBoxSizer *create_filament_basic_info();
|
||||
wxBoxSizer *create_add_filament_btn();
|
||||
wxBoxSizer *create_preset_tree_sizer();
|
||||
wxBoxSizer *create_button_sizer();
|
||||
|
||||
private:
|
||||
PresetTree * m_preset_tree_creater = nullptr;
|
||||
std::string m_filament_id;
|
||||
std::string m_filament_name;
|
||||
std::string m_vendor_name;
|
||||
std::string m_filament_type;
|
||||
std::string m_filament_serial;
|
||||
Button * m_add_filament_btn = nullptr;
|
||||
Button * m_del_filament_btn = nullptr;
|
||||
Button * m_ok_btn = nullptr;
|
||||
wxBoxSizer * m_preset_tree_sizer = nullptr;
|
||||
wxPanel * m_preset_tree_panel = nullptr;
|
||||
wxScrolledWindow * m_preset_tree_window = nullptr;
|
||||
wxBoxSizer * m_main_sizer = nullptr;
|
||||
wxStaticText * m_note_text = nullptr;
|
||||
int m_need_delete_preset_index = -1;
|
||||
int m_need_edit_preset_index = -1;
|
||||
std::string m_selected_printer = "";
|
||||
std::unordered_map<std::string, std::vector<std::shared_ptr<Preset>>> m_printer_compatible_presets;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user