Merge branch 'master' into SoftFever

Signed-off-by: SoftFever <103989404+SoftFever@users.noreply.github.com>

# Conflicts:
#	resources/i18n/zh_cn/BambuStudio.mo
#	src/libslic3r/TreeSupport.cpp
#	version.inc
This commit is contained in:
SoftFever 2022-12-21 16:54:14 +08:00
commit d733ab7e7b
54 changed files with 500 additions and 1230 deletions

View file

@ -3,6 +3,7 @@
#include <string>
#include <sstream>
#include <iostream>
#include <mutex>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/log/trivial.hpp>

View file

@ -9,7 +9,7 @@
bool write_to_pot(boost::filesystem::path path, const std::vector<std::pair<std::string, std::string>>& data)
{
boost::filesystem::ofstream file(std::move(path), std::ios_base::app);
boost::nowide::ofstream file(path.string(), std::ios_base::app);
for (const auto& element : data)
{
//Example of .pot element

View file

@ -1,6 +1,6 @@
#ifndef slic3r_Format_3mf_hpp_
#define slic3r_Format_3mf_hpp_
#include "../expat.h"
#include <expat.h>
namespace Slic3r {
// PrusaFileParser is used to check 3mf file is from Prusa

View file

@ -23,6 +23,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/string_file.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/spirit/include/karma.hpp>

View file

@ -10,6 +10,7 @@
#include <cstdint>
#include <array>
#include <vector>
#include <mutex>
#include <string>
#include <string_view>
#include <optional>

View file

@ -25,6 +25,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/string_file.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/iostream.hpp>

View file

@ -2889,7 +2889,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
// Generate intermediate layers.
// The first intermediate layer is the same as the 1st layer if there is no raft,
// or the bottom of the first intermediate layer is aligned with the bottom of the raft contact layer.
// Intermediate layers are always printed with a normal etrusion flow (non-bridging).
// Intermediate layers are always printed with a normal extrusion flow (non-bridging).
size_t idx_layer_object = 0;
size_t idx_extreme_first = 0;
if (! extremes.empty() && std::abs(extremes.front()->extreme_z() - m_slicing_params.raft_interface_top_z) < EPSILON) {

View file

@ -29,7 +29,7 @@
#define TAU (2.0 * M_PI)
#define NO_INDEX (std::numeric_limits<unsigned int>::max())
//#define SUPPORT_TREE_DEBUG_TO_SVG
// #define SUPPORT_TREE_DEBUG_TO_SVG
namespace Slic3r
{
@ -1399,7 +1399,6 @@ void TreeSupport::generate_toolpaths()
const size_t wall_count = object_config.tree_support_wall_count.value;
const bool with_infill = object_config.support_base_pattern != smpNone && object_config.support_base_pattern != smpDefault;
auto m_support_material_flow = support_material_flow(m_object, float(m_slicing_params.layer_height));
// coconut: use same intensity settings as SupportMaterial.cpp
auto m_support_material_interface_flow = support_material_interface_flow(m_object, float(m_slicing_params.layer_height));
@ -1407,8 +1406,6 @@ void TreeSupport::generate_toolpaths()
coordf_t bottom_interface_spacing = object_config.support_bottom_interface_spacing.value + m_support_material_interface_flow.spacing();
coordf_t interface_density = std::min(1., m_support_material_interface_flow.spacing() / interface_spacing);
coordf_t bottom_interface_density = std::min(1., m_support_material_interface_flow.spacing() / bottom_interface_spacing);
coordf_t support_spacing = object_config.support_base_pattern_spacing.value + m_support_material_flow.spacing();
coordf_t support_density = std::min(1., m_support_material_flow.spacing() / support_spacing);
const coordf_t branch_radius = object_config.tree_support_branch_diameter.value / 2;
const coordf_t branch_radius_scaled = scale_(branch_radius);
@ -1518,6 +1515,9 @@ void TreeSupport::generate_toolpaths()
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_id);
Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter);
coordf_t support_spacing = object_config.support_base_pattern_spacing.value + support_flow.spacing();
coordf_t support_density = std::min(1., support_flow.spacing() / support_spacing);
ts_layer->support_fills.no_sort = false;
for (auto& area_group : ts_layer->area_groups) {
@ -1569,12 +1569,11 @@ void TreeSupport::generate_toolpaths()
}
else {
// base_areas
filler_support->spacing = m_support_material_flow.spacing();
Flow flow = (layer_id == 0 && m_raft_layers == 0) ? m_object->print()->brim_flow() :
(m_support_params.base_fill_pattern == ipRectilinear && (layer_id % num_layers_to_change_infill_direction == 0) ? support_transition_flow(m_object) : support_flow);
if (area_group.dist_to_top < 10 / layer_height) {
// extra 2 walls for the top tips
make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, wall_count + 2, flow, false);
filler_support->spacing = support_flow.spacing();
Flow flow = (layer_id == 0 && m_raft_layers == 0) ? m_object->print()->brim_flow() : support_flow;
if (area_group.dist_to_top < 10 / layer_height && !with_infill) {
// at least 2 walls for the top tips
make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, std::max(wall_count, size_t(2)), flow, false);
} else {
if (with_infill && layer_id > 0 && m_support_params.base_fill_pattern != ipLightning) {
filler_support->angle = Geometry::deg2rad(object_config.support_angle.value);
@ -1893,7 +1892,7 @@ void TreeSupport::generate_support_areas()
profiler.stage_finish(STAGE_DROP_DOWN_NODES);
// Adjust support layer heights
adjust_layer_heights(contact_nodes);
// adjust_layer_heights(contact_nodes);
//Generate support areas.
profiler.stage_start(STAGE_DRAW_CIRCLES);
@ -2023,20 +2022,24 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
{
if (print->canceled())
break;
const std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr];
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
assert(ts_layer != nullptr);
// skip if current layer has no points. This fixes potential crash in get_collision (see jira BBL001-355)
if (curr_layer_nodes.empty())
if (curr_layer_nodes.empty()) {
ts_layer->print_z = 0.0;
ts_layer->height = 0.0;
continue;
}
Node* first_node = curr_layer_nodes.front();
ts_layer->print_z = first_node->print_z;
ts_layer->height = first_node->height;
if (ts_layer->height < EPSILON)
if (ts_layer->height < EPSILON) {
continue;
}
ExPolygons& base_areas = ts_layer->base_areas;
ExPolygons& roof_areas = ts_layer->roof_areas;
@ -2057,16 +2060,16 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
const Node& node = *p_node;
ExPolygon area;
// 直接从overhang多边形生成如果<EFBFBD>?
// 1) 是混合支撑里的普通部分,
// 2) 启用了顶部接触层<EFBFBD>?
// 3) 是顶部空<EFBFBD>?
// Generate directly from overhang polygon if one of the following is true:
// 1) node is a normal part of hybrid support
// 2) top interface layers are enabled
// 3) node is virtual
if (node.type == ePolygon || (top_interface_layers>0 &&node.support_roof_layers_below > 0) || node.distance_to_top<0) {
if (node.overhang->contour.size() > 100 || node.overhang->holes.size()>1)
area = *node.overhang;
else {
auto tmp = offset_ex({ *node.overhang }, scale_(m_ts_data->m_xy_distance));
if(!tmp.empty()) // 对于有缺陷的模型overhang膨胀以后可能是空的
if(!tmp.empty()) // can be empty for non-manifold models
area = tmp[0];
}
}
@ -2396,7 +2399,22 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
char fname[10]; sprintf(fname, "%d_%.2f", layer_nr, ts_layer->print_z);
draw_contours_and_nodes_to_svg(-1, base_areas, roof_areas, roof_1st_layer, {}, {}, get_svg_filename(fname, "circles"), { "base", "roof", "roof1st" });
}
#endif
// export layer & print_z log
std::ofstream draw_circles_layer_out;
draw_circles_layer_out.open("./SVG/layer_heights_draw_circles.txt");
if (draw_circles_layer_out.is_open()) {
for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) {
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
ExPolygons& base_areas = ts_layer->base_areas;
ExPolygons& roof_areas = ts_layer->roof_areas;
ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer;
ExPolygons& floor_areas = ts_layer->floor_areas;
if (base_areas.empty() && roof_areas.empty() && roof_1st_layer.empty()) continue;
draw_circles_layer_out << layer_nr << " " << ts_layer->print_z << " " << ts_layer->height << std::endl;
}
}
#endif // SUPPORT_TREE_DEBUG_TO_SVG
TreeSupportLayerPtrs& ts_layers = m_object->tree_support_layers();
auto iter = std::remove_if(ts_layers.begin(), ts_layers.end(), [](TreeSupportLayer* ts_layer) { return ts_layer->height < EPSILON; });
@ -2410,7 +2428,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
{
const PrintObjectConfig &config = m_object->config();
//Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
// Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
const coordf_t layer_height = config.layer_height.value;
const double angle = config.tree_support_branch_angle.value * M_PI / 180.;
const int wall_count = std::max(1, config.tree_support_wall_count.value);
@ -2424,6 +2442,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
const bool support_on_buildplate_only = config.support_on_build_plate_only.value;
const size_t bottom_interface_layers = config.support_interface_bottom_layers.value;
const size_t top_interface_layers = config.support_interface_top_layers.value;
std::vector<std::pair<coordf_t, coordf_t>> layer_heights = plan_layer_heights(contact_nodes);
std::unordered_set<Node*> to_free_node_set;
m_spanning_trees.resize(contact_nodes.size());
@ -2467,16 +2486,22 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
BOOST_LOG_TRIVIAL(debug) << "before m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size();
}
for (size_t layer_nr = contact_nodes.size() - 1; layer_nr > 0; layer_nr--) //Skip layer 0, since we can't drop down the vertices there.
for (size_t layer_nr = contact_nodes.size() - 1; layer_nr > 0; layer_nr--) // Skip layer 0, since we can't drop down the vertices there.
{
if (m_object->print()->canceled())
break;
auto& layer_contact_nodes = contact_nodes[layer_nr];
std::deque<std::pair<size_t, Node*>> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches.
const Layer* ts_layer = m_object->get_tree_support_layer(layer_nr);
if (layer_contact_nodes.empty())
continue;
int jump_nr = 1;
while (layer_heights[layer_nr - jump_nr].second < EPSILON)
jump_nr++;
std::deque<std::pair<size_t, Node*>> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches.
const Layer* ts_layer = m_object->get_tree_support_layer(layer_nr);
m_object->print()->set_status(60, (boost::format(_L("Support: propagate branches at layer %d")) % layer_nr).str());
Polygons layer_contours = std::move(m_ts_data->get_contours_with_holes(layer_nr));
@ -2512,8 +2537,8 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
if (node.distance_to_top < 0) {
// virtual node do not merge or move
Node* next_node = new Node(p_node->position, p_node->distance_to_top + 1, p_node->skin_direction, p_node->support_roof_layers_below - 1, p_node->to_buildplate, p_node,
m_object->get_layer(layer_nr - 1)->print_z, m_object->get_layer(layer_nr - 1)->height);
contact_nodes[layer_nr - 1].emplace_back(next_node);
layer_heights[layer_nr - jump_nr].first, layer_heights[layer_nr - jump_nr].second);
contact_nodes[layer_nr - jump_nr].emplace_back(next_node);
continue;
}
if (support_on_buildplate_only && !node.to_buildplate) //Can't rest on model and unable to reach the build plate. Then we must drop the node and leave parts unsupported.
@ -2530,8 +2555,8 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
// polygon node do not merge or move
const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], p_node->position);
Node *next_node = new Node(p_node->position, p_node->distance_to_top + 1, p_node->skin_direction, p_node->support_roof_layers_below - 1, to_buildplate, p_node,
m_object->get_layer(layer_nr - 1)->print_z, m_object->get_layer(layer_nr - 1)->height);
contact_nodes[layer_nr - 1].emplace_back(next_node);
layer_heights[layer_nr - jump_nr].first, layer_heights[layer_nr - jump_nr].second);
contact_nodes[layer_nr - jump_nr].emplace_back(next_node);
continue;
}
/* Find which part this node is located in and group the nodes in
@ -2608,7 +2633,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
const coordf_t branch_radius_node = calc_branch_radius(branch_radius, node.distance_to_top, tip_layers, diameter_angle_scale_factor);
auto avoid_layer = m_ts_data->get_avoidance(branch_radius_node, layer_nr - 1);
auto avoid_layer = m_ts_data->get_avoidance(branch_radius_node, layer_nr - jump_nr);
if (group_index == 0)
{
//Avoid collisions.
@ -2620,11 +2645,11 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
size_t new_distance_to_top = std::max(node.distance_to_top, neighbour->distance_to_top) + 1;
size_t new_support_roof_layers_below = std::max(node.support_roof_layers_below, neighbour->support_roof_layers_below) - 1;
const bool to_buildplate = !is_inside_ex(m_ts_data->get_avoidance(0, layer_nr - 1), next_position);
const bool to_buildplate = !is_inside_ex(m_ts_data->get_avoidance(0, layer_nr - jump_nr), next_position);
Node * next_node = new Node(next_position, new_distance_to_top, node.skin_direction, new_support_roof_layers_below, to_buildplate, p_node,
m_object->get_layer(layer_nr - 1)->print_z, p_node->height);
layer_heights[layer_nr - jump_nr].first, layer_heights[layer_nr - jump_nr].second);
next_node->movement = next_position - node.position;
contact_nodes[layer_nr - 1].push_back(next_node);
contact_nodes[layer_nr - jump_nr].push_back(next_node);
// Make sure the next pass doesn't drop down either of these (since that already happened).
node.merged_neighbours.push_front(neighbour);
@ -2708,8 +2733,8 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
Point direction = neighbour - node.position;
Node *neighbour_node = nodes_per_part[group_index][neighbour];
coordf_t branch_bottom_radius = calc_branch_radius(branch_radius, node.distance_to_top + layer_nr, tip_layers, diameter_angle_scale_factor);
coordf_t neighbour_bottom_radius = calc_branch_radius(branch_radius, neighbour_node->distance_to_top + layer_nr, tip_layers, diameter_angle_scale_factor);
coordf_t branch_bottom_radius = calc_branch_radius(branch_radius, node.distance_to_top + 1, tip_layers, diameter_angle_scale_factor);
coordf_t neighbour_bottom_radius = calc_branch_radius(branch_radius, neighbour_node->distance_to_top + 1, tip_layers, diameter_angle_scale_factor);
const coordf_t min_overlap = branch_radius;
double max_converge_distance = tan_angle * (ts_layer->print_z - DO_NOT_MOVER_UNDER_MM) + branch_bottom_radius + neighbour_bottom_radius - min_overlap;
if (vsize2_with_unscale(direction) > max_converge_distance * max_converge_distance)
@ -2740,7 +2765,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
branch_radius_temp = branch_radius_node;
}
#endif
auto avoid_layer = m_ts_data->get_avoidance(branch_radius_node, layer_nr - 1);
auto avoid_layer = m_ts_data->get_avoidance(branch_radius_node, layer_nr - jump_nr);
Point to_outside = projection_onto_ex(avoid_layer, node.position);
Point movement = to_outside - node.position;
@ -2785,15 +2810,15 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], next_layer_vertex);// !is_inside_ex(m_ts_data->get_avoidance(m_ts_data->m_xy_distance, layer_nr - 1), next_layer_vertex);
Node * next_node = new Node(next_layer_vertex, node.distance_to_top + 1, node.skin_direction, node.support_roof_layers_below - 1, to_buildplate, p_node,
m_object->get_layer(layer_nr - 1)->print_z, m_object->get_layer(layer_nr-1)->height);
layer_heights[layer_nr - jump_nr].first, layer_heights[layer_nr - jump_nr].second);
next_node->movement = movement;
contact_nodes[layer_nr - 1].push_back(next_node);
contact_nodes[layer_nr - jump_nr].push_back(next_node);
}
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
draw_contours_and_nodes_to_svg(layer_nr, m_ts_data->get_avoidance(0, layer_nr), m_ts_data->get_avoidance(branch_radius_temp, layer_nr), m_ts_data->m_layer_outlines_below[layer_nr],
contact_nodes[layer_nr], contact_nodes[layer_nr - 1], "contact_points", { "overhang","avoid","outline" }, { "blue","red","yellow" });
contact_nodes[layer_nr], contact_nodes[layer_nr - jump_nr], "contact_points", { "overhang","avoid","outline" }, { "blue","red","yellow" });
#endif
// Prune all branches that couldn't find support on either the model or the buildplate (resulting in 'mid-air' branches).
@ -2840,6 +2865,27 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
delete node;
}
to_free_node_set.clear();
// Merge empty contact_nodes layers
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
// export all print_z and layer height into .txt
std::ofstream layer_heights_out;
layer_heights_out.open("./SVG/layer_heights_drop_nodes.txt");
//layer_heights_out.open("layer_heights_out.txt");
if (layer_heights_out.is_open()) {
for (int i = 0; i < layer_heights.size(); i++) {
if (contact_nodes[i].empty()) {
layer_heights_out << 0 << " " << 0 << std::endl;
}
else {
layer_heights_out << contact_nodes[i][0]->print_z << " " << contact_nodes[i][0]->height << std::endl;
}
}
layer_heights_out.close();
}
#endif
}
void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes)
@ -2849,6 +2895,7 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
const PrintConfig& print_config = m_object->print()->config();
const PrintObjectConfig& config = m_object->config();
if (!print_config.independent_support_layer_height) {
for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) {
std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr];
@ -2932,6 +2979,108 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
}
}
std::vector<std::pair<coordf_t, coordf_t>> TreeSupport::plan_layer_heights(std::vector<std::vector<Node*>>& contact_nodes)
{
const PrintObjectConfig& config = m_object->config();
const coordf_t max_layer_height = m_slicing_params.max_layer_height;
const coordf_t layer_height = config.layer_height.value;
coordf_t z_distance_top = m_slicing_params.gap_support_object;
// BBS: add extra distance if thick bridge is enabled
// Note: normal support uses print_z, but tree support uses integer layers, so we need to subtract layer_height
if (!m_slicing_params.soluble_interface && m_object_config->thick_bridges) {
z_distance_top += m_object->layers()[0]->regions()[0]->region().bridging_height_avg(m_object->print()->config()) - layer_height;
}
const size_t support_roof_layers = config.support_interface_top_layers.value;
const int z_distance_top_layers = round_up_divide(scale_(z_distance_top), scale_(layer_height)) + 1;
std::vector<std::pair<coordf_t, coordf_t>> layer_heights(contact_nodes.size(), std::pair<coordf_t, coordf_t>(0.0, 0.0));
std::vector<int> bounds;
if (layer_height == max_layer_height)
return std::vector<std::pair<coordf_t, coordf_t>>();
bounds.push_back(0);
// Keep first layer still
layer_heights[0].first = m_object->get_layer(0)->print_z;
layer_heights[0].second = m_object->get_layer(0)->height;
// Collect top contact layers
for (int layer_nr = 1; layer_nr < contact_nodes.size(); layer_nr++)
{
if (!contact_nodes[layer_nr].empty())
for (int i = 0; i < support_roof_layers + z_distance_top_layers + 1; i++) {
if (layer_nr - i > 0) {
bounds.push_back(layer_nr - i);
layer_heights[layer_nr - i].first = m_object->get_layer(layer_nr - i)->print_z;
layer_heights[layer_nr - i].second = m_object->get_layer(layer_nr - i)->height;
}
else {
break;
}
}
}
std::set<int> s(bounds.begin(), bounds.end());
bounds.assign(s.begin(), s.end());
for (size_t idx_extreme = 0; idx_extreme < bounds.size(); idx_extreme++) {
int extr2_layer_nr = bounds[idx_extreme];
coordf_t extr2z = m_object->get_layer(extr2_layer_nr)->bottom_z();
int extr1_layer_nr = idx_extreme == 0 ? -1 : bounds[idx_extreme - 1];
coordf_t extr1z = idx_extreme == 0 ? 0.f : m_object->get_layer(extr1_layer_nr)->print_z;
coordf_t dist = extr2z - extr1z;
// Insert intermediate layers.
size_t n_layers_extra = size_t(ceil(dist / (m_slicing_params.max_suport_layer_height + EPSILON)));
int actual_internel_layers = extr2_layer_nr - extr1_layer_nr - 1;
int extr_layers_left = extr2_layer_nr - extr1_layer_nr - n_layers_extra - 1;
if (n_layers_extra < 1)
continue;
coordf_t step = dist / coordf_t(n_layers_extra);
coordf_t print_z = extr1z + step;
assert(step >= layer_height - EPSILON);
for (int layer_nr = extr1_layer_nr + 1; layer_nr < extr2_layer_nr; layer_nr++) {
// if (curr_layer_nodes.empty()) continue;
if (std::abs(print_z - m_object->get_layer(layer_nr)->print_z) < step / 2 + EPSILON || extr_layers_left < 1) {
layer_heights[layer_nr].first = print_z;
layer_heights[layer_nr].second = step;
print_z += step;
}
else {
// can't clear curr_layer_nodes, or the model will have empty layers
layer_heights[layer_nr].first = 0.0;
layer_heights[layer_nr].second = 0.0;
extr_layers_left--;
}
}
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
// export all print_z and layer height into .txt
std::ofstream layer_heights_out;
layer_heights_out.open("./SVG/layer_heights_out.txt");
//layer_heights_out.open("layer_heights_out.txt");
if (layer_heights_out.is_open()) {
for (int i = 0; i < layer_heights.size(); i++) {
layer_heights_out << layer_heights[i].first << " " << layer_heights[i].second << std::endl;
}
layer_heights_out.close();
}
// check bounds
if (1)
{
std::ofstream bounds_out;
bounds_out.open("bounds.txt");
if (bounds_out.is_open()) {
for (int i = 0; i < bounds.size(); i++) {
bounds_out << bounds[i] << std::endl;
}
}
}
#endif
return layer_heights;
}
void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::Node*>>& contact_nodes)
{
const PrintObjectConfig &config = m_object->config();
@ -3118,6 +3267,16 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
BOOST_LOG_TRIVIAL(info) << "avg_node_per_layer=" << avg_node_per_layer << ", nodes_angle=" << nodes_angle;
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
std::ofstream contact_nodes_out;
contact_nodes_out.open("./SVG/contact_nodes.txt");
if (contact_nodes_out.is_open()) {
for (int i = 0; i < contact_nodes.size(); i++) {
if (!contact_nodes[i].empty())
contact_nodes_out << i << std::endl;
}
}
#endif // SUPPORT_TREE_DEBUG_TO_SVG
}
void TreeSupport::insert_dropped_node(std::vector<Node*>& nodes_layer, Node* p_node)

View file

@ -170,7 +170,7 @@ public:
struct LineHash {
size_t operator()(const Line& line) const {
return (std::hash<coord_t>()(line.a(0)) ^ std::hash<coord_t>()(line.b(1))) * 102 +
(std::hash<coord_t>()(line.a(0)) ^ std::hash<coord_t>()(line.b(1))) * 10222;
(std::hash<coord_t>()(line.a(1)) ^ std::hash<coord_t>()(line.b(0))) * 10222;
}
};
@ -401,6 +401,12 @@ private:
void adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes);
/*! BBS: MusangKing: maximum layer height
* \brief Optimize the generation of tree support by pre-planning the layer_heights
*
*/
std::vector<std::pair<coordf_t, coordf_t>> plan_layer_heights(std::vector<std::vector<Node*>>& contact_nodes);
/*!
* \brief Creates points where support contacts the model.
*

View file

@ -1405,7 +1405,7 @@ bool bbl_calc_md5(std::string &filename, std::string &md5_out)
unsigned char digest[16];
MD5_CTX ctx;
MD5_Init(&ctx);
boost::filesystem::ifstream ifs(filename, std::ios::binary);
boost::nowide::ifstream ifs(filename, std::ios::binary);
std::string buf(64 * 1024, 0);
const std::size_t & size = boost::filesystem::file_size(filename);
std::size_t left_size = size;

View file

@ -41,11 +41,7 @@ export LD_LIBRARY_PATH="\$DIR/bin"
# FIXME: BambuStudio segfault workarounds
# 1) BambuStudio will segfault on systems where locale info is not as expected (i.e. Holo-ISO arch-based distro)
# 2) BambuStudio will segfault with a boost logging error if ~/.config/BambuStudio doesn't exist on first run
export LC_ALL=C
# FIXME: BambuStudio doesn't respect dark mode; use GTK_THEME workaround from sigxcpu76 │
export GTK_THEME=Adwaita:light
mkdir -p \${HOME}/.config/BambuStudio/ 2> /dev/null
exec "\$DIR/bin/@SLIC3R_APP_CMD@" "\$@"
EOF

View file

@ -64,7 +64,7 @@ void AMSMaterialsSetting::create()
m_clrData->SetChooseFull(true);
m_clrData->SetChooseAlpha(false);
m_clr_picker = new Button(this, "", "");
m_clr_picker = new Button(this, wxEmptyString, wxEmptyString, wxBU_AUTODRAW);
m_clr_picker->SetCanFocus(false);
m_clr_picker->SetSize(FromDIP(50), FromDIP(25));
m_clr_picker->SetMinSize(wxSize(FromDIP(50), FromDIP(25)));
@ -364,7 +364,12 @@ void AMSMaterialsSetting::on_clr_picker(wxCommandEvent & event)
show_flag = true;
if (clr_dialog->ShowModal() == wxID_OK) {
m_clrData = &(clr_dialog->GetColourData());
m_clr_picker->SetBackgroundColor(m_clrData->GetColour());
m_clr_picker->SetBackgroundColor(wxColour(
m_clrData->GetColour().Red(),
m_clrData->GetColour().Green(),
m_clrData->GetColour().Blue(),
254
));
}
}
@ -374,13 +379,19 @@ bool AMSMaterialsSetting::Show(bool show)
m_button_confirm->SetMinSize(AMS_MATERIALS_SETTING_BUTTON_SIZE);
m_input_nozzle_max->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20)));
m_input_nozzle_min->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20)));
m_clr_picker->SetBackgroundColour(m_clr_picker->GetParent()->GetBackgroundColour());
}
return DPIDialog::Show(show);
}
void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_min, wxString temp_max)
{
m_clr_picker->SetBackgroundColor(m_clrData->GetColour());
m_clr_picker->SetBackgroundColor(wxColour(
m_clrData->GetColour().Red(),
m_clrData->GetColour().Green(),
m_clrData->GetColour().Blue(),
254
));
if (!m_is_third) {
m_button_confirm->Hide();

View file

@ -83,7 +83,7 @@ protected:
Button * m_button_confirm;
wxStaticText* m_tip_readonly;
Button * m_button_close;
Button * m_clr_picker;
Button * m_clr_picker;
wxColourData * m_clrData;
#ifdef __APPLE__
wxComboBox *m_comboBox_filament_mac;

View file

@ -200,6 +200,11 @@ void AMSSetting::create()
m_panel_img->Layout();
m_sizer_img->Fit(m_panel_img);
m_sizer_remain_block = new wxBoxSizer(wxVERTICAL);
m_sizer_remain_block->Add(m_sizer_remain, 0, wxEXPAND | wxTOP, FromDIP(8));
m_sizer_remain_block->Add(0, 0, 0, wxTOP, 8);
m_sizer_remain_block->Add(m_sizer_remain_tip, 0, wxLEFT, 18);
m_sizer_remain_block->Add(0, 0, 0, wxTOP, 15);
m_sizerl_body->Add(m_sizer_Insert_material, 0, wxEXPAND, 0);
m_sizerl_body->Add(0, 0, 0, wxTOP, 8);
@ -209,10 +214,7 @@ void AMSSetting::create()
m_sizerl_body->Add(0, 0, 0, wxTOP, 8);
m_sizerl_body->Add(m_sizer_starting_tip, 0, wxLEFT, 18);
m_sizerl_body->Add(0, 0, 0, wxTOP, 15);
m_sizerl_body->Add(m_sizer_remain, 0, wxEXPAND | wxTOP, FromDIP(8));
m_sizerl_body->Add(0, 0, 0, wxTOP, 8);
m_sizerl_body->Add(m_sizer_remain_tip, 0, wxLEFT, 18);
m_sizerl_body->Add(0, 0, 0, wxTOP, 15);
m_sizerl_body->Add(m_sizer_remain_block, 0, wxEXPAND, 0);
m_sizerl_body->Add(m_sizer_switch_filament, 0, wxEXPAND | wxTOP, FromDIP(8));
m_sizerl_body->Add(0, 0, 0, wxTOP, 8);
m_sizerl_body->Add(m_sizer_switch_filament_tip, 0, wxLEFT, 18);
@ -231,6 +233,17 @@ void AMSSetting::create()
this->Centre(wxBOTH);
wxGetApp().UpdateDlgDarkUI(this);
Bind(wxEVT_SHOW, [this](auto& e) {
if (this->IsShown()) {
if (ams_support_remain) {
m_sizer_remain_block->Show(true);
}
else {
m_sizer_remain_block->Show(false);
}
}
});
}
void AMSSetting::update_insert_material_read_mode(bool selected)

View file

@ -39,6 +39,7 @@ public:
wxString append_title(wxString text);
wxStaticText *append_text(wxString text);
MachineObject *obj{nullptr};
bool ams_support_remain{false};
int ams_id { 0 };
protected:
@ -72,6 +73,7 @@ protected:
wxBoxSizer *m_sizer_starting_tip_inline;
wxBoxSizer *m_sizer_remain_inline;
wxBoxSizer *m_sizer_switch_filament_inline;
wxBoxSizer *m_sizer_remain_block;
};
}} // namespace Slic3r::GUI

View file

@ -456,7 +456,9 @@ void AuFile::on_set_cover()
{
if (wxGetApp().plater()->model().model_info == nullptr) { wxGetApp().plater()->model().model_info = std::make_shared<ModelInfo>(); }
wxGetApp().plater()->model().model_info->cover_file = m_file_name.ToStdString();
fs::path path(into_path(m_file_name));
wxGetApp().plater()->model().model_info->cover_file = path.string();
//wxGetApp().plater()->model().model_info->cover_file = m_file_name.ToStdString();
auto full_path = m_file_path.branch_path();
auto full_root_path = full_path.branch_path();
@ -696,7 +698,8 @@ void AuFolderPanel::update_cover()
if (wxGetApp().plater()->model().model_info != nullptr) {
for (auto i = 0; i < m_aufiles_list.GetCount(); i++) {
AuFiles *aufile = m_aufiles_list[i];
if (wxGetApp().plater()->model().model_info->cover_file == aufile->file->m_file_name) {
if (wxString::FromUTF8(wxGetApp().plater()->model().model_info->cover_file) == aufile->file->m_file_name) {
aufile->file->set_cover(true);
} else {
aufile->file->set_cover(false);

View file

@ -271,6 +271,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
}
double sparse_infill_density = config->option<ConfigOptionPercent>("sparse_infill_density")->value;
auto timelapse_type = config->opt_enum<TimelapseType>("timelapse_type");
if (config->opt_bool("spiral_mode") &&
! (config->opt_int("wall_loops") == 1 &&
@ -279,12 +280,12 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
! config->opt_bool("enable_support") &&
config->opt_int("enforce_support_layers") == 0 &&
config->opt_bool("ensure_vertical_shell_thickness") &&
! config->opt_bool("detect_thin_wall")))
! config->opt_bool("detect_thin_wall") &&
config->opt_enum<TimelapseType>("timelapse_type") == TimelapseType::tlTraditional))
{
wxString msg_text = _(L("Spiral mode only works when wall loops is 1, \n"
"support is disabled, top shell layers is 0 and sparse infill density is 0\n"));
wxString msg_text = _(L("Spiral mode only works when wall loops is 1, support is disabled, top shell layers is 0, sparse infill density is 0 and timelapse type is traditional"));
if (is_global_config)
msg_text += "\n" + _(L("Change these settings automatically? \n"
msg_text += "\n\n" + _(L("Change these settings automatically? \n"
"Yes - Change these settings and enable spiral mode automatically\n"
"No - Give up using spiral mode this time"));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "",
@ -301,7 +302,9 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
new_conf.set_key_value("enforce_support_layers", new ConfigOptionInt(0));
new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(true));
new_conf.set_key_value("detect_thin_wall", new ConfigOptionBool(false));
new_conf.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
sparse_infill_density = 0;
timelapse_type = TimelapseType::tlTraditional;
support = false;
}
else {
@ -310,6 +313,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
apply(config, &new_conf);
if (cb_value_change) {
cb_value_change("sparse_infill_density", sparse_infill_density);
cb_value_change("timelapse_type", timelapse_type);
if (!support)
cb_value_change("enable_support", false);
}

View file

@ -1259,6 +1259,29 @@ bool MachineObject::is_recording()
return camera_recording;
}
void MachineObject::parse_version_func()
{
auto ota_version = module_vers.find("ota");
if (printer_type == "BL-P001" ||
printer_type == "BL-P002") {
if (ota_version != module_vers.end()) {
if (ota_version->second.sw_ver.compare("01.01.01.00") <= 0) {
ams_support_remain = false;
ams_support_auto_switch_filament_flag = false;
is_xcam_buildplate_supported = false;
xcam_support_recovery_step_loss = false;
is_support_send_to_sdcard = false;
} else {
ams_support_remain = true;
ams_support_auto_switch_filament_flag = true;
is_xcam_buildplate_supported = true;
xcam_support_recovery_step_loss = true;
is_support_send_to_sdcard = true;
}
}
}
}
int MachineObject::command_get_version(bool with_retry)
{
BOOST_LOG_TRIVIAL(info) << "command_get_version";
@ -1990,9 +2013,15 @@ bool MachineObject::is_function_supported(PrinterFunction func)
func_name = "FUNC_AI_MONITORING";
break;
case FUNC_BUILDPLATE_MARKER_DETECT:
parse_version_func();
if (!is_xcam_buildplate_supported)
return false;
func_name = "FUNC_BUILDPLATE_MARKER_DETECT";
break;
case FUNC_AUTO_RECOVERY_STEP_LOSS:
parse_version_func();
if (!xcam_support_recovery_step_loss)
return false;
func_name = "FUNC_AUTO_RECOVERY_STEP_LOSS";
break;
case FUNC_FLOW_CALIBRATION:
@ -2026,9 +2055,15 @@ bool MachineObject::is_function_supported(PrinterFunction func)
func_name = "FUNC_ALTER_RESOLUTION";
break;
case FUNC_SEND_TO_SDCARD:
parse_version_func();
if (!is_support_send_to_sdcard)
return false;
func_name = "FUNC_SEND_TO_SDCARD";
break;
case FUNC_AUTO_SWITCH_FILAMENT:
parse_version_func();
if (!ams_support_auto_switch_filament_flag)
return false;
func_name = "FUNC_AUTO_SWITCH_FILAMENT";
break;
case FUNC_VIRTUAL_CAMERA:
@ -2615,6 +2650,9 @@ int MachineObject::parse_json(std::string payload)
else {
if (jj["xcam"].contains("buildplate_marker_detector")) {
xcam_buildplate_marker_detector = jj["xcam"]["buildplate_marker_detector"].get<bool>();
is_xcam_buildplate_supported = true;
} else {
is_xcam_buildplate_supported = false;
}
}
}
@ -2874,6 +2912,8 @@ int MachineObject::parse_json(std::string payload)
}
if (tray_it->contains("remain")) {
curr_tray->remain = (*tray_it)["remain"].get<int>();
} else {
curr_tray->remain = -1;
}
try {
if (!ams_id.empty() && !curr_tray->id.empty()) {
@ -3021,6 +3061,7 @@ int MachineObject::parse_json(std::string payload)
ver_info.hw_ver = (*it)["hw_ver"].get<std::string>();
module_vers.emplace(ver_info.name, ver_info);
}
parse_version_func();
bool get_version_result = true;
if (j["info"].contains("result"))
if (j["info"]["result"].get<std::string>() == "fail")

View file

@ -423,8 +423,10 @@ public:
bool ams_insert_flag { false };
bool ams_power_on_flag { false };
bool ams_calibrate_remain_flag { false };
bool ams_support_auto_switch_filament_flag { true };
bool ams_auto_switch_filament_flag { false };
bool ams_support_use_ams { false };
bool ams_support_remain { true };
int ams_humidity;
int ams_user_setting_hold_count = 0;
AmsStatusMain ams_status_main;
@ -579,8 +581,10 @@ public:
bool xcam_ai_monitoring{ false };
int xcam_ai_monitoring_hold_count = 0;
std::string xcam_ai_monitoring_sensitivity;
bool is_xcam_buildplate_supported { true };
bool xcam_buildplate_marker_detector{ false };
int xcam_buildplate_marker_hold_count = 0;
bool xcam_support_recovery_step_loss { true };
bool xcam_auto_recovery_step_loss{ false };
int xcam_auto_recovery_hold_count = 0;
int ams_print_option_count = 0;
@ -588,6 +592,7 @@ public:
/* sdcard */
MachineObject::SdcardState sdcard_state { NO_SDCARD };
MachineObject::SdcardState get_sdcard_state();
bool is_support_send_to_sdcard { true };
/* HMS */
std::vector<HMSItem> hms_list;
@ -622,6 +627,8 @@ public:
MachineObject(NetworkAgent* agent, std::string name, std::string id, std::string ip);
~MachineObject();
void parse_version_func();
/* command commands */
int command_get_version(bool with_retry = true);
int command_request_push_all();

View file

@ -1699,7 +1699,7 @@ void GUI_App::init_networking_callbacks()
wxCommandEvent event(EVT_CONNECT_LAN_MODE_PRINT);
if (obj) {
if (obj->is_lan_mode_printer()) {
if (state == ConnectStatus::ConnectStatusOk) {
obj->command_request_push_all();
@ -1892,6 +1892,9 @@ void GUI_App::init_app_config()
if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() )
dir = wxFileName::GetHomeDir() + wxS("/.config");
set_data_dir((dir + "/" + GetAppName()).ToUTF8().data());
boost::filesystem::path data_dir_path(data_dir());
if (!boost::filesystem::exists(data_dir_path))
boost::filesystem::create_directory(data_dir_path);
#endif
} else {
m_datadir_redefined = true;
@ -2729,7 +2732,7 @@ void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool ju
/*if (m_is_dark_mode != dark_mode() )
m_is_dark_mode = dark_mode();*/
if (m_is_dark_mode) {
auto original_col = window->GetBackgroundColour();

View file

@ -201,7 +201,7 @@ void GridCellFilamentsEditor::BeginEdit(int row, int col, wxGrid* grid)
{
// This event handler is needed to properly dismiss the editor when the popup is closed
m_control->Bind(wxEVT_COMBOBOX_CLOSEUP, &GridCellFilamentsEditor::OnComboCloseUp, this);
evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
evtHandler = static_cast<wxGridCellEditorEvtHandler*>(m_control->GetEventHandler());
}
// Don't immediately end if we get a kill focus event within BeginEdit
@ -403,7 +403,7 @@ void GridCellChoiceEditor::BeginEdit(int row, int col, wxGrid *grid)
if (m_control) {
// This event handler is needed to properly dismiss the editor when the popup is closed
m_control->Bind(wxEVT_COMBOBOX_CLOSEUP, &GridCellChoiceEditor::OnComboCloseUp, this);
evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
evtHandler = static_cast<wxGridCellEditorEvtHandler*>(m_control->GetEventHandler());
}
// Don't immediately end if we get a kill focus event within BeginEdit

View file

@ -8,6 +8,7 @@
#include "MsgDialog.hpp"
#include "DownloadProgressDialog.hpp"
#include <boost/filesystem/string_file.hpp>
#undef pid_t
#include <boost/process.hpp>
#ifdef __WIN32__

View file

@ -1198,6 +1198,28 @@ std::vector<int> PartPlate::get_extruders() const
return plate_extruders;
}
std::vector<int> PartPlate::get_used_extruders()
{
std::vector<int> used_extruders;
// if gcode.3mf file
if (m_model->objects.empty()) {
for (int i = 0; i < slice_filaments_info.size(); i++) {
used_extruders.push_back(slice_filaments_info[i].id + 1);
}
return used_extruders;
}
GCodeProcessorResult* result = get_slice_result();
if (!result)
return used_extruders;
PrintEstimatedStatistics& ps = result->print_statistics;
for (auto it = ps.volumes_per_extruder.begin(); it != ps.volumes_per_extruder.end(); it++) {
used_extruders.push_back(it->first + 1);
}
return used_extruders;
}
Vec3d PartPlate::estimate_wipe_tower_size(const double w, const double wipe_volume) const
{
Vec3d wipe_tower_size;

View file

@ -259,6 +259,7 @@ public:
Vec3d get_origin() { return m_origin; }
Vec3d estimate_wipe_tower_size(const double w, const double wipe_volume) const;
std::vector<int> get_extruders() const;
std::vector<int> get_used_extruders();
/* instance related operations*/
//judge whether instance is bound in plate or not

View file

@ -2930,7 +2930,7 @@ void SelectMachineDialog::set_default()
}
// material info
auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_extruders();
auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders();
BitmapCache bmcache;
MaterialHash::iterator iter = m_materialList.begin();

View file

@ -2707,7 +2707,7 @@ void Selection::paste_objects_from_clipboard()
auto start_offset = in_current ? src_object->instances.front()->get_offset() : plate->get_build_volume().center();
auto point_offset = start_offset - start_point;
auto empty_cell = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({start_point(0), start_point(1)}, {bbox.size()(0)+1, bbox.size()(1)+1});
displacement = {empty_cell.x() + point_offset.x(), empty_cell.y() + point_offset.y(), start_point(2)};
displacement = {empty_cell.x() + point_offset.x(), empty_cell.y() + point_offset.y(), start_offset(2)};
}
for (ModelInstance* inst : dst_object->instances)

View file

@ -1807,6 +1807,7 @@ void StatusPanel::update_ams(MachineObject *obj)
// update obj in sub dlg
if (m_ams_setting_dlg) {
m_ams_setting_dlg->obj = obj;
if (obj && m_ams_setting_dlg->IsShown()) {
m_ams_setting_dlg->update_insert_material_read_mode(obj->ams_insert_flag);
m_ams_setting_dlg->update_starting_read_mode(obj->ams_power_on_flag);
@ -2445,6 +2446,7 @@ void StatusPanel::on_ams_setting_click(SimpleEvent &event)
try {
int ams_id_int = atoi(ams_id.c_str());
m_ams_setting_dlg->ams_id = ams_id_int;
m_ams_setting_dlg->ams_support_remain = obj->ams_support_remain;
m_ams_setting_dlg->Show();
} catch (...) {
;

View file

@ -4,9 +4,13 @@
#include <wx/webviewarchivehandler.h>
#include <wx/webviewfshandler.h>
#if wxUSE_WEBVIEW_EDGE
#include <wx/msw/webview_edge.h>
#endif
#include <wx/uri.h>
#if defined(__WIN32__) || defined(__WXMAC__)
#include "wx/private/jsscriptwrapper.h"
#endif
#ifdef __WIN32__
#include "../WebView2.h"

View file

@ -33,6 +33,7 @@
#include <cstdint> // uint8_t
#include <ctype.h> // ::tolower, ::toupper
#include <cwctype> // ::towlower
#include <cstring> // memcpy
#include <cstdio>

View file

@ -9,6 +9,7 @@
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/string_file.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/log/trivial.hpp>