Gcode文件切断处理,其他优化

This commit is contained in:
cjw 2025-06-26 09:01:39 +08:00
parent 02ef64b26a
commit e1f2dc9b4e
16 changed files with 586 additions and 40 deletions

View File

@ -60,15 +60,16 @@ namespace Slic3r {
{
Polylines polylines_out;
Polygon_t polygon;
//BoundingBox bounding_box = surface->expolygon.contour.bounding_box();
{
Points points = surface->expolygon.contour.points;
if (points.size()<=20) {
return polylines_out;
double area = surface->expolygon.contour.area();
//>e+08
if (area < 9000000000) {
return polylines_out;
}
Points points = surface->expolygon.contour.points;
Point first = points[0];
points.push_back(first);
//Polygon outPolygon = bounding_box.polygon();
std::vector<Point_t> outerBoundary;
outerBoundary.reserve(points.size());
for (Point one : points) {
@ -80,14 +81,12 @@ namespace Slic3r {
bg::append(polygon.outer(), outerBoundary);
}
//std::vector<Point_t> innerBoundary;
{
Polygons inPolygons = surface->expolygon.holes;
for (Polygon one : inPolygons) {
/*if (one.points.size() >= 97) {
return polylines_out;
}*/
//if (one.points.size() >= 97) {
// return polylines_out;
//}
Ring innerRing;
innerRing.reserve(one.points.size() + 1);
Points points = one.points;
@ -104,21 +103,17 @@ namespace Slic3r {
}
this->polygon = polygon;
auto abc = float(scale_(this->overlap - 0.5 * this->spacing));
/* auto abc = float(scale_(this->overlap - 0.5 * this->spacing));
if (abc < 0) {
abc = -abc;
}
//this->offset = abc/ 1000000.0;
this->offset = abc;*/
this->offset = 40000;
printTree();
int size = ringNodes.begin()->second.size();
//第一个桥接边
int b_size = bridges.size();
BridgeMap bm = bridges[0];
IdIndex parent(1, 1);
//遍历
traverseRing(findNode(bm.from_ii), parent, bm.from, bm.from2, true);
//outputPaths();
Point_t last = { bm.from.x(),bm.from.y() };
path.emplace_back(last);
@ -732,6 +727,11 @@ void Bridge::generateRings() {
//清空
nodeHandles.clear();
if (!offsetNodes.empty()) {
if (offsetNodes.size() == 2) {
if (bg::within(offsetNodes[0].ring, offsetNodes[1].ring)) {
break;
}
}
//重填
nodeHandles.insert(nodeHandles.end(), offsetNodes.begin(), offsetNodes.end());
}

View File

@ -17,7 +17,7 @@
#include "FillFloatingConcentric.hpp"
#define NARROW_INFILL_AREA_THRESHOLD 3
#define SLIC3R_DEBUG_SLICE_PROCESSING
//#define SLIC3R_DEBUG_SLICE_PROCESSING
namespace Slic3r {
@ -459,10 +459,92 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
void export_group_fills_to_svg(const char* path, const std::vector<SurfaceFill>& fills)
{
std::string basename = std::move(path);
size_t pos = basename.find(".svg");
if (pos != std::string::npos) {
basename.replace(pos, 4, "-");
}
BoundingBox bbox;
for (const auto& fill : fills)
for (const auto& expoly : fill.expolygons)
int i = 1;
//int fillSize = fills.size();
//if (fillSize>3) {
// std::cout << basename << std::endl;
//}
for (const auto& fill : fills) {
int j = 1;
std::string filename = basename + std::to_string(i) + ".txt";
std::ofstream outfile(filename, std::ios_base::app);
for (const auto& expoly : fill.expolygons) {
{
Points points = expoly.contour.points;
outfile << "//**********Out**********\n";
outfile << " std::vector<sf::Vertex> outPoint" << j << ";\n";
for (Point one : points) {
double x = one.x();
double y = one.y();
outfile << "outPoint" << j << ".emplace_back(sf::Vertex(\n";
outfile << "sf::Vector2f(static_cast<double>(" << x << "/ 10000.0 + 200),\n";
outfile << "static_cast<double>(" << y << "/ 10000.0 + 200)),sf::Color::Red));\n";
}
}
{
Polygons inPolygons = expoly.holes;
int k = 1;
for (Polygon one : inPolygons) {
Points points = one.points;
outfile << "//**********In**********\n";
outfile << " std::vector<sf::Vertex> inPoint" << k << ";\n";
for (Point two : points) {
double x = two.x();
double y = two.y();
outfile << "inPoint" << k << ".emplace_back(sf::Vertex(\n";
outfile << "sf::Vector2f(static_cast<double>(" << x << "/ 10000.0 + 200),\n";
outfile << "static_cast<double>(" << y << "/ 10000.0 + 200)),sf::Color::Red));\n";
}
k++;
}
}
outfile << "window.draw(outPoint" << j << ".data(), " << "outPoint" << j << ".size(), sf::LineStrip);\n";
j++;
bbox.merge(get_extents(expoly));
}
outfile.close();
i++;
}
//for (const auto& fill : fills) {
// int j = 1;
// for (const auto& expoly : fill.expolygons) {
// std::string filename = basename + std::to_string(i) + ".txt";
// std::ofstream outfile(filename, std::ios_base::app);
// {
// Points points = expoly.contour.points;
// outfile << "//**********Out" << j << "**********\n";
// for (Point one : points) {
// double x = one.x();
// double y = one.y();
// outfile << "Point(" << x << "," << y << "),\n";
// }
// }
// {
// Polygons inPolygons = expoly.holes;
// int k = 1;
// for (Polygon one : inPolygons) {
// Points points = one.points;
// outfile << "//**********In" << k << "**********\n";
// for (Point two : points) {
// double x = two.x();
// double y = two.y();
// outfile << "Point(" << x << "," << y << "),\n";
// }
// k++;
// }
// }
// outfile.close();
// bbox.merge(get_extents(expoly));
// j++;
// }
// i++;
//}
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min(0), bbox.max(1));
bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
@ -474,6 +556,7 @@ void export_group_fills_to_svg(const char* path, const std::vector<SurfaceFill>&
svg.draw(expoly, surface_type_to_color_name(fill.surface.surface_type), transparency);
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}
#endif
@ -490,14 +573,12 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
std::vector<SurfaceFill> surface_fills = group_fills(*this);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
const auto resolution = this->object()->print()->config().resolution.value;
//static int iRun = 0;
std::string base_path;
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
static int iRun = 0;
const char* tempDir = debug_out_path("Layer-fill_surfaces-10_fill-final-%d.svg", iRun++).c_str();
base_path = tempDir;
export_group_fills_to_svg(tempDir, surface_fills);
std::string filename = debug_out_path("Layer-fill_surfaces-10_fill-final-%d.svg", iRun++);
export_group_fills_to_svg(filename.c_str(), surface_fills);
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
@ -621,17 +702,87 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
if (surface_fill.params.pattern == ipGrid || surface_fill.params.pattern == ipFloatingConcentric)
params.can_reverse = false;
LayerRegion* layerm = this->m_regions[surface_fill.region_id];
/*if (surface_fill.params.pattern == ipFiberSpiral) {
ExPolygons polygons = surface_fill.expolygons;
int size = polygons.size();
if (size > 1) {
//寻找并记录最大的图形
int bigSize = 0;
for (int i = 1; i < size; i++) {
ExPolygon one = polygons[bigSize];
Polygon onePolygon = one.contour;
Points& points = onePolygon.points;
Point first = points[0];
points.push_back(first);
ExPolygon two = polygons[i];
Polygon twoPolygon = two.contour;
for (Point point : twoPolygon.points) {
if (!onePolygon.contains(point)) {
bigSize = i;
break;
}
}
}
ExPolygon& bigPolygon = polygons[bigSize];
//删除最大的图形
polygons.erase(polygons.begin() + bigSize);
Polygons lastHoles;
for (ExPolygon other : polygons) {
Polygons bigPolygons = bigPolygon.holes;
Points points = other.contour.points;
for (Polygon bigHole : bigPolygons) {
bool isIn = true;
for (Point point : points) {
if (!bigHole.contains(point)) {
isIn = false;
break;
}
}
if (isIn) {
polygons_append(lastHoles, other.holes);
//lastHoles.emplace_back(other.holes);
}
}
}
Polygons& bigPolygons = bigPolygon.holes;
bigPolygons.clear();
bigPolygons.emplace_back(lastHoles);
surface_fill.surface.expolygon = std::move(bigPolygon);
f->fill_surface_extrusion(&surface_fill.surface,
params,
m_regions[surface_fill.region_id]->fills.entities);
}
else{
for (ExPolygon& expoly : surface_fill.expolygons) {
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = { expoly }, ApplySafetyOffset::Yes);
if (params.symmetric_infill_y_axis) {
params.symmetric_y_axis = f->extended_object_bounding_box().center().x();
expoly.symmetric_y(params.symmetric_y_axis);
}
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
f->spacing = surface_fill.params.spacing;
surface_fill.surface.expolygon = std::move(expoly);
// BBS: make fill
f->fill_surface_extrusion(&surface_fill.surface,
params,
m_regions[surface_fill.region_id]->fills.entities);
}
}
}
else {*/
for (ExPolygon& expoly : surface_fill.expolygons) {
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = { expoly }, ApplySafetyOffset::Yes);
if (params.symmetric_infill_y_axis) {
params.symmetric_y_axis = f->extended_object_bounding_box().center().x();
expoly.symmetric_y(params.symmetric_y_axis);
}
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
f->spacing = surface_fill.params.spacing;
surface_fill.surface.expolygon = std::move(expoly);
// BBS: make fill
f->fill_surface_extrusion(&surface_fill.surface,
params,

View File

@ -19,7 +19,7 @@
#include "../Flow.hpp"
#include "../ExtrusionEntity.hpp"
#include "../ExtrusionEntityCollection.hpp"
//测试一下啊
namespace Slic3r {
class Surface;

View File

@ -147,10 +147,14 @@ ExPolygons Layer::merged(float offset_scaled) const
// Here the perimeters are created cummulatively for all layer regions sharing the same parameters influencing the perimeters.
// The perimeter paths and the thin fills (ExtrusionEntityCollection) are assigned to the first compatible layer region.
// The resulting fill surface is split back among the originating regions.
//这里,为共享影响周长的相同参数的所有层区域累积创建周长。
//周界路径和薄填充ExtrusionEntityCollection被指定给第一个兼容的图层区域。
//生成的填充曲面在原始区域之间被拆分。
void Layer::make_perimeters()
{
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id();
// keep track of regions whose perimeters we have already generated
//跟踪我们已经生成边界的区域
std::vector<unsigned char> done(m_regions.size(), false);
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm)
@ -167,6 +171,7 @@ void Layer::make_perimeters()
const PrintRegionConfig &config = (*layerm)->region().config();
// find compatible regions
//查找兼容区域
LayerRegionPtrs layerms;
layerms.push_back(*layerm);
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it)
@ -208,9 +213,11 @@ void Layer::make_perimeters()
} else {
SurfaceCollection new_slices;
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
//使用填充率最高的区域因为下面的make_perimeters函数根据填充的存在决定间隙填充。
LayerRegion *layerm_config = layerms.front();
{
// group slices (surfaces) according to number of extra perimeters
//根据额外周长的数量对切片(表面)进行分组
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
for (LayerRegion *layerm : layerms) {
for (const Surface &surface : layerm->slices.surfaces)
@ -219,6 +226,7 @@ void Layer::make_perimeters()
layerm_config = layerm;
}
// merge the surfaces assigned to each group
//合并分配给每个组的曲面
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
new_slices.append(offset_ex(surfaces_with_extra_perimeters.second, ClipperSafetyOffset), surfaces_with_extra_perimeters.second.front());
}
@ -230,6 +238,7 @@ void Layer::make_perimeters()
layerm_config->make_perimeters(new_slices, &fill_surfaces, &fill_no_overlap, this->loop_nodes);
// assign fill_surfaces to each layer
//为每一层指定fill_surfaces
if (!fill_surfaces.surfaces.empty()) {
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
// Separate the fill surfaces.

View File

@ -1197,20 +1197,24 @@ static Polygons to_polygons_with_flag(const ExPolygon& src, const bool contour_f
void PerimeterGenerator::process_classic()
{
// other perimeters
//其他周界
m_mm3_per_mm = this->perimeter_flow.mm3_per_mm();
coord_t perimeter_width = this->perimeter_flow.scaled_width();
coord_t perimeter_spacing = this->perimeter_flow.scaled_spacing();
// external perimeters
//外部边界
m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm();
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width();
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
// overhang perimeters
//悬垂周界
m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
// solid infill
//实心填充物
coord_t solid_infill_spacing = this->solid_infill_flow.scaled_spacing();
// Calculate the minimum required spacing between two adjacent traces.
@ -1223,19 +1227,25 @@ void PerimeterGenerator::process_classic()
// which is the spacing between external and internal, which is not correct
// and would make the collapsing (thus the details resolution) dependent on
// internal flow which is unrelated.
//计算两条相邻迹线之间所需的最小间距。
//这应该等于标称流量间距,但我们进行了一些容差实验,以避免在某些挤压可能起作用时触发中轴。环路仍然由整个流量间距隔开;这仅适用于折叠零件。
//对于ext_min_spaceing我们使用为两个相邻外部循环计算的ext_perimeter_spaceing这是正确的方法而不是使用ext_perimeter_spaceng2后者是外部和内部之间的间距这是不正确的会使坍缩即细节分辨率依赖于无关的内部流。
coord_t min_spacing = coord_t(perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE));
coord_t ext_min_spacing = coord_t(ext_perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE));
bool has_gap_fill = this->config->gap_infill_speed.get_at(get_extruder_index(*print_config, this->config->wall_filament - 1)) > 0;
// BBS: this flow is for smaller external perimeter for small area
//BBS此流量适用于小面积的较小外部周长
coord_t ext_min_spacing_smaller = coord_t(ext_perimeter_spacing * (1 - SMALLER_EXT_INSET_OVERLAP_TOLERANCE));
this->smaller_ext_perimeter_flow = this->ext_perimeter_flow;
// BBS: to be checked
//BBS待检查
this->smaller_ext_perimeter_flow = this->smaller_ext_perimeter_flow.with_width(SCALING_FACTOR *
(ext_perimeter_width - 0.5 * SMALLER_EXT_INSET_OVERLAP_TOLERANCE * ext_perimeter_spacing));
m_ext_mm3_per_mm_smaller_width = this->smaller_ext_perimeter_flow.mm3_per_mm();
// prepare grown lower layer slices for overhang detection
//准备生长的下层切片用于悬垂检测
m_lower_polygons_series = generate_lower_polygons_series(this->perimeter_flow.width());
m_lower_overhang_dist_boundary = dist_boundary(this->perimeter_flow.width());
if (ext_perimeter_width == perimeter_width){
@ -1249,10 +1259,12 @@ void PerimeterGenerator::process_classic()
m_smaller_external_overhang_dist_boundary = dist_boundary(this->smaller_ext_perimeter_flow.width());
// we need to process each island separately because we might have different
// extra perimeters for each one
//我们需要分别处理每个岛屿,因为每个岛屿可能有不同的额外边界
// BBS: don't simplify too much which influence arc fitting when export gcode if arc_fitting is enabled
//BBS如果启用了arc_fitting导出gcode时不要过于简化这会影响圆弧拟合
double surface_simplify_resolution = (print_config->enable_arc_fitting && this->config->fuzzy_skin == FuzzySkinType::None) ? 0.2 * m_scaled_resolution : m_scaled_resolution;
//BBS: reorder the surface to reduce the travel time
//BBS重新排序表面以减少旅行时间
ExPolygons surface_exp;
for (const Surface &surface : this->slices->surfaces)
surface_exp.push_back(surface.expolygon);
@ -1260,8 +1272,10 @@ void PerimeterGenerator::process_classic()
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
//BBS: set the topmost and bottom most layer to be one wall
//BBS将最顶层和最底层设置为一面墙
if (loop_number > 0 && ((this->object_config->top_one_wall_type != TopOneWallType::None && this->upper_slices == nullptr) || (this->object_config->only_one_wall_first_layer && layer_id == 0)))
loop_number = 0;
@ -1291,36 +1305,46 @@ void PerimeterGenerator::process_classic()
std::vector<NodeContour> outwall_paths;
if (loop_number >= 0) {
// In case no perimeters are to be generated, loop_number will equal to -1.
//如果不生成周界loop_number将等于-1。
std::vector<PerimeterGeneratorLoops> contours(loop_number+1); // depth => loops
std::vector<PerimeterGeneratorLoops> holes(loop_number+1); // depth => loops
ThickPolylines thin_walls;
// we loop one time more than needed in order to find gaps after the last perimeter was applied
for (int i = 0;; ++ i) { // outer loop is 0
//在应用最后一个周长后,我们比需要多循环一次,以找到间隙
for (int i = 0;; ++ i) { // outer loop is 0 //外环为0
// Calculate next onion shell of perimeters.
//计算下一个洋葱壳的周长。
ExPolygons offsets;
ExPolygons offsets_with_smaller_width;
if (i == 0) {
// look for thin walls
//寻找薄壁
if (this->config->detect_thin_wall) {
// the minimum thickness of a single loop is:
//单个环的最小厚度为:
// ext_width/2 + ext_spacing/2 + spacing/2 + width/2
offsets = offset2_ex(last,
-float(ext_perimeter_width / 2. + ext_min_spacing / 2. - 1),
+float(ext_min_spacing / 2. - 1));
// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
// (actually, something larger than that still may exist due to mitering or other causes)
//下面的offset2确保@thin_walls中几乎没有任何东西比$min_width窄
//(实际上,由于斜接或其他原因,可能仍然存在比这更大的东西)
coord_t min_width = coord_t(scale_(this->ext_perimeter_flow.nozzle_diameter() / 3));
ExPolygons expp = opening_ex(
// medial axis requires non-overlapping geometry
//中轴需要不重叠的几何形状
diff_ex(last, offset(offsets, float(ext_perimeter_width / 2.) + ClipperSafetyOffset)),
float(min_width / 2.));
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
//我们薄壁区域的最大厚度等于单个环的最小厚度
for (ExPolygon &ex : expp)
ex.medial_axis(min_width, ext_perimeter_width + ext_perimeter_spacing2, &thin_walls);
} else {
coord_t ext_perimeter_smaller_width = this->smaller_ext_perimeter_flow.scaled_width();
for (const ExPolygon& expolygon : last) {
// BBS: judge whether it's narrow but not too long island which is hard to place two line
//BBS判断它是否狭窄但不太长难以放置两条线
ExPolygons expolys;
expolys.push_back(expolygon);
ExPolygons offset_result = offset2_ex(expolys,
@ -1329,11 +1353,13 @@ void PerimeterGenerator::process_classic()
if (offset_result.empty() &&
expolygon.area() < (double)(ext_perimeter_width + ext_min_spacing_smaller) * scale_(narrow_loop_length_threshold)) {
// BBS: for narrow external loop, use smaller line width
//BBS对于窄的外环使用较小的线宽
ExPolygons temp_result = offset_ex(expolygon, -float(ext_perimeter_smaller_width / 2.));
offsets_with_smaller_width.insert(offsets_with_smaller_width.end(), temp_result.begin(), temp_result.end());
}
else {
//BBS: for not narrow loop, use normal external perimeter line width
//BBS对于不窄的环路使用正常的外周长线宽
ExPolygons temp_result = offset_ex(expolygon, -float(ext_perimeter_width / 2.));
offsets.insert(offsets.end(), temp_result.begin(), temp_result.end());
}
@ -1341,18 +1367,22 @@ void PerimeterGenerator::process_classic()
}
if (m_spiral_vase && (offsets.size() > 1 || offsets_with_smaller_width.size() > 1)) {
// Remove all but the largest area polygon.
//删除除最大面积多边形外的所有多边形。
keep_largest_contour_only(offsets);
//BBS
if (offsets.empty())
//BBS: only have small width loop, then keep the largest in spiral vase mode
//BBS只有小宽度的环然后在螺旋花瓶模式下保持最大
keep_largest_contour_only(offsets_with_smaller_width);
else
//BBS: have large area, clean the small width loop
//BBS面积大清洁小宽度环
offsets_with_smaller_width.clear();
}
} else {
//FIXME Is this offset correct if the line width of the inner perimeters differs
// from the line width of the infill?
//FIXME如果内周长的线宽与填充物的线宽不同则此偏移是否正确
coord_t distance = (i == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
//BBS
//offsets = this->config->thin_walls ?
@ -1372,26 +1402,32 @@ void PerimeterGenerator::process_classic()
//BBS: For internal perimeter, we should "enable" thin wall strategy in which offset2 is used to
// remove too closed line, so that gap fill can be used for such internal narrow area in following
// handling.
//BBS对于内部周界我们应该“启用”薄壁策略其中使用offset2来删除过于封闭的线以便在后续处理中可以对这种内部狭窄区域使用间隙填充。
offsets = offset2_ex(last,
-float(distance + min_spacing / 2. - 1.),
float(min_spacing / 2. - 1.));
// look for gaps
//寻找差距
if (has_gap_fill)
// not using safety offset here would "detect" very narrow gaps
// (but still long enough to escape the area threshold) that gap fill
// won't be able to fill but we'd still remove from infill area
//这里不使用安全偏移将“检测”非常窄的间隙(但仍然足够长以逃脱面积阈值),间隙填充将无法填充,但我们仍会从填充区域中删除
append(gaps, diff_ex(
offset(last, - float(0.5 * distance)),
offset(offsets, float(0.5 * distance + 10)))); // safety offset
}
if (offsets.empty() && offsets_with_smaller_width.empty()) {
// Store the number of loops actually generated.
//存储实际生成的循环数。
loop_number = i - 1;
// No region left to be filled in.
//没有剩余区域需要填写。
last.clear();
break;
} else if (i > loop_number) {
// If i > loop_number, we were looking just for gaps.
//如果i>loop_number我们只是在寻找缺口。
break;
}
{
@ -1403,6 +1439,8 @@ void PerimeterGenerator::process_classic()
// outer contour may overlap with itself.
//FIXME evaluate the overlaps, annotate each point with an overlap depth,
// compensate for the depth of intersection.
//外轮廓可能与内轮廓重叠,内轮廓可能与另一个内轮廓重叠。外轮廓可能与其自身重叠。
//FIXME评估重叠用重叠深度注释每个点补偿相交深度。
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, fuzzify_contours, false, counter_circle_compensation));
if (!expolygon.holes.empty()) {
holes[i].reserve(holes[i].size() + expolygon.holes.size());
@ -1412,8 +1450,10 @@ void PerimeterGenerator::process_classic()
}
//BBS: save perimeter loop which use smaller width
//BBS节省使用较小宽度的周长环
if (i == 0) {
//store outer wall
//仓库外墙
if (print_config->z_direction_outwall_speed_continuous) {
// not loop
for (const ThickPolyline &polyline : thin_walls) {
@ -1457,55 +1497,71 @@ void PerimeterGenerator::process_classic()
//BBS: refer to superslicer
//store surface for top infill if only_one_wall_top
//BBS参考超级链接
//如果只有one_wall_top则存储顶部填充的曲面
if (i == 0 && i != loop_number && this->object_config->top_one_wall_type == TopOneWallType::Alltop && this->upper_slices != NULL) {
//split the polygons with top/not_top
//get the offset from solid surface anchor
//使用top/not_top分割多边形获取实体曲面锚点的偏移量
coord_t offset_top_surface = scale_(1.5 * (config->wall_loops.value == 0 ? 0. : unscaled(double(ext_perimeter_width + perimeter_spacing * int(int(config->wall_loops.value) - int(1))))));
// if possible, try to not push the extra perimeters inside the sparse infill
//如果可能的话,尽量不要将额外的周界推到稀疏填充物内
if (offset_top_surface > 0.9 * (config->wall_loops.value <= 1 ? 0. : (perimeter_spacing * (config->wall_loops.value - 1))))
offset_top_surface -= coord_t(0.9 * (config->wall_loops.value <= 1 ? 0. : (perimeter_spacing * (config->wall_loops.value - 1))));
else
offset_top_surface = 0;
//don't takes into account too thin areas
//不要考虑太薄的区域
double min_width_top_surface = (this->object_config->top_area_threshold / 100) * std::max(ext_perimeter_spacing / 2.0, perimeter_width / 2.0);
//BBS: get boungding box of last
//BBS获取最后一个弹匣
BoundingBox last_box = get_extents(last);
last_box.offset(SCALED_EPSILON);
// BBS: get the Polygons upper the polygon this layer
//BBS将多边形置于该层多边形的上方
Polygons upper_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->upper_slices, last_box);
upper_polygons_series_clipped = offset(upper_polygons_series_clipped, min_width_top_surface);
//set the clip to a virtual "second perimeter"
//将剪辑设置为虚拟的“第二边界”
fill_clip = offset_ex(last, -double(ext_perimeter_spacing));
// get the real top surface
//获得真实的顶面
ExPolygons grown_lower_slices;
ExPolygons bridge_checker;
ExPolygons top_polygons = diff_ex(last, upper_polygons_series_clipped, ApplySafetyOffset::Yes);
//get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the min_width_top_surface we removed a bit before)
//从“真实顶部”获取非顶面但通过external_fill_margin放大以及我们之前删除的min_width_top_surface
ExPolygons temp_gap = diff_ex(top_polygons, fill_clip);
ExPolygons inner_polygons = diff_ex(last,
offset_ex(top_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)),
ApplySafetyOffset::Yes);
// BBS: check whether surface be bridge or not
//BBS检查表面是否桥接
if (this->lower_slices != NULL) {
// BBS: get the Polygons below the polygon this layer
//BBS获取该层多边形下方的多边形
Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->lower_slices, last_box);
double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width)));
bridge_checker = offset_ex(diff_ex(last, lower_polygons_series_clipped, ApplySafetyOffset::Yes), 1.5 * bridge_offset);
// BBS: Check which piece the bridge belongs to. If the bridge has a connection with the non-top area, it should belong to the non-top area, otherwise it should belong to the top area to get a better surface.
//BBS检查桥架属于哪一块。如果桥架与非顶部区域有连接则应属于非顶部区域否则应属于顶部区域以获得更好的表面。
if (!bridge_checker.empty() && !intersection_ex(bridge_checker, inner_polygons).empty())
inner_polygons = union_ex(inner_polygons, bridge_checker);
}
// get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly the polygons to fill.
//通过使用innerpolygons而不是upperslice来获得放大的顶面并对其进行剪裁使其恰好是要填充的多边形。
top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes);
// increase by half peri the inner space to fill the frontier between last and stored.
//将内部空间增加一半,以填充最后和存储之间的边界。
top_fills = union_ex(top_fills, top_polygons);
//set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap.
//将夹子设置为外墙但通过fille_extrusion_width/2返回内部以确保即使有100%的重叠,挤出也不会向外。
double infill_spacing_unscaled = this->config->sparse_infill_line_width.value;
fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2));
last = intersection_ex(inner_polygons, last);
@ -1527,17 +1583,22 @@ void PerimeterGenerator::process_classic()
if (i == loop_number && (! has_gap_fill || this->config->sparse_infill_density.value == 0)) {
// The last run of this loop is executed to collect gaps for gap fill.
// As the gap fill is either disabled or not
//执行此循环的最后一次运行是为了收集间隙以进行间隙填充。
//由于间隙填充功能已禁用或未禁用
break;
}
}
// nest loops: holes first
//嵌套循环:先打孔
for (int d = 0; d <= loop_number; ++ d) {
PerimeterGeneratorLoops &holes_d = holes[d];
// loop through all holes having depth == d
//穿过深度==d的所有孔
for (int i = 0; i < (int)holes_d.size(); ++ i) {
const PerimeterGeneratorLoop &loop = holes_d[i];
// find the hole loop that contains this one, if any
//找到包含此孔的孔环(如果有的话)
for (int t = d + 1; t <= loop_number; ++ t) {
for (int j = 0; j < (int)holes[t].size(); ++ j) {
PerimeterGeneratorLoop &candidate_parent = holes[t][j];
@ -1550,6 +1611,7 @@ void PerimeterGenerator::process_classic()
}
}
// if no hole contains this hole, find the contour loop that contains it
//如果没有孔包含此孔,请找到包含它的轮廓环
for (int t = loop_number; t >= 0; -- t) {
for (int j = 0; j < (int)contours[t].size(); ++ j) {
PerimeterGeneratorLoop &candidate_parent = contours[t][j];
@ -1565,12 +1627,15 @@ void PerimeterGenerator::process_classic()
}
}
// nest contour loops
//嵌套轮廓环
for (int d = loop_number; d >= 1; -- d) {
PerimeterGeneratorLoops &contours_d = contours[d];
// loop through all contours having depth == d
//遍历深度==d的所有轮廓
for (int i = 0; i < (int)contours_d.size(); ++ i) {
const PerimeterGeneratorLoop &loop = contours_d[i];
// find the contour loop that contains it
//找到包含它的轮廓环
for (int t = d - 1; t >= 0; -- t) {
for (size_t j = 0; j < contours[t].size(); ++ j) {
PerimeterGeneratorLoop &candidate_parent = contours[t][j];
@ -1586,19 +1651,24 @@ void PerimeterGenerator::process_classic()
}
}
// at this point, all loops should be in contours[0]
//此时,所有循环都应位于等高线[0]中
ExtrusionEntityCollection entities = traverse_loops(*this, contours.front(), thin_walls);
// if brim will be printed, reverse the order of perimeters so that
// we continue inwards after having finished the brim
// TODO: add test for perimeter order
//如果要打印帽沿,请颠倒周长的顺序,以便在完成帽沿后继续向内
//TODO:添加周界顺序测试
bool is_outer_wall_first =
this->object_config->wall_sequence == WallSequence::OuterInner;
if (is_outer_wall_first ||
//BBS: always print outer wall first when there indeed has brim.
//BBS确实有帽沿的时候一定要先打印外墙。
(this->layer_id == 0 &&
this->object_config->brim_type == BrimType::btOuterOnly &&
this->object_config->brim_width.value > 0))
entities.reverse();
//BBS. adjust wall generate seq
//BBS。调整墙生成序列
else if (this->object_config->wall_sequence == WallSequence::InnerOuterInner)
if (entities.entities.size() > 1){
int second_wall = -1;
@ -1620,6 +1690,7 @@ void PerimeterGenerator::process_classic()
}
//BBS: add node for loops
//BBS为循环添加节点
if (!outwall_paths.empty() && this->layer_id > 0) {
entities.loop_node_range.first = this->loop_nodes->size();
if (outwall_paths.size() == 1) {
@ -1635,6 +1706,7 @@ void PerimeterGenerator::process_classic()
matched.resize(outwall_paths.size(), false);
for (int entity_idx = 0; entity_idx < entities.entities.size(); ++entity_idx) {
//skip inner wall
//跳过内壁
if(entities.entities[entity_idx]->role() == erPerimeter)
continue;
@ -1661,22 +1733,26 @@ void PerimeterGenerator::process_classic()
// append perimeters for this slice as a collection
//将此切片的周长作为集合附加
if (! entities.empty())
this->loops->append(entities);
} // for each loop of an island
} // for each loop of an island//对于岛屿的每个环路
// fill gaps
//填补空白
if (! gaps.empty()) {
// collapse
double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE);
double max = 2. * perimeter_spacing;
ExPolygons gaps_ex = diff_ex(
//FIXME offset2 would be enough and cheaper.
//FIXME offset2就足够了而且更便宜。
opening_ex(gaps, float(min / 2.)),
offset2_ex(gaps, - float(max / 2.), float(max / 2. + ClipperSafetyOffset)));
ThickPolylines polylines;
for (ExPolygon& ex : gaps_ex) {
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
//BBS使用DP简化来避免重复点并加速中轴计算。
ex.douglas_peucker(surface_simplify_resolution);
ex.medial_axis(min, max, &polylines);
}
@ -1697,6 +1773,7 @@ void PerimeterGenerator::process_classic()
}
#endif
// OrcaSlicer: filter out tiny gap fills
//OrcaSlicer过滤掉微小的缝隙填充物
polylines.erase(std::remove_if(polylines.begin(), polylines.end(), [&](const ThickPolyline &p) {
return p.length()< scale_(this->config->filter_out_gap_fill.value);
}), polylines.end());
@ -1709,9 +1786,12 @@ void PerimeterGenerator::process_classic()
Growing actual extrusions ensures that gaps not filled by medial axis
are not subtracted from fill surfaces (they might be too short gaps
that medial axis skips but infill might join with other infill regions
and use zigzag). */
and use zigzag).
diff
使齿*/
//FIXME Vojtech: This grows by a rounded extrusion width, not by line spacing,
// therefore it may cover the area, but no the volume.
//FIXME Vojtech这是通过圆形挤压宽度而不是线间距来增长的因此它可能会覆盖整个区域但不会覆盖整个体积。
last = diff_ex(last, gap_fill.polygons_covered_by_width(10.f));
this->gap_fill->append(std::move(gap_fill.entities));
}
@ -1721,6 +1801,7 @@ void PerimeterGenerator::process_classic()
// 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 inset =
(loop_number < 0) ? 0 :
(loop_number == 0) ?
@ -1729,17 +1810,20 @@ void PerimeterGenerator::process_classic()
// two or more loops?
perimeter_spacing / 2;
// only apply infill overlap if we actually have one perimeter
//只有当我们实际上只有一个周长时,才应用填充重叠
coord_t infill_peri_overlap = 0;
if (inset > 0) {
infill_peri_overlap = coord_t(scale_(this->config->infill_wall_overlap.get_abs_value(unscale<double>(inset + solid_infill_spacing / 2))));
inset -= infill_peri_overlap;
}
// simplify infill contours according to resolution
//根据分辨率简化填充轮廓
Polygons pp;
for (ExPolygon &ex : last)
ex.simplify_p(m_scaled_resolution, &pp);
ExPolygons not_filled_exp = union_ex(pp);
// collapse too narrow infill areas
//塌陷过窄的填充区域
coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
ExPolygons infill_exp = offset2_ex(
@ -1748,6 +1832,7 @@ void PerimeterGenerator::process_classic()
float(min_perimeter_infill_spacing / 2.));
// append infill areas to fill_surfaces
//if any top_fills, grow them by ext_perimeter_spacing/2 to have the real un-anchored fill
//如果有任何top_fill则将填充区域附加到fill_surfaces将其按ext_perimeter_space/2增长以获得真正的未锚定填充
ExPolygons top_infill_exp = intersection_ex(fill_clip, offset_ex(top_fills, double(ext_perimeter_spacing / 2)));
if (!top_fills.empty()) {
infill_exp = union_ex(infill_exp, offset_ex(top_infill_exp, double(infill_peri_overlap)));
@ -1755,6 +1840,7 @@ void PerimeterGenerator::process_classic()
this->fill_surfaces->append(infill_exp, stInternal);
// BBS: get the no-overlap infill expolygons
//BBS获取无重叠填充表达式
{
ExPolygons polyWithoutOverlap;
if (min_perimeter_infill_spacing / 2 > infill_peri_overlap)
@ -1771,7 +1857,7 @@ void PerimeterGenerator::process_classic()
this->fill_no_overlap->insert(this->fill_no_overlap->end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
}
} // for each island
} // for each island//每个岛屿
}
//BBS:

View File

@ -8,6 +8,7 @@
#include "MultiPoint.hpp"
#include "Polyline.hpp"
namespace Slic3r {
class Polygon;

View File

@ -132,7 +132,7 @@ PresetBundle& PresetBundle::operator=(const PresetBundle &rhs)
sla_materials = rhs.sla_materials;
printers = rhs.printers;
physical_printers = rhs.physical_printers;
configs = rhs.configs;
configs = rhs.configs;
filament_presets = rhs.filament_presets;
project_config = rhs.project_config;
@ -145,7 +145,7 @@ PresetBundle& PresetBundle::operator=(const PresetBundle &rhs)
filaments .update_vendor_ptrs_after_copy(this->vendors);
sla_materials.update_vendor_ptrs_after_copy(this->vendors);
printers .update_vendor_ptrs_after_copy(this->vendors);
configs.update_vendor_ptrs_after_copy(this->vendors);
configs .update_vendor_ptrs_after_copy(this->vendors);
return *this;
}
@ -1437,13 +1437,13 @@ std::vector<std::string> PresetBundle::merge_presets(PresetBundle &&other)
std::vector<std::string> duplicate_filaments = this->filaments .merge_presets(std::move(other.filaments), this->vendors);
std::vector<std::string> duplicate_sla_materials = this->sla_materials.merge_presets(std::move(other.sla_materials), this->vendors);
std::vector<std::string> duplicate_printers = this->printers .merge_presets(std::move(other.printers), this->vendors);
std::vector<std::string> duplicate_configs = this->configs.merge_presets(std::move(other.configs), this->vendors);
std::vector<std::string> duplicate_configs = this->configs .merge_presets(std::move(other.configs), this->vendors);
append(this->obsolete_presets.prints, std::move(other.obsolete_presets.prints));
append(this->obsolete_presets.sla_prints, std::move(other.obsolete_presets.sla_prints));
append(this->obsolete_presets.filaments, std::move(other.obsolete_presets.filaments));
append(this->obsolete_presets.sla_materials, std::move(other.obsolete_presets.sla_materials));
append(this->obsolete_presets.printers, std::move(other.obsolete_presets.printers));
append(this->obsolete_presets.configs, std::move(other.obsolete_presets.configs));
append(this->obsolete_presets.configs, std::move(other.obsolete_presets.configs));
append(duplicate_prints, std::move(duplicate_sla_prints));
append(duplicate_prints, std::move(duplicate_filaments));
append(duplicate_prints, std::move(duplicate_sla_materials));
@ -1459,14 +1459,13 @@ void PresetBundle::update_system_maps()
this->filaments .update_map_system_profile_renamed();
this->sla_materials.update_map_system_profile_renamed();
this->printers .update_map_system_profile_renamed();
this->configs .update_map_system_profile_renamed();
this->prints .update_map_alias_to_profile_name();
this->sla_prints .update_map_alias_to_profile_name();
this->filaments .update_map_alias_to_profile_name();
this->sla_materials.update_map_alias_to_profile_name();
this->configs.update_map_alias_to_profile_name();
this->configs .update_map_alias_to_profile_name();
}
static inline std::string remove_ini_suffix(const std::string &name)
@ -1537,7 +1536,8 @@ void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::
type == Preset::TYPE_SLA_PRINT ? sla_prints :
type == Preset::TYPE_FILAMENT ? filaments :
type == Preset::TYPE_SLA_MATERIAL ? sla_materials :
type == Preset::TYPE_CONFIG ? configs : printers;
type == Preset::TYPE_CONFIG ? configs :
printers;
// if we want to save just some from selected options
if (!unselected_options.empty()) {
@ -2452,6 +2452,7 @@ DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optio
{
DynamicPrintConfig out;
out.apply(FullPrintConfig::defaults());
out.apply(this->prints.get_edited_preset().config);
// Add the default filament preset to have the "filament_preset_id" defined.
out.apply(this->filaments.default_preset().config);
@ -4668,6 +4669,7 @@ void PresetBundle::set_default_suppressed(bool default_suppressed)
sla_prints.set_default_suppressed(default_suppressed);
sla_materials.set_default_suppressed(default_suppressed);
printers.set_default_suppressed(default_suppressed);
configs.set_default_suppressed(default_suppressed);
}
} // namespace Slic3r

View File

@ -1862,6 +1862,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("The material type of filament");
def->gui_type = ConfigOptionDef::GUIType::f_enum_open;
def->gui_flags = "show_value";
def->enum_values.push_back("CFC");
def->enum_values.push_back("PLA");
def->enum_values.push_back("ABS");
def->enum_values.push_back("ASA");

View File

@ -318,9 +318,13 @@ std::vector<std::set<int>> PrintObject::detect_extruder_geometric_unprintables()
// 1) Merges typed region slices into stInternal type.
// 2) Increases an "extra perimeters" counter at region slices where needed.
// 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal).
//1将类型化的区域切片合并为stInternal类型。
//2在需要的区域切片处增加“额外周长”计数器。
//3生成周界、间隙填充和填充区域stInternal类型的填充区域
void PrintObject::make_perimeters()
{
// prerequisites
//先决条件
this->slice();
if (! this->set_started(posPerimeters))
@ -330,6 +334,7 @@ void PrintObject::make_perimeters()
BOOST_LOG_TRIVIAL(info) << "Generating walls..." << log_memory_info();
// Revert the typed slices into untyped slices.
//将类型化切片还原为非类型化切片。
if (m_typed_slices) {
for (Layer *layer : m_layers) {
layer->restore_untyped_slices();
@ -345,6 +350,8 @@ void PrintObject::make_perimeters()
// but we don't generate any extra perimeter if fill density is zero, as they would be floating
// inside the object - infill_only_where_needed should be the method of choice for printing
// hollow objects
//将每一层与下面的一层进行比较,并标记需要额外内周的切片,如圆顶对象的顶部
//该算法确保至少有一个周长是重叠的,但如果填充密度为零,我们不会生成任何额外的周长,因为它们将漂浮在对象内部-仅填充,其中需要填充应该是打印空心对象的首选方法
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
const PrintRegion &region = this->printing_region(region_id);
//BBS: remove extra_perimeters, always false
@ -361,6 +368,7 @@ void PrintObject::make_perimeters()
const LayerRegion &upper_layerm = *m_layers[layer_idx+1]->get_region(region_id);
const Polygons upper_layerm_polygons = to_polygons(upper_layerm.slices.surfaces);
// Filter upper layer polygons in intersection_ppl by their bounding boxes?
//通过边界框过滤intersection_ppl中的上层多边形
// my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ];
const double total_loop_length = total_length(upper_layerm_polygons);
const coord_t perimeter_spacing = layerm.flow(frPerimeter).scaled_spacing();
@ -371,18 +379,23 @@ void PrintObject::make_perimeters()
for (Surface &slice : layerm.slices.surfaces) {
for (;;) {
// compute the total thickness of perimeters
//计算周界的总厚度
const coord_t perimeters_thickness = ext_perimeter_width/2 + ext_perimeter_spacing/2
+ (region.config().wall_loops-1 + slice.extra_perimeters) * perimeter_spacing;
// define a critical area where we don't want the upper slice to fall into
// (it should either lay over our perimeters or outside this area)
//定义一个关键区域,我们不希望上部切片落入其中
//(它应该位于我们的周边或该区域之外)
const coord_t critical_area_depth = coord_t(perimeter_spacing * 1.5);
const Polygons critical_area = diff(
offset(slice.expolygon, float(- perimeters_thickness)),
offset(slice.expolygon, float(- perimeters_thickness - critical_area_depth))
);
// check whether a portion of the upper slices falls inside the critical area
//检查上部切片的一部分是否落在临界区域内
const Polylines intersection = intersection_pl(to_polylines(upper_layerm_polygons), critical_area);
// only add an additional loop if at least 30% of the slice loop would benefit from it
//仅当切片循环的至少30%将从中受益时,才添加额外的循环
if (total_length(intersection) <= total_loop_length*0.3)
break;
/*
@ -437,6 +450,7 @@ void PrintObject::make_perimeters()
if (this->m_print->m_config.z_direction_outwall_speed_continuous) {
// BBS: get continuity of nodes
//BBS获取节点的连续性
BOOST_LOG_TRIVIAL(debug) << "Calculating perimeters connection in parallel - start";
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_layers.size()), [this](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
@ -464,6 +478,7 @@ void PrintObject::make_perimeters()
//write merged node to each perimeter
//将合并节点写入每个边界
BOOST_LOG_TRIVIAL(debug) << "Recrod cooling_node id for each extrusion in parallel - start";
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_layers.size()), [this](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {

View File

@ -46,6 +46,7 @@ LayerPtrs new_layers(
}
// Slice single triangle mesh.
//对单个三角形网格进行切片。
static std::vector<ExPolygons> slice_volume(
const ModelVolume &volume,
const std::vector<float> &zs,
@ -69,6 +70,8 @@ static std::vector<ExPolygons> slice_volume(
// Slice single triangle mesh.
// Filter the zs not inside the ranges. The ranges are closed at the bottom and open at the top, they are sorted lexicographically and non overlapping.
//对单个三角形网格进行切片。
//过滤不在范围内的zs。范围在底部是封闭的在顶部是开放的它们按字典顺序排列不重叠。
static std::vector<ExPolygons> slice_volume(
const ModelVolume &volume,
const std::vector<float> &z,
@ -80,6 +83,7 @@ static std::vector<ExPolygons> slice_volume(
if (! z.empty() && ! ranges.empty()) {
if (ranges.size() == 1 && z.front() >= ranges.front().first && z.back() < ranges.front().second) {
// All layers fit into a single range.
//所有层都适合一个范围。
out = slice_volume(volume, z, params, throw_on_cancel_callback);
} else {
std::vector<float> z_filtered;
@ -117,6 +121,10 @@ static inline bool model_volume_needs_slicing(const ModelVolume &mv)
// Apply closing radius.
// Apply positive XY compensation to ModelVolumeType::MODEL_PART and ModelVolumeType::PARAMETER_MODIFIER, not to ModelVolumeType::NEGATIVE_VOLUME.
// Apply contour simplification.
//切片可打印卷、负卷和修改器卷按ModelVolume:id排序。
//应用闭合半径。
//将正XY补偿应用于ModelVolumeType:MODEL_PART和ModelVolumeTypePARAMETERMODIFIER而不是应用于ModelVolumeType:NEGATIVE_VOLUME。
//应用轮廓简化。
static std::vector<VolumeSlices> slice_volumes_inner(
const PrintConfig &print_config,
const PrintObjectConfig &print_object_config,
@ -141,6 +149,8 @@ static std::vector<VolumeSlices> slice_volumes_inner(
params_base.trafo = object_trafo;
//BBS: 0.0025mm is safe enough to simplify the data to speed slicing up for high-resolution model.
//Also has on influence on arc fitting which has default resolution 0.0125mm.
//BBS:0.0025mm足够安全,可以简化数据,加快高分辨率模型的切片速度。
//对默认分辨率为0.0125mm的圆弧拟合也没有影响。
params_base.resolution = print_config.resolution <= 0.001 ? 0.0f : 0.0025;
switch (print_object_config.slicing_mode.value) {
case SlicingMode::Regular: params_base.mode = MeshSlicingParams::SlicingMode::Regular; break;
@ -155,6 +165,8 @@ static std::vector<VolumeSlices> slice_volumes_inner(
const bool is_mm_painted = num_extruders > 1 && std::any_of(model_volumes.cbegin(), model_volumes.cend(), [](const ModelVolume *mv) { return mv->is_mm_painted(); });
// BBS: don't do size compensation when slice volume.
// Will handle contour and hole size compensation seperately later.
//BBS切片时不要做尺寸补偿。
//稍后将分别处理轮廓和孔尺寸补偿。
//const auto extra_offset = is_mm_painted ? 0.f : std::max(0.f, float(print_object_config.xy_contour_compensation.value));
const auto extra_offset = 0.f;
@ -171,6 +183,8 @@ static std::vector<VolumeSlices> slice_volumes_inner(
params.mode = MeshSlicingParams::SlicingMode::PositiveLargestContour;
// Slice the bottom layers with SlicingMode::Regular.
// This needs to be in sync with LayerRegion::make_perimeters() spiral_mode!
//使用SlicingModeRegular对底层进行切片。
//这需要与LayerRegion:make_perimetersspiral_mode同步
const PrintRegionConfig &region_config = it->region->config();
params.slicing_mode_normal_below_layer = size_t(region_config.bottom_shell_layers.value);
for (; params.slicing_mode_normal_below_layer < zs.size() && zs[params.slicing_mode_normal_below_layer] < region_config.bottom_shell_thickness - EPSILON;
@ -245,6 +259,8 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
std::vector<VolumeSlices> &&volume_slices,
// If clipping is disabled, then ExPolygons produced by different volumes will never be merged, thus they will be allowed to overlap.
// It is up to the model designer to handle these overlaps.
//如果禁用剪裁则由不同体积生成的ExPolygon将永远不会合并因此它们将被允许重叠。
//由模型设计者来处理这些重叠。
const bool clip_multipart_objects,
const std::function<void()> &throw_on_cancel_callback)
{
@ -253,6 +269,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
std::vector<std::vector<ExPolygons>> slices_by_region(print_object_regions.all_regions.size(), std::vector<ExPolygons>(zs.size(), ExPolygons()));
// First shuffle slices into regions if there is no overlap with another region possible, collect zs of the complex cases.
//首先若并没有可能和另一个区域重叠则将切片洗牌到各个区域收集复杂案例的zs。
std::vector<std::pair<size_t, float>> zs_complex;
{
size_t z_idx = 0;
@ -285,6 +302,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
}
else if (idx_first_printable_region != -1) {
// Test for overlap with some other region.
//测试是否与其他区域重叠。
for (int idx_region2 = idx_first_printable_region; idx_region2 < idx_region; ++ idx_region2) {
const PrintObjectRegions::VolumeRegion &region2 = layer_range.volume_regions[idx_region2];
if (region2.bbox->min().z() <= z && region2.bbox->max().z() >= z && overlap_in_xy(*region.bbox, *region2.bbox)) {
@ -310,6 +328,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
}
// Second perform region clipping and assignment in parallel.
//其次,并行执行区域裁剪和分配。
if (! zs_complex.empty()) {
std::vector<std::vector<VolumeSlices*>> layer_ranges_regions_to_slices(print_object_regions.layer_ranges.size(), std::vector<VolumeSlices*>());
for (const PrintObjectRegions::LayerRangeRegions &layer_range : print_object_regions.layer_ranges) {
@ -325,9 +344,11 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
float z = zs_complex[range.begin()].second;
auto it_layer_range = layer_range_first(print_object_regions.layer_ranges, z);
// Per volume_regions slices at this Z height.
//按体积_区域在此Z高度处切片。
struct RegionSlice {
ExPolygons expolygons;
// Identifier of this region in PrintObjectRegions::all_regions
//PrintObjectRegions中此区域的标识符all_regions
int region_id;
ObjectID volume_id;
bool operator<(const RegionSlice &rhs) const {
@ -335,6 +356,8 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
bool rhs_empty = rhs.region_id < 0 || rhs.expolygons.empty();
// Sort the empty items to the end of the list.
// Sort by region_id & volume_id lexicographically.
//将空项目排序到列表末尾。
//按region_id和volume_id按字母顺序排序。
return ! this_empty && (rhs_empty || (this->region_id < rhs.region_id || (this->region_id == rhs.region_id && volume_id < volume_id)));
}
};
@ -375,6 +398,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
{
std::vector<VolumeSlices*> &layer_range_regions_to_slices = layer_ranges_regions_to_slices[it_layer_range - print_object_regions.layer_ranges.begin()];
// Per volume_regions slices at thiz Z height.
//按体积_区域在Z高度处切片。
temp_slices.clear();
temp_slices.reserve(layer_range.volume_regions.size());
for (VolumeSlices* &slices : layer_range_regions_to_slices) {
@ -399,12 +423,15 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
}
if (next_region_same_modifier)
// To be used in the following iteration.
//将在以下迭代中使用。
temp_slices[idx_region + 1].expolygons = std::move(source);
} else if ((region.model_volume->is_model_part() && clip_multipart_objects) || region.model_volume->is_negative_volume()) {
// Clip every non-zero region preceding it.
//剪切它前面的每个非零区域。
for (int idx_region2 = 0; idx_region2 < idx_region; ++ idx_region2)
if (! temp_slices[idx_region2].expolygons.empty()) {
// Skip trim_overlap for now, because it slow down the performace so much for some special cases
//暂时跳过trim_overlap因为在某些特殊情况下它会大大降低性能
#if 1
if (const PrintObjectRegions::VolumeRegion& region2 = layer_range.volume_regions[idx_region2];
!region2.model_volume->is_negative_volume() && overlap_in_xy(*region.bbox, *region2.bbox))
@ -422,12 +449,16 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
}
}
// Sort by region_id, push empty slices to the end.
//按region_id排序将空切片推到末尾。
std::sort(temp_slices.begin(), temp_slices.end());
// Remove the empty slices.
//移除空切片。
temp_slices.erase(std::find_if(temp_slices.begin(), temp_slices.end(), [](const auto &slice) { return slice.region_id == -1 || slice.expolygons.empty(); }), temp_slices.end());
// Merge slices and store them to the output.
//合并切片并将其存储到输出中。
for (int i = 0; i < int(temp_slices.size());) {
// Find a range of temp_slices with the same region_id.
//查找具有相同region_id的temp_slices范围。
int j = i;
bool merged = false;
ExPolygons &expolygons = temp_slices[i].expolygons;
@ -443,6 +474,8 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
// Don't unite the regions if ! clip_multipart_objects. In that case it is user's responsibility
// to handle region overlaps. Indeed, one may intentionally let the regions overlap to produce crossing perimeters
// for example.
//如果发生这种情况不要团结各地区clip_multipart_objects。在这种情况下这是用户的责任
//以处理区域重叠。事实上,例如,人们可能会故意让这些区域重叠以产生交叉边界。
if (merged && clip_multipart_objects)
expolygons = closing_ex(expolygons, float(scale_(EPSILON)));
slices_by_region[temp_slices[i].region_id][z_idx] = std::move(expolygons);
@ -788,11 +821,20 @@ void groupingVolumesForBrim(PrintObject* object, LayerPtrs& layers, int firstLay
// 5) Applies size compensation (offsets the slices in XY plane)
// 6) Replaces bad slices by the slices reconstructed from the upper/lower layer
// Resulting expolygons of layer regions are marked as Internal.
//由make_perimeters调用
//1决定层的Z位置
//2初始化层及其区域
//3分割对象网格
//4对修改器网格进行切片并根据修改器网格的切片对对象网格的切片进行重新分类
//5应用尺寸补偿偏移XY平面中的切片
//6用从上层/下层重建的切片替换坏切片
//层区域的扩展结果标记为内部。
void PrintObject::slice()
{
if (! this->set_started(posSlice))
return;
//BBS: add flag to reload scene for shell rendering
//BBS添加标志以重新加载场景进行shell渲染
m_print->set_status(5, L("Slicing mesh"), PrintBase::SlicingStatus::RELOAD_SCENE);
std::vector<coordf_t> layer_height_profile;
this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile);
@ -807,6 +849,7 @@ void PrintObject::slice()
#if 1
// Fix the model.
//FIXME is this the right place to do? It is done repeateadly at the UI and now here at the backend.
//FIXME是合适的地方吗它在UI上重复完成现在在后端完成。
std::string warning = fix_slicing_errors(this, m_layers, [this](){ m_print->throw_if_canceled(); }, firstLayerReplacedBy);
m_print->throw_if_canceled();
//BBS: send warning message to slicing callback
@ -818,9 +861,11 @@ void PrintObject::slice()
#endif
// BBS: the actual first layer slices stored in layers are re-sorted by volume group and will be used to generate brim
//BBS存储在层中的实际第一层切片按卷组重新排序并将用于生成边缘
groupingVolumesForBrim(this, m_layers, firstLayerReplacedBy);
// Update bounding boxes, back up raw slices of complex models.
//更新边界框,备份复杂模型的原始切片。
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this](const tbb::blocked_range<size_t>& range) {
@ -845,6 +890,7 @@ template<typename ThrowOnCancel>
static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCancel throw_on_cancel)
{
// Returns MMU segmentation based on painting in MMU segmentation gizmo
//MMU分割控件中基于绘画的MMU分割返回
std::vector<std::vector<ExPolygons>> segmentation = multi_material_segmentation_by_painting(print_object, throw_on_cancel);
assert(segmentation.size() == print_object.layer_count());
tbb::parallel_for(
@ -871,6 +917,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
it_layer_range = layer_range_next(layer_ranges, it_layer_range, layer->slice_z);
const PrintObjectRegions::LayerRangeRegions &layer_range = *it_layer_range;
// Gather per extruder expolygons.
//按照挤出机的规格进行收集。
by_extruder.assign(num_extruders, ByExtruder());
by_region.assign(layer->region_count(), ByRegion());
bool layer_split = false;
@ -886,6 +933,8 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
continue;
// Split LayerRegions by by_extruder regions.
// layer_range.painted_regions are sorted by extruder ID and parent PrintObject region ID.
//按by_extruder区域拆分图层区域。
//layer_range.painted_regions按挤出机ID和父打印对象区域ID排序。
auto it_painted_region = layer_range.painted_regions.begin();
for (int region_id = 0; region_id < int(layer->region_count()); ++ region_id)
if (LayerRegion &layerm = *layer->get_region(region_id); ! layerm.slices.surfaces.empty()) {
@ -893,25 +942,30 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
const BoundingBox bbox = get_extents(layerm.slices.surfaces);
assert(it_painted_region < layer_range.painted_regions.end());
// Find the first it_painted_region which overrides this region.
//找到覆盖此区域的第一个it_paoint_region。
for (; layer_range.volume_regions[it_painted_region->parent].region->print_object_region_id() < region_id; ++ it_painted_region)
assert(it_painted_region != layer_range.painted_regions.end());
assert(it_painted_region != layer_range.painted_regions.end());
assert(layer_range.volume_regions[it_painted_region->parent].region == &layerm.region());
// 1-based extruder ID
//1-基挤出机ID
bool self_trimmed = false;
int self_extruder_id = -1;
for (int extruder_id = 1; extruder_id <= int(by_extruder.size()); ++ extruder_id)
if (ByExtruder &segmented = by_extruder[extruder_id - 1]; segmented.bbox.defined && bbox.overlap(segmented.bbox)) {
// Find the target region.
//找到目标区域。
for (; int(it_painted_region->extruder_id) < extruder_id; ++ it_painted_region)
assert(it_painted_region != layer_range.painted_regions.end());
assert(layer_range.volume_regions[it_painted_region->parent].region == &layerm.region() && int(it_painted_region->extruder_id) == extruder_id);
//FIXME Don't trim by self, it is not reliable.
//FIXME不要自己修剪它不可靠。
if (&layerm.region() == it_painted_region->region) {
self_extruder_id = extruder_id;
continue;
}
// Steal from this region.
//从这个地区偷东西。
int target_region_id = it_painted_region->region->print_object_region_id();
ExPolygons stolen = intersection_ex(layerm.slices.surfaces, segmented.expolygons);
if (! stolen.empty()) {
@ -931,6 +985,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
}
if (! self_trimmed) {
// Trim slices of this LayerRegion with all the MMU regions.
//使用所有MMU区域修剪此LayerRegion的切片。
Polygons mine = to_polygons(std::move(layerm.slices.surfaces));
for (auto &segmented : by_extruder)
if (&segmented - by_extruder.data() + 1 != self_extruder_id && segmented.bbox.defined && bbox.overlap(segmented.bbox)) {
@ -943,6 +998,9 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
// (because of preprocessing of the input regions in multi-material segmentation). Therefore, subtraction from
// layerm.region() could produce a huge number of small unprintable regions for the model's base extruder.
// This could, on some models, produce bulges with the model's base color (#7109).
//过滤掉通过从layrm.region中减去多材质绘制区域而产生的无法打印的多边形。
//从多材质分割返回的ExPolygon与layem.region中的ExPolygons不完全匹配因为多材质分割中的输入区域进行了预处理。因此从layer.region中减去可能会为模型的基础挤出机产生大量无法打印的小区域。
//在某些型号上,这可能会产生与型号基础颜色相同的凸起(#7109
if (! mine.empty())
mine = opening(union_ex(mine), float(scale_(5 * EPSILON)), float(scale_(5 * EPSILON)));
if (! mine.empty()) {
@ -957,10 +1015,12 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
}
}
// Re-create Surfaces of LayerRegions.
//重新创建图层区域的曲面。
for (size_t region_id = 0; region_id < layer->region_count(); ++ region_id) {
ByRegion &src = by_region[region_id];
if (src.needs_merge)
// Multiple regions were merged into one.
//多个区域合并为一个。
src.expolygons = closing_ex(src.expolygons, float(scale_(10 * EPSILON)));
layer->get_region(region_id)->slices.set(std::move(src.expolygons), stInternal);
}
@ -978,6 +1038,15 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
// Resulting expolygons of layer regions are marked as Internal.
//
// this should be idempotent
//1决定层的Z位置
//2初始化层及其区域
//3分割对象网格
//4对修改器网格进行切片并根据修改器网格的切片对对象网格的切片进行重新分类
//5应用尺寸补偿偏移XY平面中的切片
//6用从上层/下层重建的切片替换坏切片
//层区域的扩展结果标记为内部。
//
//这应该是幂等的
void PrintObject::slice_volumes()
{
BOOST_LOG_TRIVIAL(info) << "Slicing volumes..." << log_memory_info();
@ -985,8 +1054,10 @@ void PrintObject::slice_volumes()
const auto throw_on_cancel_callback = std::function<void()>([print](){ print->throw_if_canceled(); });
// Clear old LayerRegions, allocate for new PrintRegions.
//清除旧的LayerRegions为新的PrintRegions分配。
for (Layer* layer : m_layers) {
//BBS: should delete all LayerRegionPtr to avoid memory leak
//BBS应删除所有LayerRegionPtr以避免内存泄漏
while (!layer->m_regions.empty()) {
if (layer->m_regions.back())
delete layer->m_regions.back();
@ -1010,6 +1081,11 @@ void PrintObject::slice_volumes()
//firstLayerObjSliceByVolume = findPartVolumes(objSliceByVolume, this->model_object()->volumes);
//groupingVolumes(objSliceByVolumeParts, firstLayerObjSliceByGroups, scaled_resolution);
//applyNegtiveVolumes(this->model_object()->volumes, objSliceByVolume, firstLayerObjSliceByGroups, scaled_resolution);
//BBS:“model_part”卷根据其连接进行分组
//const auto-scaled_resolution=scaled<double>(打印->config.reresolution.value
//firstLayerObjSliceByVolume=findPartVolumesobjSliceByVolume此->模型对象()->卷);
//分组卷objSliceByVolumeParts、firstLayerObjSliceByGroups、scaled_session
//applyNegativeVolumes此->模型对象()->卷、objSliceByVolume、firstLayerObjSliceByGroups、scaled_session
firstLayerObjSliceByVolume = objSliceByVolume;
std::vector<std::vector<ExPolygons>> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs,
@ -1037,12 +1113,15 @@ void PrintObject::slice_volumes()
m_print->throw_if_canceled();
// Is any ModelVolume MMU painted?
//是否有任何ModelVolume MMU涂漆
if (const auto& volumes = this->model_object()->volumes;
m_print->config().filament_diameter.size() > 1 && // BBS
std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume* v) { return !v->mmu_segmentation_facets.empty(); }) != volumes.end()) {
// If XY Size compensation is also enabled, notify the user that XY Size compensation
// would not be used because the object is multi-material painted.
//如果还启用了XY尺寸补偿请通知用户XY尺寸补偿
//不会使用,因为该对象是多材质绘制的。
if (m_config.xy_hole_compensation.value != 0.f || m_config.xy_contour_compensation.value != 0.f) {
this->active_step_add_warning(
PrintStateBase::WarningLevel::CRITICAL,
@ -1060,6 +1139,7 @@ void PrintObject::slice_volumes()
m_print->throw_if_canceled();
// SuperSlicer: filament shrink
//SuperSlicer长丝收缩
for (Layer *layer : m_layers) {
for (size_t i = 0; i < layer->region_count(); ++i) {
LayerRegion *region = layer->get_region(i);
@ -1079,16 +1159,20 @@ void PrintObject::slice_volumes()
BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin";
{
// Compensation value, scaled. Only applying the negative scaling here, as the positive scaling has already been applied during slicing.
//补偿值,按比例计算。此处仅应用负缩放,因为在切片过程中已经应用了正缩放。
const size_t num_extruders = print->config().filament_diameter.size();
const auto xy_hole_scaled = (num_extruders > 1 && this->is_mm_painted()) ? scaled<float>(0.f) : scaled<float>(m_config.xy_hole_compensation.value);
const auto xy_contour_scaled = (num_extruders > 1 && this->is_mm_painted()) ? scaled<float>(0.f) : scaled<float>(m_config.xy_contour_compensation.value);
const float elephant_foot_compensation_scaled = (m_config.raft_layers == 0) ?
// Only enable Elephant foot compensation if printing directly on the print bed.
//仅在直接在打印床上打印时启用象脚补偿。
float(scale_(m_config.elefant_foot_compensation.value)) :
0.f;
// Uncompensated slices for the first layer in case the Elephant foot compensation is applied.
//在应用象脚补偿的情况下,第一层的无补偿切片。
ExPolygons lslices_1st_layer;
//BBS: this part has been changed a lot to support seperated contour and hole size compensation
//BBS这部分已经做了很多更改以支持单独的轮廓和孔尺寸补偿
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this, xy_hole_scaled, xy_contour_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer](const tbb::blocked_range<size_t>& range) {
@ -1096,13 +1180,17 @@ void PrintObject::slice_volumes()
m_print->throw_if_canceled();
Layer *layer = m_layers[layer_id];
// Apply size compensation and perform clipping of multi-part objects.
//应用尺寸补偿并对多部分对象进行剪裁。
float elfoot = (layer_id == 0) ? elephant_foot_compensation_scaled : 0.f;
if (layer->m_regions.size() == 1) {
// Optimized version for a single region layer.
// Single region, growing or shrinking.
//针对单个区域层的优化版本。
//单一地区,增长或萎缩。
LayerRegion *layerm = layer->m_regions.front();
if (elfoot > 0) {
// Apply the elephant foot compensation and store the 1st layer slices without the Elephant foot compensation applied.
//应用象脚补偿,并存储未应用象脚赔偿的第一层切片。
lslices_1st_layer = to_expolygons(std::move(layerm->slices.surfaces));
if (xy_contour_scaled > 0 || xy_hole_scaled > 0) {
lslices_1st_layer = _shrink_contour_holes(std::max(0.f, xy_contour_scaled),
@ -1121,6 +1209,7 @@ void PrintObject::slice_volumes()
stInternal);
} else {
// Apply the XY contour and hole size compensation.
//应用XY轮廓和孔尺寸补偿。
if (xy_contour_scaled != 0.0f || xy_hole_scaled != 0.0f) {
ExPolygons expolygons = to_expolygons(std::move(layerm->slices.surfaces));
if (xy_contour_scaled > 0 || xy_hole_scaled > 0) {
@ -1143,12 +1232,15 @@ void PrintObject::slice_volumes()
if (max_growth > 0) {
//BBS: merge polygons because region can cut "holes".
//Then, cut them to give them again later to their region
//BBS合并多边形因为该区域可以切割“孔”。
//然后,把它们剪下来,稍后再送给它们所在的地区
merged_poly_for_holes_growing = layer->merged(float(SCALED_EPSILON));
merged_poly_for_holes_growing = _shrink_contour_holes(std::max(0.f, xy_contour_scaled),
std::max(0.f, xy_hole_scaled),
union_ex(merged_poly_for_holes_growing));
// BBS: clipping regions, priority is given to the first regions.
//BBS剪切区域优先剪切第一个区域。
Polygons processed;
for (size_t region_id = 0; region_id < layer->regions().size(); ++region_id) {
ExPolygons slices = to_expolygons(std::move(layer->m_regions[region_id]->slices.surfaces));
@ -1157,16 +1249,19 @@ void PrintObject::slice_volumes()
}
//BBS: Trim by the slices of already processed regions.
//BBS按已加工区域的切片进行修剪。
if (region_id > 0)
slices = diff_ex(to_polygons(std::move(slices)), processed);
if (region_id + 1 < layer->regions().size())
// Collect the already processed regions to trim the to be processed regions.
//收集已处理的区域以修剪待处理的区域。
polygons_append(processed, slices);
layer->m_regions[region_id]->slices.set(std::move(slices), stInternal);
}
}
if (min_growth < 0.f || elfoot > 0.f) {
// Apply the negative XY compensation. (the ones that is <0)
//应用负XY补偿。小于0的那些
ExPolygons trimming;
static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
if (elfoot > 0.f) {
@ -1181,8 +1276,10 @@ void PrintObject::slice_volumes()
std::min(0.f, xy_hole_scaled),
trimming);
//BBS: trim surfaces
//BBS修整表面
for (size_t region_id = 0; region_id < layer->regions().size(); ++region_id) {
// BBS: split trimming result by region
//BBS按地区划分修剪结果
ExPolygons contour_exp = to_expolygons(std::move(layer->regions()[region_id]->slices.surfaces));
layer->regions()[region_id]->slices.set(intersection_ex(contour_exp, to_polygons(trimming)), stInternal);
@ -1190,6 +1287,7 @@ void PrintObject::slice_volumes()
}
}
// Merge all regions' slices to get islands, chain them by a shortest path.
//合并所有区域的切片以获得岛屿,用最短路径将它们链接起来。
if (this->config().enable_circle_compensation)
layer->apply_auto_circle_compensation();
layer->make_slices();
@ -1198,9 +1296,13 @@ void PrintObject::slice_volumes()
if (elephant_foot_compensation_scaled > 0.f && ! m_layers.empty()) {
// The Elephant foot has been compensated, therefore the 1st layer's lslices are shrank with the Elephant foot compensation value.
// Store the uncompensated value there.
//大象脚已经得到补偿,因此第一层的切片缩小了大象脚补偿值。
//将未补偿的价值存储在那里。
assert(m_layers.front()->id() == 0);
//BBS: sort the lslices_1st_layer according to shortest path before saving
//Otherwise the travel of first layer would be mess.
//BBS保存前按最短路径对lslices_1st_layer进行排序
//否则,第一层的旅行会一团糟。
Points ordering_points;
ordering_points.reserve(lslices_1st_layer.size());
for (const ExPolygon& ex : lslices_1st_layer)

View File

@ -721,6 +721,7 @@ bool adjust_layer_series_to_align_object_height(const SlicingParameters &slicing
}
// Produce object layers as pairs of low / high layer boundaries, stored into a linear vector.
//将对象层作为低/高层边界对生成,并存储到线性向量中。
std::vector<coordf_t> generate_object_layers(
const SlicingParameters &slicing_params,
const std::vector<coordf_t> &layer_height_profile,
@ -741,6 +742,7 @@ std::vector<coordf_t> generate_object_layers(
size_t idx_layer_height_profile = 0;
// loop until we have at least one layer and the max slice_z reaches the object height
//循环直到我们至少有一个层并且最大slice_z达到对象高度
coordf_t slice_z = print_z + 0.5 * slicing_params.min_layer_height;
while (slice_z < slicing_params.object_print_z_height()) {
height = slicing_params.min_layer_height;
@ -774,6 +776,7 @@ std::vector<coordf_t> generate_object_layers(
}
if (is_precise_z_height)
//调整图层系列以对齐对象高度
adjust_layer_series_to_align_object_height(slicing_params, out);
return out;
}

View File

@ -13,15 +13,23 @@ struct MeshSlicingParams
enum class SlicingMode : uint32_t {
// Regular slicing, maintain all contours and their orientation.
// slice_mesh_ex() applies ClipperLib::pftNonZero rule to the result of slice_mesh().
//定期切片,保持所有轮廓及其方向。
//slice_mesh_ex将ClipperLib:pftNonZero规则应用于slice_mesh的结果。
Regular,
// For slicing 3DLabPrints plane models (aka to be compatible with S3D default strategy).
// slice_mesh_ex() applies ClipperLib::pftEvenOdd rule. slice_mesh() slices EvenOdd as Regular.
//用于切片3DLabPrints平面模型也就是与S3D默认策略兼容
//slice_mesh_ex应用ClipperLib:pftEvenOdd规则。slice_mesh将EvenOdd切片为常规。
EvenOdd,
// Maintain all contours, orient all contours CCW.
// slice_mesh_ex() applies ClipperLib::pftNonZero rule, thus holes will be closed.
//保持所有轮廓,将所有轮廓逆时针定向。
//slice_mesh_ex应用ClipperLib:pftNonZero规则因此漏洞将被关闭。
Positive,
// Orient all contours CCW and keep only the contour with the largest area.
// This mode is useful for slicing complex objects in vase mode.
//将所有轮廓逆时针定向,只保留面积最大的轮廓。
//此模式对于在花瓶模式下切片复杂对象非常有用。
PositiveLargestContour,
};

View File

@ -4054,7 +4054,7 @@ void MainFrame::update_side_preset_ui()
//BBS: update the preset
m_plater->sidebar().update_presets(Preset::TYPE_PRINTER);
m_plater->sidebar().update_presets(Preset::TYPE_FILAMENT);
m_plater->sidebar().update_presets(Preset::TYPE_CONFIG);
//m_plater->sidebar().update_presets(Preset::TYPE_CONFIG);
//take off multi machine

View File

@ -15,6 +15,7 @@
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <wx/sizer.h>
#include <wx/stattext.h>
@ -13601,16 +13602,21 @@ void Plater::export_gcode(bool prefer_removable)
// If possible, remove accents from accented latin characters.
// This function is useful for generating file names to be processed by legacy firmwares.
//如果可能的话,删除带重音的拉丁字符中的重音。
//此函数对于生成要由旧固件处理的文件名非常有用。
fs::path default_output_file;
try {
// Update the background processing, so that the placeholder parser will get the correct values for the ouput file template.
// Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed.
//更新后台处理,以便占位符解析器获得输出文件模板的正确值。
//此外,如果当前配置有问题,将显示一个弹出对话框,并且不会执行导出。
unsigned int state = this->p->update_restart_background_process(false, false);
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
return;
default_output_file = this->p->background_process.output_filepath_for_project("");
} catch (const Slic3r::PlaceholderParserError &ex) {
// Show the error with monospaced font.
//用等宽字体显示错误。
show_error(this, ex.what(), true);
return;
} catch (const std::exception &ex) {
@ -13621,12 +13627,15 @@ void Plater::export_gcode(bool prefer_removable)
AppConfig &appconfig = *wxGetApp().app_config;
RemovableDriveManager &removable_drive_manager = *wxGetApp().removable_drive_manager();
// Get a last save path, either to removable media or to an internal media.
//获取可移动媒体或内部媒体的最后保存路径。
std::string start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), prefer_removable);
if (prefer_removable) {
// Returns a path to a removable media if it exists, prefering start_dir. Update the internal removable drives database.
//返回可移动媒体的路径如果存在首选start_dir。更新内部可移动驱动器数据库。
start_dir = removable_drive_manager.get_removable_drive_path(start_dir);
if (start_dir.empty())
// Direct user to the last internal media.
//将用户引导到最后一个内部媒体。
start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), false);
}
@ -13666,6 +13675,8 @@ void Plater::export_gcode(bool prefer_removable)
// Storing a path to AppConfig either as path to removable media or a path to internal media.
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
// while the dialog was open.
//将AppConfig的路径存储为可移动媒体的路径或内部媒体的路径。
//使用“true”参数调用is_path_on_removable_drive来更新其内部数据库因为用户可能在对话框打开时洗牌了外部驱动器。
appconfig.update_last_output_dir(output_path.parent_path().string(), path_on_removable_media);
try {
@ -13686,6 +13697,156 @@ void Plater::export_gcode(bool prefer_removable)
} catch (...) {}
}
//std::this_thread::sleep_for(std::chrono::seconds(5));
//output_path = "E:\\Downloads\\Download\\123.gcode";
/* std::string temp_file = output_path.string();
size_t pos = temp_file.find(".gcode");
if (pos != std::string::npos) {
temp_file.replace(pos, 5, "-process");
}
temp_file = temp_file + ".gcode";*/
std::string copy_file = output_path.parent_path().string() + "\\copyFile.gcode";
std::string temp_file = output_path.parent_path().string() + "\\tempFile.gcode";
fs::copy(output_path, copy_file);
std::ifstream inFile(copy_file);
std::ofstream tempFile(temp_file);
double total_length = 50 * 1000;
std::string line;
bool isSwitch = false;
bool isStart = false;
std::string switch_One = "T0";
std::string switch_Two = "T1";
std::string start_line = "; FEATURE";
std::string G1_X_line = "G1 X";
std::regex break_point_pattern(R"(G1\sX\d+\.?\d+?\sY\d+\.?\d+?(?:\s+Z-?\d*\.?\d+?)?(?:\sE-\d*\.?\d+?)?(?:\sF\d+?)?\n?\r?\f?)");
std::regex extrusion_pattern(R"(G1\sX(\d+\.?\d+?)\sY(\d+\.?\d+?)\sE(\d+\.?\d*|\.\d+)\n?\r?\f?)");
if (!inFile.is_open()) {
std::cerr << "Failed to open files." << std::endl;
return;
}
if (!tempFile.is_open()) {
std::cerr << "Failed to open files." << std::endl;
return;
}
std::vector<std::string> tempLine;
std::vector<std::string> stackLine;
while (std::getline(inFile, line)) {
if (line.find(switch_One) == 0) {
isSwitch = false;
}
if (line.find(switch_Two) == 0) {
isSwitch = true;
}
if (isSwitch) {
if (line.find(start_line) != std::string::npos) {
isStart = true;
}
}
if (isStart) {
tempLine.push_back(line);
std::string test = line;
std::cout << test << std::endl;
bool match = std::regex_match(line, break_point_pattern);
if (match) {
bool isProcess = false;
Point last = { 0,0 };
double temp_length = total_length;
double record_extrusion = 0;
int size = tempLine.size();
for (int i = size - 1; i >= 0; i--) {
std::string tempString = tempLine[i];
if (isProcess) {
stackLine.push_back(tempString);
continue;
}
std::smatch matches;
bool found = std::regex_search(tempString, matches, extrusion_pattern);
if (found) {
double x = std::stod(matches[1]);
double y = std::stod(matches[2]);
Point now = { x * 1000.0, y * 1000.0 };
if (last == Point(0, 0)) {
last = now;
stackLine.push_back(tempString);
}
else {
double distance = (last - now).norm();
if (distance < 0) {
distance = -distance;
}
temp_length = temp_length - distance;
if (temp_length < 0) {
double percent = -temp_length / distance;
Point middle_point = interpolate(now, last, percent);
double front_extrusion = record_extrusion * percent;
double back_extrusion = record_extrusion - front_extrusion;
std::stringstream back;
back << "G1 X" << std::fixed << std::setprecision(3) << last.x() / 1000.0 << " Y" << std::fixed << std::setprecision(3) << last.y() / 1000.0 << " E" << std::fixed << std::setprecision(5) << back_extrusion;
stackLine.pop_back();
stackLine.push_back(back.str());
stackLine.push_back("Cut");
std::stringstream front;
front << "G1 X" << std::fixed << std::setprecision(3) << middle_point.x() / 1000.0 << " Y" << std::fixed << std::setprecision(3) << middle_point.y() / 1000.0 << " E" << std::fixed << std::setprecision(5) << front_extrusion;
stackLine.push_back(front.str());
stackLine.push_back(tempString);
isProcess = true;
}
else if (temp_length > 0) {
stackLine.push_back(tempString);
record_extrusion = std::stod(matches[3]);
last = now;
if (i == 0) {
//抛出异常
//throw Slic3r::InvalidArgument();
show_error(this, _L("test1212121212121212121212"));
}
}
else {
stackLine.push_back(tempString);
stackLine.push_back("Cut");
isProcess = true;
}
}
}
else {
stackLine.push_back(tempString);
}
}
int stackSize = stackLine.size();
for (int j = stackSize - 1; j >= 0; j--) {
tempFile << stackLine[j] << std::endl;
}
isStart = false;
tempLine.clear();
stackLine.clear();
continue;
}
else {
continue;
}
}
tempFile << line << std::endl;
}
inFile.close();
tempFile.close();
fs::remove(copy_file);
//fs::remove(output_path);
//std::rename("temp.txt", "original.txt");
//std::this_thread::sleep_for(std::chrono::seconds(4));
fs::rename(temp_file, output_path);
}
Point Plater::interpolate(const Point& p1, const Point& p2, double t) {
return {
double(p1.x() + t * (p2.x() - p1.x())),
double(p1.y() + t * (p2.y() - p1.y()))
};
}
void Plater::send_to_printer(bool isall)

View File

@ -426,6 +426,7 @@ public:
void send_to_printer(bool isall = false);
void export_gcode(bool prefer_removable);
Point interpolate(const Point& p1, const Point& p2, double t);
void export_gcode_3mf(bool export_all = false);
void send_gcode_finish(wxString name);
void export_core_3mf();

View File

@ -3857,6 +3857,9 @@ void TabFilament::toggle_options()
// update_filament_overrides_page();
wxString abc = wxString::FromUTF8(m_preset_bundle->filaments.get_edited_preset().name);
std::string type;
m_preset_bundle->filaments.get_edited_preset().get_filament_type(type);
//CFC
wxString lian_xu = _L("Lian xu");
if (abc.Contains(lian_xu)) {
if (m_active_page->title() == "Filament")
@ -6549,6 +6552,9 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach, bool save_to_proje
else
dependent = { Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL };
break;
case Preset::TYPE_CONFIG:
dependent = { Preset::TYPE_CONFIG };
break;
default:
break;
}