mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-25 09:50:59 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e266c7b234 |
+5
-31
@@ -5527,28 +5527,12 @@ int CLI::run(int argc, char **argv)
|
||||
//add the virtual object into unselect list if has
|
||||
partplate_list.preprocess_exclude_areas(unselected, enable_wrapping_detect);
|
||||
|
||||
// Filament ids given on the command line size the tower for STL input. A project
|
||||
// records its filament use per plate, so count there and keep its tower positions.
|
||||
const int plate_count = partplate_list.get_plate_count();
|
||||
const bool from_project = used_filament_set.empty();
|
||||
std::vector<int> plate_filament_counts(plate_count, static_cast<int>(used_filament_set.size()));
|
||||
if (from_project)
|
||||
for (int plate_index = 0; plate_index < plate_count; ++plate_index)
|
||||
plate_filament_counts[plate_index] = static_cast<int>(partplate_list.get_plate(plate_index)->get_extruders_under_cli(true, m_print_config).size());
|
||||
// A project only gets a tower the slicer will print: the prime tower enabled, and not
|
||||
// a by-object print unless a smooth timelapse needs it, as the per-plate arrange decides.
|
||||
const bool project_tower_allowed = m_print_config.option<ConfigOptionBool>("enable_prime_tower", true)->value &&
|
||||
(is_smooth_timelapse || !arrange_cfg.is_seq_print);
|
||||
const auto plate_needs_wipe_tower = [from_project, project_tower_allowed, is_smooth_timelapse](int filament_count) {
|
||||
if (!from_project)
|
||||
return filament_count > 0;
|
||||
return project_tower_allowed && (filament_count > 1 || (filament_count > 0 && is_smooth_timelapse));
|
||||
};
|
||||
const int max_filament_count = plate_count > 0 ? *std::max_element(plate_filament_counts.begin(), plate_filament_counts.end()) : 0;
|
||||
|
||||
if (plate_needs_wipe_tower(max_filament_count))
|
||||
if (used_filament_set.size() > 0)
|
||||
{
|
||||
//prepare the wipe tower
|
||||
int plate_count = partplate_list.get_plate_count();
|
||||
int extruder_size = used_filament_set.size();
|
||||
|
||||
auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure");
|
||||
// This margin only pre-adjusts the default away from the near edges;
|
||||
// estimate_wipe_tower_polygon below computes the real clamped position.
|
||||
@@ -5584,11 +5568,7 @@ int CLI::run(int argc, char **argv)
|
||||
|
||||
for (int bedid = 0; bedid < MAX_PLATE_COUNT; bedid++) {
|
||||
int plate_index_valid = std::min(bedid, plate_count - 1);
|
||||
// Overflow beds may receive objects from any plate, so size them for the busiest one.
|
||||
const int extruder_size = bedid < plate_count ? plate_filament_counts[bedid] : max_filament_count;
|
||||
if (!plate_needs_wipe_tower(extruder_size))
|
||||
continue;
|
||||
if (bedid < plate_count && !from_project) {
|
||||
if (bedid < plate_count) {
|
||||
wipe_x_option->set_at(&wt_x_opt, plate_index_valid, 0);
|
||||
wipe_y_option->set_at(&wt_y_opt, plate_index_valid, 0);
|
||||
}
|
||||
@@ -7044,12 +7024,6 @@ int CLI::run(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
sliced_info.sliced_plates.push_back(sliced_plate_info);
|
||||
} catch (const Slic3r::SlicingErrors &exs) {
|
||||
const std::string message = print_fff ? print_fff->slicing_errors_message(exs) : std::string(exs.what());
|
||||
BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate " << index+1 << ": " << message;
|
||||
boost::nowide::cerr << message << std::endl;
|
||||
record_exit_reson(outfile_dir, CLI_SLICING_ERROR, index+1, message, sliced_info);
|
||||
flush_and_exit(CLI_SLICING_ERROR);
|
||||
} catch (const std::exception &ex) {
|
||||
BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate "<<index+1 << std::endl;
|
||||
boost::nowide::cerr << ex.what() << std::endl;
|
||||
|
||||
@@ -636,8 +636,6 @@ static std::vector<std::pair<size_t, size_t>> get_segments(const ColoredLines &p
|
||||
return segments;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static std::vector<PaintedLine> filter_painted_lines(const Line &line_to_process, const size_t start_idx, const size_t end_idx, const std::vector<PaintedLine> &painted_lines)
|
||||
{
|
||||
const int filter_eps_value = scale_(0.1f);
|
||||
@@ -690,29 +688,15 @@ static std::vector<std::vector<PaintedLine>> post_process_painted_lines(const st
|
||||
if (painted_lines.empty())
|
||||
return {};
|
||||
|
||||
// The painted lines were appended by parallel workers, so their order is arbitrary. The sort must
|
||||
// therefore be a total order: two projections of the same span from facets of different colours
|
||||
// tie on every geometric key, and whichever sorts first wins the span in filter_painted_lines().
|
||||
// The colour and the end points break such ties so the result does not depend on scheduling.
|
||||
auto comp = [&contours](const PaintedLine &first, const PaintedLine &second) {
|
||||
if (first.contour_idx != second.contour_idx)
|
||||
return first.contour_idx < second.contour_idx;
|
||||
if (first.line_idx != second.line_idx)
|
||||
return first.line_idx < second.line_idx;
|
||||
const Point start_p = contours[first.contour_idx].segment_start(first.line_idx);
|
||||
const double first_dist = (first.projected_line.a - start_p).cast<double>().squaredNorm();
|
||||
const double second_dist = (second.projected_line.a - start_p).cast<double>().squaredNorm();
|
||||
if (first_dist != second_dist)
|
||||
return first_dist < second_dist;
|
||||
const double first_len = (first.projected_line.b - first.projected_line.a).cast<double>().squaredNorm();
|
||||
const double second_len = (second.projected_line.b - second.projected_line.a).cast<double>().squaredNorm();
|
||||
if (first_len != second_len)
|
||||
return first_len < second_len;
|
||||
if (first.color != second.color)
|
||||
return first.color < second.color;
|
||||
if (first.projected_line.a != second.projected_line.a)
|
||||
return first.projected_line.a < second.projected_line.a;
|
||||
return first.projected_line.b < second.projected_line.b;
|
||||
Point first_start_p = contours[first.contour_idx].segment_start(first.line_idx);
|
||||
return first.contour_idx < second.contour_idx ||
|
||||
(first.contour_idx == second.contour_idx &&
|
||||
(first.line_idx < second.line_idx ||
|
||||
(first.line_idx == second.line_idx &&
|
||||
((first.projected_line.a - first_start_p).cast<double>().squaredNorm() < (second.projected_line.a - first_start_p).cast<double>().squaredNorm() ||
|
||||
((first.projected_line.a - first_start_p).cast<double>().squaredNorm() == (second.projected_line.a - first_start_p).cast<double>().squaredNorm() &&
|
||||
(first.projected_line.b - first.projected_line.a).cast<double>().squaredNorm() < (second.projected_line.b - second.projected_line.a).cast<double>().squaredNorm())))));
|
||||
};
|
||||
std::sort(painted_lines.begin(), painted_lines.end(), comp);
|
||||
|
||||
@@ -1216,12 +1200,15 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
const size_t num_layers = input_expolygons.size();
|
||||
const ConstLayerPtrsAdaptor layers = print_object.layers();
|
||||
|
||||
// Maximum number of top / bottom layers accounts for maximum overlap of one thread group into a neighbor thread group.
|
||||
int max_top_layers = 0;
|
||||
int max_bottom_layers = 0;
|
||||
int granularity = 1;
|
||||
for (size_t i = 0; i < print_object.num_printing_regions(); ++ i) {
|
||||
const PrintRegionConfig &config = print_object.printing_region(i).config();
|
||||
max_top_layers = std::max(max_top_layers, config.top_shell_layers.value);
|
||||
max_bottom_layers = std::max(max_bottom_layers, config.bottom_shell_layers.value);
|
||||
granularity = std::max(granularity, std::max(config.top_shell_layers.value, config.bottom_shell_layers.value) - 1);
|
||||
}
|
||||
|
||||
// Project upwards pointing painted triangles over top surfaces,
|
||||
@@ -1340,16 +1327,14 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
|
||||
std::vector<std::vector<ExPolygons>> triangles_by_color_bottom(num_facets_states);
|
||||
std::vector<std::vector<ExPolygons>> triangles_by_color_top(num_facets_states);
|
||||
triangles_by_color_bottom.assign(num_facets_states, std::vector<ExPolygons>(num_layers));
|
||||
triangles_by_color_top.assign(num_facets_states, std::vector<ExPolygons>(num_layers));
|
||||
triangles_by_color_bottom.assign(num_facets_states, std::vector<ExPolygons>(num_layers * 2));
|
||||
triangles_by_color_top.assign(num_facets_states, std::vector<ExPolygons>(num_layers * 2));
|
||||
|
||||
// BBS: the painted top / bottom surfaces are also projected onto the shell layers below / above them.
|
||||
// Each layer only writes the projections it produced, keyed by the layer they land on, so the
|
||||
// parallel loop shares nothing; they are gathered per target layer afterwards, in source-layer
|
||||
// order, which keeps the result independent of how the layers were scheduled.
|
||||
using ShellProjections = std::vector<std::pair<size_t, ExPolygons>>; // (target layer, projection)
|
||||
std::vector<std::vector<ShellProjections>> shell_triangles_by_color_bottom(num_facets_states, std::vector<ShellProjections>(num_layers));
|
||||
std::vector<std::vector<ShellProjections>> shell_triangles_by_color_top(num_facets_states, std::vector<ShellProjections>(num_layers));
|
||||
// BBS: use shell_triangles_by_color_bottom & shell_triangles_by_color_top to save the top and bottom embedded layers's color information
|
||||
std::vector<std::vector<ExPolygons>> shell_triangles_by_color_bottom(num_facets_states);
|
||||
std::vector<std::vector<ExPolygons>> shell_triangles_by_color_top(num_facets_states);
|
||||
shell_triangles_by_color_bottom.assign(num_facets_states, std::vector<ExPolygons>(num_layers * 2));
|
||||
shell_triangles_by_color_top.assign(num_facets_states, std::vector<ExPolygons>(num_layers * 2));
|
||||
|
||||
struct LayerColorStat {
|
||||
// Number of regions for a queried color.
|
||||
@@ -1393,9 +1378,11 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
return out;
|
||||
};
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&num_layers, &num_facets_states, &layer_color_stat, &top_raw, &triangles_by_color_top,
|
||||
&throw_on_cancel_callback, &input_expolygons, &bottom_raw, &triangles_by_color_bottom,
|
||||
&shell_triangles_by_color_top, &shell_triangles_by_color_bottom](const tbb::blocked_range<size_t> &range) {
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers, granularity), [&granularity, &num_layers, &num_facets_states, &layer_color_stat, &top_raw, &triangles_by_color_top,
|
||||
&throw_on_cancel_callback, &input_expolygons, &bottom_raw, &triangles_by_color_bottom,
|
||||
&shell_triangles_by_color_top, &shell_triangles_by_color_bottom](const tbb::blocked_range<size_t> &range) {
|
||||
size_t group_idx = range.begin() / granularity;
|
||||
size_t layer_idx_offset = (group_idx & 1) * num_layers;
|
||||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
||||
for (size_t color_idx = 0; color_idx < num_facets_states; ++color_idx) {
|
||||
throw_on_cancel_callback();
|
||||
@@ -1405,7 +1392,7 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
// Clean up thin projections. They are not printable anyways.
|
||||
top_ex = opening_ex(top_ex, stat.small_region_threshold);
|
||||
if (! top_ex.empty()) {
|
||||
append(triangles_by_color_top[color_idx][layer_idx], top_ex);
|
||||
append(triangles_by_color_top[color_idx][layer_idx + layer_idx_offset], top_ex);
|
||||
float offset = 0.f;
|
||||
ExPolygons layer_slices_trimmed = input_expolygons[layer_idx];
|
||||
for (int last_idx = int(layer_idx) - 1; last_idx > std::max(int(layer_idx - stat.top_shell_layers), int(0)); --last_idx) {
|
||||
@@ -1416,7 +1403,7 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
ExPolygons last = opening_ex(intersection_ex(top_ex, offset_ex(layer_slices_trimmed, offset)), stat.small_region_threshold);
|
||||
if (last.empty())
|
||||
break;
|
||||
shell_triangles_by_color_top[color_idx][layer_idx].emplace_back(size_t(last_idx), std::move(last));
|
||||
append(shell_triangles_by_color_top[color_idx][last_idx + layer_idx_offset], std::move(last));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1425,7 +1412,7 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
// Clean up thin projections. They are not printable anyways.
|
||||
bottom_ex = opening_ex(bottom_ex, stat.small_region_threshold);
|
||||
if (! bottom_ex.empty()) {
|
||||
append(triangles_by_color_bottom[color_idx][layer_idx], bottom_ex);
|
||||
append(triangles_by_color_bottom[color_idx][layer_idx + layer_idx_offset], bottom_ex);
|
||||
float offset = 0.f;
|
||||
ExPolygons layer_slices_trimmed = input_expolygons[layer_idx];
|
||||
for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + stat.bottom_shell_layers, num_layers); ++last_idx) {
|
||||
@@ -1436,7 +1423,7 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
ExPolygons last = opening_ex(intersection_ex(bottom_ex, offset_ex(layer_slices_trimmed, offset)), stat.small_region_threshold);
|
||||
if (last.empty())
|
||||
break;
|
||||
shell_triangles_by_color_bottom[color_idx][layer_idx].emplace_back(last_idx, std::move(last));
|
||||
append(shell_triangles_by_color_bottom[color_idx][last_idx + layer_idx_offset], std::move(last));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1444,28 +1431,19 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
}
|
||||
});
|
||||
|
||||
// Gather the shell projections per target layer, walking the source layers in order.
|
||||
std::vector<std::vector<ExPolygons>> shell_top_by_layer(num_facets_states, std::vector<ExPolygons>(num_layers));
|
||||
std::vector<std::vector<ExPolygons>> shell_bottom_by_layer(num_facets_states, std::vector<ExPolygons>(num_layers));
|
||||
for (size_t color_idx = 0; color_idx < num_facets_states; ++color_idx)
|
||||
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
|
||||
for (auto &[target, projection] : shell_triangles_by_color_top[color_idx][layer_idx])
|
||||
append(shell_top_by_layer[color_idx][target], std::move(projection));
|
||||
for (auto &[target, projection] : shell_triangles_by_color_bottom[color_idx][layer_idx])
|
||||
append(shell_bottom_by_layer[color_idx][target], std::move(projection));
|
||||
}
|
||||
|
||||
std::vector<std::vector<ExPolygons>> triangles_by_color_merged(num_facets_states);
|
||||
triangles_by_color_merged.assign(num_facets_states, std::vector<ExPolygons>(num_layers));
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&triangles_by_color_merged, &triangles_by_color_bottom, &triangles_by_color_top, &throw_on_cancel_callback,
|
||||
&shell_top_by_layer, &shell_bottom_by_layer](const tbb::blocked_range<size_t> &range) {
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&triangles_by_color_merged, &triangles_by_color_bottom, &triangles_by_color_top, &num_layers, &throw_on_cancel_callback,
|
||||
&shell_triangles_by_color_top, &shell_triangles_by_color_bottom](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
||||
throw_on_cancel_callback();
|
||||
ExPolygons painted_exploys;
|
||||
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
||||
auto &self = triangles_by_color_merged[color_idx][layer_idx];
|
||||
append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx]));
|
||||
append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx + num_layers]));
|
||||
append(self, std::move(triangles_by_color_top[color_idx][layer_idx]));
|
||||
append(self, std::move(triangles_by_color_top[color_idx][layer_idx + num_layers]));
|
||||
self = union_ex(self);
|
||||
|
||||
append(painted_exploys, self);
|
||||
@@ -1477,8 +1455,13 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
||||
auto &self = triangles_by_color_merged[color_idx][layer_idx];
|
||||
|
||||
auto top_area = diff_ex(union_ex(shell_top_by_layer[color_idx][layer_idx]), painted_exploys);
|
||||
auto bottom_area = diff_ex(union_ex(shell_bottom_by_layer[color_idx][layer_idx]), painted_exploys);
|
||||
auto top_area = diff_ex(union_ex(shell_triangles_by_color_top[color_idx][layer_idx],
|
||||
shell_triangles_by_color_top[color_idx][layer_idx + num_layers]),
|
||||
painted_exploys);
|
||||
|
||||
auto bottom_area = diff_ex(union_ex(shell_triangles_by_color_bottom[color_idx][layer_idx],
|
||||
shell_triangles_by_color_bottom[color_idx][layer_idx + num_layers]),
|
||||
painted_exploys);
|
||||
|
||||
append(self, top_area);
|
||||
append(self, bottom_area);
|
||||
|
||||
@@ -1705,25 +1705,6 @@ StringObjectException Print::check_multi_filament_valid(const Print& print)
|
||||
|
||||
// Precondition: Print::validate() requires the Print::apply() to be called its invocation.
|
||||
//BBS: refine seq-print validation logic
|
||||
// The exception's own message is just "Errors"; the detail is in the per-object errors,
|
||||
// whose object id is the PrintObject's.
|
||||
std::string Print::slicing_errors_message(const SlicingErrors &errors) const
|
||||
{
|
||||
std::string message;
|
||||
for (const SlicingError &error : errors.errors_) {
|
||||
std::string object_name;
|
||||
for (const PrintObject *object : m_objects)
|
||||
if (object->id().id == error.objectId()) {
|
||||
object_name = object->model_object()->name;
|
||||
break;
|
||||
}
|
||||
if (!message.empty())
|
||||
message += "\n";
|
||||
message += object_name.empty() ? std::string(error.what()) : object_name + ": " + error.what();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
StringObjectException Print::validate(std::vector<StringObjectException> *warnings, Polygons* collison_polygons, std::vector<std::pair<Polygon, float>>* height_polygons) const
|
||||
{
|
||||
auto add_warning = [warnings](StringObjectException w) {
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class SlicingErrors;
|
||||
|
||||
class GCode;
|
||||
class Layer;
|
||||
class ModelObject;
|
||||
@@ -969,8 +967,6 @@ public:
|
||||
|
||||
// Returns an empty string if valid, otherwise returns an error message.
|
||||
StringObjectException validate(std::vector<StringObjectException> *warnings = nullptr, Polygons* collison_polygons = nullptr, std::vector<std::pair<Polygon, float>>* height_polygons = nullptr) const override;
|
||||
// The per-object messages of a SlicingErrors, each prefixed with its object's name.
|
||||
std::string slicing_errors_message(const SlicingErrors &errors) const;
|
||||
double skirt_first_layer_height() const;
|
||||
Flow brim_flow() const;
|
||||
Flow skirt_flow() const;
|
||||
|
||||
@@ -1062,23 +1062,6 @@ inline std::pair<SlabLines, SlabLines> slice_slabs_make_lines(
|
||||
}
|
||||
}
|
||||
);
|
||||
// As in slice_make_lines(): the facet loop is parallel, so the per-slab line order depends on
|
||||
// thread scheduling, and make_slab_loops() derives loop order and start vertices from it.
|
||||
// Sort canonically; edge_type and flags only break ties, std::sort being unstable.
|
||||
auto sort_canonically = [](std::vector<IntersectionLines> &lines_per_slab) {
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, lines_per_slab.size()),
|
||||
[&lines_per_slab](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t i = range.begin(); i < range.end(); ++ i)
|
||||
std::sort(lines_per_slab[i].begin(), lines_per_slab[i].end(), [](const IntersectionLine &l, const IntersectionLine &r) {
|
||||
return std::make_tuple(l.edge_a_id, l.edge_b_id, l.a_id, l.b_id, l.a.x(), l.a.y(), l.b.x(), l.b.y(), l.edge_type, l.flags) <
|
||||
std::make_tuple(r.edge_a_id, r.edge_b_id, r.a_id, r.b_id, r.a.x(), r.a.y(), r.b.x(), r.b.y(), r.edge_type, r.flags);
|
||||
});
|
||||
});
|
||||
};
|
||||
for (SlabLines *slab_lines : { &lines_top, &lines_bottom }) {
|
||||
sort_canonically(slab_lines->at_slice);
|
||||
sort_canonically(slab_lines->between_slices);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@ static const char* Segments_Vertex_Shader =
|
||||
// ORCA: 0 during the shadow caster pass - the bias below shifts eye_position but not
|
||||
// world_position, so the caster would write a depth the receiver never looks up.
|
||||
"uniform float bias_scale;\n"
|
||||
// draw the instances last to first, top layers before the ones they hide, so that early depth
|
||||
// rejection discards most of the hidden fragments; set when the camera looks down on the print
|
||||
"uniform int reverse_order;\n"
|
||||
"uniform int instance_count;\n"
|
||||
"in int vertex_id;\n"
|
||||
"out vec3 color;\n"
|
||||
"// ORCA: realistic view - the light the shadow map is able to block, kept apart from the\n"
|
||||
@@ -59,7 +63,8 @@ static const char* Segments_Vertex_Shader =
|
||||
" return top_diffuse + front_diffuse + top_specular;\n"
|
||||
"}\n"
|
||||
"void main() {\n"
|
||||
" int id_a = int(texelFetch(segment_index_tex, gl_InstanceID).r);\n"
|
||||
" int instance = (reverse_order != 0) ? instance_count - 1 - gl_InstanceID : gl_InstanceID;\n"
|
||||
" int id_a = int(texelFetch(segment_index_tex, instance).r);\n"
|
||||
" int id_b = id_a + 1;\n"
|
||||
" vec3 pos_a = texelFetch(position_tex, id_a).xyz;\n"
|
||||
" vec3 pos_b = texelFetch(position_tex, id_b).xyz;\n"
|
||||
|
||||
@@ -763,6 +763,8 @@ void ViewerImpl::init(const std::string& opengl_context_version)
|
||||
m_uni_segments_height_width_angle_tex_id = glGetUniformLocation(m_segments_shader_id, "height_width_angle_tex");
|
||||
m_uni_segments_colors_tex_id = glGetUniformLocation(m_segments_shader_id, "color_tex");
|
||||
m_uni_segments_segment_index_tex_id = glGetUniformLocation(m_segments_shader_id, "segment_index_tex");
|
||||
m_uni_segments_reverse_order_id = glGetUniformLocation(m_segments_shader_id, "reverse_order");
|
||||
m_uni_segments_instance_count_id = glGetUniformLocation(m_segments_shader_id, "instance_count");
|
||||
// ORCA: realistic view
|
||||
m_uni_segments_shadow_map_id = glGetUniformLocation(m_segments_shader_id, "shadow_map");
|
||||
m_uni_segments_shadow_light_vp_id = glGetUniformLocation(m_segments_shader_id, "shadow_light_vp");
|
||||
@@ -2090,6 +2092,15 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
|
||||
glsafe(glUniformMatrix4fv(m_uni_segments_view_matrix_id, 1, GL_FALSE, view_matrix.data()));
|
||||
glsafe(glUniformMatrix4fv(m_uni_segments_projection_matrix_id, 1, GL_FALSE, projection_matrix.data()));
|
||||
glsafe(glUniform3fv(m_uni_segments_camera_position_id, 1, camera_position.data()));
|
||||
// The segments come in print order, bottom layer first. Seen from above, that is back to front,
|
||||
// and every hidden fragment is shaded before the one that covers it. Drawing them last to first
|
||||
// lets the depth test reject the hidden ones instead. The camera looks down when the world's
|
||||
// up axis points towards it, which is the view matrix's (2, 2) entry being positive.
|
||||
const bool top_down = !m_rendering_shadow_casters && view_matrix[10] > 0.0f;
|
||||
glsafe(glUniform1i(m_uni_segments_reverse_order_id, top_down ? 1 : 0));
|
||||
#ifndef ENABLE_OPENGL_ES
|
||||
glsafe(glUniform1i(m_uni_segments_instance_count_id, static_cast<int>(m_enabled_segments_count)));
|
||||
#endif // ENABLE_OPENGL_ES
|
||||
// ORCA: realistic view. The depth pass writes the map it would otherwise read, so it shades
|
||||
// with the lookup off.
|
||||
glsafe(glUniform1i(m_uni_segments_shadow_map_id, m_shadow_map_texture_unit));
|
||||
|
||||
@@ -362,6 +362,8 @@ private:
|
||||
int m_uni_segments_height_width_angle_tex_id{ -1 };
|
||||
int m_uni_segments_colors_tex_id{ -1 };
|
||||
int m_uni_segments_segment_index_tex_id{ -1 };
|
||||
int m_uni_segments_reverse_order_id{ -1 };
|
||||
int m_uni_segments_instance_count_id{ -1 };
|
||||
int m_uni_segments_shadow_map_id{ -1 };
|
||||
int m_uni_segments_shadow_light_vp_id{ -1 };
|
||||
int m_uni_segments_shadow_intensity_id{ -1 };
|
||||
|
||||
@@ -7184,14 +7184,6 @@ void Tab::activate_selected_page(std::function<void()> throw_if_canceled)
|
||||
if (!m_active_page)
|
||||
return;
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// Builds the page off screen, since GTK crashes when it desensitizes a multiline text view
|
||||
// that was built on screen and hidden before its first size allocation.
|
||||
const bool hide_view = m_active_page->build_pending() && m_page_view->IsShown();
|
||||
if (hide_view)
|
||||
m_page_view->Hide();
|
||||
ScopeGuard show_view([this, hide_view] { if (hide_view) m_page_view->Show(); });
|
||||
#endif
|
||||
m_active_page->activate(m_mode, throw_if_canceled);
|
||||
update_changed_ui();
|
||||
update_description_lines();
|
||||
|
||||
@@ -505,29 +505,3 @@ TEST_CASE("Sequential printing publishes the nozzle group result", "[Print][Mult
|
||||
CHECK(gcode.find("; SEQ-ND-OK") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Slicing errors are reported per object with the object's name", "[Print]")
|
||||
{
|
||||
Print print;
|
||||
Model model;
|
||||
init_print({Slic3r::Test::cube(20.)}, print, model);
|
||||
// Lift the cube off the bed: its first layer is empty, which G-code export reports per object.
|
||||
ModelObject *object = model.objects.front();
|
||||
object->name = "floating cube";
|
||||
object->instances.front()->set_offset(object->instances.front()->get_offset() + Vec3d(0., 0., 2.));
|
||||
print.apply(model, DynamicPrintConfig::full_print_config());
|
||||
print.set_status_silent();
|
||||
|
||||
ScopedTemporaryFile temp(".gcode");
|
||||
std::string message;
|
||||
try {
|
||||
print.process();
|
||||
print.export_gcode(temp.string(), nullptr, nullptr);
|
||||
FAIL("slicing did not report the empty first layer");
|
||||
} catch (const SlicingErrors &errors) {
|
||||
REQUIRE(errors.errors_.size() == 1);
|
||||
message = print.slicing_errors_message(errors);
|
||||
}
|
||||
CHECK(message.rfind("floating cube: ", 0) == 0);
|
||||
CHECK(message.find("empty first layer") != std::string::npos);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_stl.cpp
|
||||
test_triangle_selector.cpp
|
||||
test_meshboolean.cpp
|
||||
test_trianglemesh_slicer.cpp
|
||||
test_marchingsquares.cpp
|
||||
test_lay_on_face.cpp
|
||||
test_model.cpp
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <tbb/global_control.h>
|
||||
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
// The slab slicer collects each slab's intersection lines from a parallel loop over the facets.
|
||||
// Its loops, and therefore the projected polygons, are derived from the order of those lines, so
|
||||
// the order has to be canonical or the same mesh projects to different polygons run to run.
|
||||
// The single-threaded projection is the reference; every multi-threaded run must reproduce it
|
||||
// exactly, vertex order included.
|
||||
TEST_CASE("Slab slicing projects the same polygons whatever the thread schedule", "[TriangleMeshSlicer]")
|
||||
{
|
||||
// A dense sphere, tilted so no facet is axis aligned: thousands of upward and downward
|
||||
// facing facets spread over every slab.
|
||||
indexed_triangle_set mesh = its_make_sphere(10., 0.05);
|
||||
Transform3d trafo = Transform3d::Identity();
|
||||
trafo.rotate(Eigen::AngleAxisd(0.37, Vec3d(0.3, 0.5, 1.).normalized()));
|
||||
trafo.translate(Vec3d(1., 2., 0.));
|
||||
std::vector<float> zs;
|
||||
for (float z = -9.7f; z < 9.7f; z += 0.2f)
|
||||
zs.emplace_back(z);
|
||||
|
||||
auto project = [&mesh, &trafo, &zs]() {
|
||||
std::vector<Polygons> top, bottom;
|
||||
slice_mesh_slabs(mesh, zs, trafo, &top, &bottom, nullptr, []{});
|
||||
return std::make_pair(std::move(top), std::move(bottom));
|
||||
};
|
||||
|
||||
std::pair<std::vector<Polygons>, std::vector<Polygons>> reference;
|
||||
{
|
||||
tbb::global_control single_thread(tbb::global_control::max_allowed_parallelism, 1);
|
||||
reference = project();
|
||||
}
|
||||
REQUIRE(reference.first.size() == zs.size());
|
||||
REQUIRE(std::any_of(reference.first.begin(), reference.first.end(), [](const Polygons &p) { return !p.empty(); }));
|
||||
REQUIRE(std::any_of(reference.second.begin(), reference.second.end(), [](const Polygons &p) { return !p.empty(); }));
|
||||
|
||||
for (int run = 0; run < 3; ++run) {
|
||||
DYNAMIC_SECTION("multi-threaded run " << run)
|
||||
{
|
||||
auto parallel = project();
|
||||
CHECK(parallel.first == reference.first);
|
||||
CHECK(parallel.second == reference.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user