mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-01-31 07:58:43 +03:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4888f01b47 | ||
|
|
428388b804 | ||
|
|
576389430c | ||
|
|
2b0652398d | ||
|
|
aa6efa280d | ||
|
|
8c016acf83 | ||
|
|
4983297dee | ||
|
|
e0dd4753c0 | ||
|
|
bb3884101f | ||
|
|
f155e1c167 | ||
|
|
a50473f8a9 | ||
|
|
b6f5986a9a | ||
|
|
821eb8ebe9 | ||
|
|
2eecb1ce8a | ||
|
|
12da7dac6a | ||
|
|
83c42c3d4f | ||
|
|
bf9dbfae79 | ||
|
|
5bba8ccb1b | ||
|
|
8de170e272 | ||
|
|
ec37905b75 | ||
|
|
c564e62549 | ||
|
|
eba6ab9ac1 | ||
|
|
abbe9d06df | ||
|
|
0b6f75c9dc | ||
|
|
2f7a8a7568 | ||
|
|
b7625edc45 | ||
|
|
6a26320804 | ||
|
|
8f7e2169c4 |
File diff suppressed because it is too large
Load Diff
BIN
resources/calib/VolumetricSpeed/volumetric_speed.stl
Normal file
BIN
resources/calib/VolumetricSpeed/volumetric_speed.stl
Normal file
Binary file not shown.
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
|
||||
<g id="hex_x5F_green">
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
|
||||
<g id="hex_x5F_green_2_">
|
||||
<g>
|
||||
<polygon fill="#ED6B21" points="8,1 2,5 2,7 2,11 8,15 14,11 14,7 14,5 "/>
|
||||
<polygon fill="#4479FB" points="8,1 2,5 2,7 2,11 8,15 14,11 14,7 14,5 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 493 B |
@@ -1,3 +1,5 @@
|
||||
min_slic3r_version = 1.1.1
|
||||
1.1.1 Optimize parameters
|
||||
min_slic3r_version = 1.1.0
|
||||
1.1.0 Optimize parameters
|
||||
min_slic3r_version = 1.0.9
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
name = QIDI Technology
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the QIDISlicer configuration to be downgraded.
|
||||
config_version = 1.1.0
|
||||
config_version = 1.1.1
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://github.com/QIDITECH/QIDISlicer/releases/download/QIDITechnology/
|
||||
changelog_url = https://qidi3d.com/pages/software-firmware
|
||||
@@ -145,6 +145,7 @@ raft_first_layer_density = 90%
|
||||
raft_first_layer_expansion = 3
|
||||
raft_layers = 0
|
||||
resolution = 0
|
||||
seam_gap = 15
|
||||
seam_position = aligned
|
||||
single_extruder_multi_material_priming = 1
|
||||
skirt_distance = 6
|
||||
@@ -197,8 +198,10 @@ support_tree_tip_diameter = 0.8
|
||||
support_tree_top_rate = 15%
|
||||
thick_bridges = 0
|
||||
thin_walls = 0
|
||||
top_area_threshold = 100
|
||||
top_fill_pattern = monotoniclines
|
||||
top_infill_extrusion_width = 0.42
|
||||
top_one_wall_type = all_top
|
||||
top_solid_infill_acceleration = 2000
|
||||
top_solid_infill_speed = 200
|
||||
top_solid_layers = 5
|
||||
@@ -223,7 +226,6 @@ wipe_tower_x = 180
|
||||
wipe_tower_y = 140
|
||||
xy_size_compensation = 0
|
||||
|
||||
# Machine Print preset
|
||||
[print:*X-MAX 3*]
|
||||
inherits = *common*
|
||||
|
||||
@@ -565,9 +567,9 @@ compatible_prints =
|
||||
compatible_prints_condition =
|
||||
cooling = 1
|
||||
disable_fan_first_layers = 1
|
||||
disable_rapid_cooling_fan_first_layers = 15
|
||||
disable_rapid_cooling_fan_first_layers = 3
|
||||
enable_advance_pressure = 1
|
||||
enable_auxiliary_fan = 100
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 0
|
||||
enable_volume_fan = 100
|
||||
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
|
||||
@@ -632,7 +634,6 @@ inherits = *common*
|
||||
advance_pressure = 0.021
|
||||
bed_temperature = 90
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
enable_volume_fan = 0
|
||||
extrusion_multiplier = 0.92
|
||||
@@ -655,7 +656,6 @@ inherits = *common*
|
||||
advance_pressure = 0.021
|
||||
bed_temperature = 90
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
enable_volume_fan = 0
|
||||
extrusion_multiplier = 0.95
|
||||
@@ -678,7 +678,6 @@ inherits = *common*
|
||||
advance_pressure = 0.01
|
||||
bed_temperature = 100
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_volume_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
extrusion_multiplier = 0.95
|
||||
@@ -701,7 +700,6 @@ inherits = *common*
|
||||
advance_pressure = 0.021
|
||||
bed_temperature = 90
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
enable_volume_fan = 0
|
||||
extrusion_multiplier = 0.92
|
||||
@@ -726,7 +724,6 @@ inherits = *common*
|
||||
advance_pressure = 0.021
|
||||
bed_temperature = 90
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
enable_volume_fan = 0
|
||||
extrusion_multiplier = 0.7
|
||||
@@ -757,7 +754,6 @@ advance_pressure = 0.01
|
||||
bed_temperature = 80
|
||||
bridge_fan_speed = 50
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
extrusion_multiplier = 0.96
|
||||
fan_below_layer_time = 10
|
||||
@@ -782,7 +778,6 @@ advance_pressure = 0.01
|
||||
bed_temperature = 80
|
||||
bridge_fan_speed = 50
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
extrusion_multiplier = 0.96
|
||||
fan_below_layer_time = 10
|
||||
filament_colour = #4F4F4F
|
||||
@@ -803,7 +798,6 @@ advance_pressure = 0.04
|
||||
bed_temperature = 100
|
||||
bridge_fan_speed = 60
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
enable_volume_fan = 0
|
||||
extrusion_multiplier = 0.92
|
||||
@@ -828,7 +822,6 @@ advance_pressure = 0.01
|
||||
bed_temperature = 80
|
||||
bridge_fan_speed = 50
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
extrusion_multiplier = 1
|
||||
fan_below_layer_time = 10
|
||||
@@ -852,7 +845,6 @@ inherits = *common*
|
||||
advance_pressure = 0.04
|
||||
bed_temperature = 80
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
extrusion_multiplier = 0.95
|
||||
fan_below_layer_time = 30
|
||||
@@ -883,7 +875,6 @@ inherits = *common*
|
||||
advance_pressure = 0.03
|
||||
bed_temperature = 80
|
||||
bridge_fan_speed = 50
|
||||
enable_auxiliary_fan = 0
|
||||
extrusion_multiplier = 0.96
|
||||
filament_colour = #FFEBCD
|
||||
filament_density = 1.21
|
||||
@@ -902,7 +893,6 @@ inherits = *common*
|
||||
advance_pressure = 0.021
|
||||
bed_temperature = 90
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
enable_volume_fan = 0
|
||||
extrusion_multiplier = 0.95
|
||||
@@ -926,7 +916,6 @@ inherits = *common*
|
||||
advance_pressure = 0.04
|
||||
bed_temperature = 80
|
||||
disable_fan_first_layers = 3
|
||||
enable_auxiliary_fan = 0
|
||||
enable_dynamic_fan_speeds = 1
|
||||
extrusion_multiplier = 0.95
|
||||
fan_below_layer_time = 30
|
||||
@@ -954,7 +943,6 @@ filament_vendor = Generic
|
||||
[filament:*Generic TPU 95A*]
|
||||
inherits = *common*
|
||||
advance_pressure = 0.1
|
||||
enable_auxiliary_fan = 0
|
||||
extrusion_multiplier = 1
|
||||
filament_colour = #8000FF
|
||||
filament_density = 1.21
|
||||
@@ -1988,7 +1976,7 @@ auxiliary_fan = 1
|
||||
bed_shape = 0x0,325x0,325x325,0x325
|
||||
chamber_temperature = 1
|
||||
max_print_height = 315
|
||||
thumbnails = 380x380/QIDI, 210x210/QIDI, 110X110/PNG
|
||||
thumbnails = 380x380/QIDI, 210x210/QIDI, 110x110/PNG
|
||||
|
||||
[printer:X-MAX 3 0.2 nozzle]
|
||||
inherits = *X-MAX 3*
|
||||
@@ -2034,7 +2022,7 @@ auxiliary_fan = 1
|
||||
bed_shape = 0x0,280x0,280x280,0x280
|
||||
chamber_temperature = 1
|
||||
max_print_height = 270
|
||||
thumbnails = 380x380/QIDI, 210x210/QIDI, 110X110/PNG
|
||||
thumbnails = 380x380/QIDI, 210x210/QIDI, 110x110/PNG
|
||||
|
||||
[printer:X-Plus 3 0.2 nozzle]
|
||||
inherits = *X-Plus 3*
|
||||
@@ -2078,7 +2066,7 @@ inherits = *common*
|
||||
printer_model = X-smart 3
|
||||
bed_shape = 0x0,175x0,175x180,0x180
|
||||
max_print_height = 170
|
||||
thumbnails = 205x205/QIDI, 140x140/QIDI, 110X110/PNG
|
||||
thumbnails = 205x205/QIDI, 140x140/QIDI, 110x110/PNG
|
||||
|
||||
[printer:X-smart 3 0.2 nozzle]
|
||||
inherits = *X-smart 3*
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1687832492956" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10887" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M972.146238 0.005962h-3.629346c-15.683959 0.907336-246.277047 15.683959-374.341111 93.714898-27.479334 16.850535-36.16384 49.12579-41.867098 104.602935a94.362995 94.362995 0 0 0-67.920617-31.627158 85.16001 85.16001 0 0 0-52.625517 18.924447c-47.051878 37.330416-207.391197 171.356977-277.256107 332.862872C68.698334 717.320267 82.826859 863.66068 83.474957 869.752797c0 1.555434 0.907336 2.981248 1.166575 4.536682-47.959214 61.439642-77.123602 104.732555-80.364089 109.398857a25.9239 25.9239 0 0 0 7.129073 35.515743A25.9239 25.9239 0 0 0 25.9239 1024a25.9239 25.9239 0 0 0 21.387217-11.406516c0-1.036956 27.479334-40.830142 72.716539-98.899677h1.685053A250.295251 250.295251 0 0 0 181.467298 920.304401c99.547775 0 305.902016-38.88585 570.325793-296.958271C987.570958 393.012282 1019.716594 99.294498 1023.086701 58.723595A47.829595 47.829595 0 0 0 1023.994038 51.853762a51.070082 51.070082 0 0 0-51.8478-51.8478zM716.406968 586.404573C461.575034 835.533249 267.405025 868.456602 181.467298 868.456602c-10.499179 0-18.794827 0-25.9239-1.166576 87.363542-107.195325 220.353147-251.202588 368.378615-349.972645a25.9239 25.9239 0 0 0-28.51629-42.644815c-145.173838 97.214624-272.200947 232.148522-361.89764 338.825369a795.215623 795.215623 0 0 1 67.531759-274.274859c64.809749-151.136335 221.001245-280.626214 262.220245-312.901469a33.182592 33.182592 0 0 1 20.998359-8.166029c45.237205 0 81.401045 108.750759 100.195872 108.75076h1.944293c16.202437-7.517931 9.591843-173.560508 34.349167-188.72599C741.034672 64.815712 972.146238 51.853762 972.146238 51.853762s-19.054066 303.180007-255.73927 534.550811z" fill="#4479FB" p-id="10888"></path></svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
|
||||
<path fill="#4479FB" d="M19,0L19,0c-0.4,0-4.9,0.3-7.4,1.8c-0.5,0.3-0.7,1-0.8,2C10.4,3.5,10,3.3,9.5,3.3c-0.4,0-0.7,0.1-1,0.4
|
||||
C7.5,4.4,4.4,7,3,10.1C1.3,14,1.6,16.9,1.6,17c0,0,0,0.1,0,0.1c-0.9,1.2-1.5,2-1.6,2.1c-0.1,0.2-0.1,0.5,0.1,0.7
|
||||
C0.3,20,0.4,20,0.5,20c0.2,0,0.3-0.1,0.4-0.2c0,0,0.5-0.8,1.4-1.9h0C2.8,17.9,3.2,18,3.5,18c1.9,0,6-0.8,11.1-5.8
|
||||
c4.6-4.5,5.2-10.2,5.3-11c0,0,0-0.1,0-0.1C20,0.5,19.6,0,19,0C19,0,19,0,19,0z M14,11.5C9,16.3,5.2,17,3.5,17c-0.2,0-0.4,0-0.5,0
|
||||
c1.7-2.1,4.3-4.9,7.2-6.8c0.2-0.2,0.2-0.5,0-0.7c-0.1-0.2-0.4-0.2-0.6-0.1c-2.8,1.9-5.3,4.5-7.1,6.6c0.1-1.9,0.6-3.7,1.3-5.4
|
||||
c1.3-3,4.3-5.5,5.1-6.1c0.1-0.1,0.3-0.2,0.4-0.2c0.9,0,1.6,2.1,2,2.1h0c0.3-0.1,0.2-3.4,0.7-3.7C14.5,1.3,19,1,19,1
|
||||
S18.6,6.9,14,11.5L14,11.5z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 2.0 KiB |
@@ -993,6 +993,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
// Write information on the generator.
|
||||
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
||||
|
||||
|
||||
if (! export_to_binary_gcode) {
|
||||
// if exporting gcode in ascii format, generate the thumbnails here
|
||||
auto [thumbnails, errors] = GCodeThumbnails::make_and_check_thumbnail_list(print.full_print_config());
|
||||
@@ -1043,9 +1044,10 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
}
|
||||
//B41
|
||||
// adds tags for time estimators
|
||||
if (print.config().remaining_times.value)
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
|
||||
// if (print.config().remaining_times.value)
|
||||
// file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
|
||||
|
||||
// Starting now, the G-code find / replace post-processor will be enabled.
|
||||
file.find_replace_enable();
|
||||
@@ -1122,7 +1124,8 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
|
||||
// Label all objects so printer knows about them since the start.
|
||||
m_label_objects.init(print);
|
||||
file.write(m_label_objects.all_objects_header());
|
||||
//B41
|
||||
// file.write(m_label_objects.all_objects_header());
|
||||
// Update output variables after the extruders were initialized.
|
||||
m_placeholder_parser_integration.init(m_writer);
|
||||
// Let the start-up script prime the 1st printing tool.
|
||||
@@ -1409,6 +1412,23 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
if (print.m_print_statistics.total_toolchanges > 0)
|
||||
file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
||||
|
||||
//B3
|
||||
if (!export_to_binary_gcode) {
|
||||
// if exporting gcode in ascii format, generate the thumbnails here
|
||||
auto [thumbnails, errors] = GCodeThumbnails::make_and_check_thumbnail_list(print.full_print_config());
|
||||
if (errors != enum_bitmask<ThumbnailError>()) {
|
||||
std::string error_str = format("Invalid thumbnails value:");
|
||||
error_str += GCodeThumbnails::get_error_string(errors);
|
||||
throw Slic3r::ExportError(error_str);
|
||||
}
|
||||
if (!thumbnails.empty())
|
||||
GCodeThumbnails::export_qidi_thumbnails_to_file(
|
||||
thumbnail_cb, thumbnails, [&file](const char *sz) { file.write(sz); }, [&print]() { print.throw_if_canceled(); });
|
||||
}
|
||||
|
||||
file.write("\n");
|
||||
|
||||
// Append full config, delimited by two 'phony' configuration keys qidislicer_config = begin and qidislicer_config = end.
|
||||
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of QIDISlicer G-code viewer.
|
||||
{
|
||||
@@ -2842,7 +2862,8 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC
|
||||
// if polyline was shorter than the clipping distance we'd get a null polyline, so
|
||||
// we discard it in that case.
|
||||
if (m_enable_loop_clipping)
|
||||
clip_end(smooth_path, scaled<double>(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, scaled<double>(min_gcode_segment_length));
|
||||
//Y21
|
||||
clip_end(smooth_path, scaled<double>(EXTRUDER_CONFIG(nozzle_diameter)) * (m_config.seam_gap.value / 100), scaled<double>(min_gcode_segment_length));
|
||||
|
||||
if (smooth_path.empty())
|
||||
return {};
|
||||
|
||||
@@ -86,17 +86,18 @@ inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb,
|
||||
if (data.is_valid()) {
|
||||
switch (format) {
|
||||
case GCodeThumbnailsFormat::QIDI: {
|
||||
auto compressed = compress_qidi_thumbnail(data, format);
|
||||
//auto compressed = compress_qidi_thumbnail(data, format);
|
||||
|
||||
if (count == 0) {
|
||||
output((boost::format("\n\n;gimage:%s\n\n") % compressed).str().c_str());
|
||||
count++;
|
||||
break;
|
||||
} else {
|
||||
output((boost::format("\n\n;simage:%s\n\n") % compressed).str().c_str());
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
//if (count == 0) {
|
||||
// output((boost::format("\n\n;gimage:%s\n\n") % compressed).str().c_str());
|
||||
// count++;
|
||||
// break;
|
||||
//} else {
|
||||
// output((boost::format("\n\n;simage:%s\n\n") % compressed).str().c_str());
|
||||
// count++;
|
||||
// break;
|
||||
//}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
auto compressed = compress_thumbnail(data, format);
|
||||
@@ -129,6 +130,67 @@ inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb,
|
||||
}
|
||||
}
|
||||
}
|
||||
//B3
|
||||
template<typename WriteToOutput, typename ThrowIfCanceledCallback>
|
||||
inline void export_qidi_thumbnails_to_file(ThumbnailsGeneratorCallback & thumbnail_cb,
|
||||
const std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> &thumbnails_list,
|
||||
WriteToOutput output,
|
||||
ThrowIfCanceledCallback throw_if_canceled)
|
||||
{
|
||||
// Write thumbnails using base64 encoding
|
||||
if (thumbnail_cb != nullptr) {
|
||||
//B3
|
||||
int count = 0;
|
||||
for (const auto &[format, size] : thumbnails_list) {
|
||||
static constexpr const size_t max_row_length = 78;
|
||||
ThumbnailsList thumbnails = thumbnail_cb(ThumbnailsParams{{size}, true, false, false, true});
|
||||
for (const ThumbnailData &data : thumbnails)
|
||||
if (data.is_valid()) {
|
||||
switch (format) {
|
||||
case GCodeThumbnailsFormat::QIDI: {
|
||||
auto compressed = compress_qidi_thumbnail(data, format);
|
||||
|
||||
if (count == 0) {
|
||||
output((boost::format("\n\n;gimage:%s\n\n") % compressed).str().c_str());
|
||||
count++;
|
||||
break;
|
||||
} else {
|
||||
output((boost::format("\n\n;simage:%s\n\n") % compressed).str().c_str());
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
//auto compressed = compress_thumbnail(data, format);
|
||||
//if (compressed->data && compressed->size) {
|
||||
// std::string encoded;
|
||||
// encoded.resize(boost::beast::detail::base64::encoded_size(compressed->size));
|
||||
// encoded.resize(boost::beast::detail::base64::encode((void *) encoded.data(), (const void *) compressed->data,
|
||||
// compressed->size));
|
||||
|
||||
// output((boost::format("\n;\n; %s begin %dx%d %d\n") % compressed->tag() % data.width % data.height %
|
||||
// encoded.size())
|
||||
// .str()
|
||||
// .c_str());
|
||||
|
||||
// while (encoded.size() > max_row_length) {
|
||||
// output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str());
|
||||
// encoded = encoded.substr(max_row_length);
|
||||
// }
|
||||
|
||||
// if (encoded.size() > 0)
|
||||
// output((boost::format("; %s\n") % encoded).str().c_str());
|
||||
|
||||
// output((boost::format("; %s end\n;\n") % compressed->tag()).str().c_str());
|
||||
//}
|
||||
}
|
||||
}
|
||||
throw_if_canceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ThrowIfCanceledCallback>
|
||||
inline void generate_binary_thumbnails(ThumbnailsGeneratorCallback& thumbnail_cb, std::vector<bgcode::binarize::ThumbnailBlock>& out_thumbnails,
|
||||
|
||||
@@ -79,7 +79,8 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
static constexpr const std::string_view wipe_retract_comment = "wipe and retract"sv;
|
||||
|
||||
// Remaining quantized retraction length.
|
||||
if (double retract_length = extruder.retract_to_go(toolchange ? extruder.retract_length_toolchange() : extruder.retract_length());
|
||||
//w15
|
||||
if (double retract_length = extruder.retract_to_go(toolchange ? extruder.retract_length_toolchange() * 0.95 : extruder.retract_length()) * 0.95;
|
||||
retract_length > 0 && this->has_path()) {
|
||||
// Delayed emitting of a wipe start tag.
|
||||
bool wiped = false;
|
||||
@@ -104,7 +105,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
double segment_length = (p_quantized - prev_quantized).norm();
|
||||
// Quantize E axis as it is to be extruded as a whole segment.
|
||||
// w15
|
||||
double dE = gcodegen.writer().config.retract_length.get_at(extruder.id()) * segment_length / wipe_dist_max;
|
||||
double dE = retract_length * segment_length / wipe_dist_max;
|
||||
bool done = false;
|
||||
if (dE > retract_length - EPSILON) {
|
||||
if (dE > retract_length + EPSILON)
|
||||
@@ -144,7 +145,13 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
float angle = Geometry::ArcWelder::arc_angle(prev_quantized.cast<double>(), p_quantized.cast<double>(), double(radius));
|
||||
assert(angle > 0);
|
||||
double segment_length = angle * std::abs(radius);
|
||||
wipe_dist += segment_length;
|
||||
if (wipe_dist > wipe_dist_max) {
|
||||
angle = angle * (wipe_dist_max - wipe_dist + segment_length) / segment_length;
|
||||
segment_length = wipe_dist_max - wipe_dist + segment_length;
|
||||
}
|
||||
double dE = GCodeFormatter::quantize_e(xy_to_e * segment_length);
|
||||
dE = retract_length * segment_length / wipe_dist_max;
|
||||
bool done = false;
|
||||
if (dE > retract_length - EPSILON) {
|
||||
if (dE > retract_length + EPSILON) {
|
||||
@@ -153,12 +160,12 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
angle = Geometry::ArcWelder::arc_angle(prev_quantized.cast<double>(), p.cast<double>(), double(radius));
|
||||
segment_length = angle * std::abs(radius);
|
||||
//w15
|
||||
dE = gcodegen.writer().config.retract_length.get_at(extruder.id())* segment_length / wipe_dist_max ;
|
||||
dE = retract_length* segment_length / wipe_dist_max ;
|
||||
p = GCodeFormatter::quantize(
|
||||
Vec2d(center + Eigen::Rotation2D((ccw ? angle : -angle) * (retract_length / dE)) * (prev_quantized - center)));
|
||||
} else
|
||||
p = p_quantized;
|
||||
dE = retract_length;
|
||||
//dE = retract_length;
|
||||
done = true;
|
||||
} else
|
||||
p = p_quantized;
|
||||
@@ -174,13 +181,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
p, ij, ccw, -dE, wipe_retract_comment);
|
||||
}
|
||||
retract_length -= dE;
|
||||
//w15
|
||||
//return done;
|
||||
wipe_dist += segment_length;
|
||||
if (wipe_dist >= wipe_dist_max) {
|
||||
Vec2d direction = (p - prev_quantized).normalized();
|
||||
p = prev_quantized + direction * abs(wipe_dist - segment_length - wipe_dist_max);
|
||||
}
|
||||
|
||||
return done;
|
||||
};
|
||||
// Start with the current position, which may be different from the wipe path start in case of loop clipping.
|
||||
@@ -197,11 +198,11 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange)
|
||||
prev = p;
|
||||
auto end = this->path().end();
|
||||
for (; it != end && ! done; ++ it) {
|
||||
//w15
|
||||
if (wipe_dist >= wipe_dist_max)
|
||||
break;
|
||||
p = gcodegen.point_to_gcode(it->point + m_offset);
|
||||
if (p != prev) {
|
||||
//w15
|
||||
if (wipe_dist >= wipe_dist_max)
|
||||
break;
|
||||
start_wipe();
|
||||
if (it->linear() ?
|
||||
wipe_linear(prev, p) :
|
||||
|
||||
@@ -106,31 +106,56 @@ void LayerRegion::make_perimeters(
|
||||
|
||||
// Cummulative sum of polygons over all the regions.
|
||||
const ExPolygons *lower_slices = this->layer()->lower_layer ? &this->layer()->lower_layer->lslices : nullptr;
|
||||
//w16
|
||||
const ExPolygons *upper_slices = this->layer()->upper_layer ? &this->layer()->upper_layer->lslices : nullptr;
|
||||
// Cache for offsetted lower_slices
|
||||
Polygons lower_layer_polygons_cache;
|
||||
Polygons upper_layer_polygons_cache;
|
||||
|
||||
for (const Surface &surface : slices) {
|
||||
auto perimeters_begin = uint32_t(m_perimeters.size());
|
||||
auto gap_fills_begin = uint32_t(m_thin_fills.size());
|
||||
auto fill_expolygons_begin = uint32_t(fill_expolygons.size());
|
||||
if (this->layer()->object()->config().perimeter_generator.value == PerimeterGeneratorType::Arachne && !spiral_vase)
|
||||
PerimeterGenerator::process_arachne(
|
||||
|
||||
//w16
|
||||
if (this->layer()->object()->config().top_one_wall_type == TopOneWallType::Alltop)
|
||||
PerimeterGenerator::process_with_one_wall_arachne(
|
||||
// input:
|
||||
params,
|
||||
surface,
|
||||
lower_slices,
|
||||
//w16
|
||||
upper_slices,
|
||||
lower_layer_polygons_cache,
|
||||
upper_layer_polygons_cache,
|
||||
// output:
|
||||
m_perimeters,
|
||||
m_thin_fills,
|
||||
fill_expolygons);
|
||||
else
|
||||
PerimeterGenerator::process_arachne(
|
||||
// input:
|
||||
params,
|
||||
surface,
|
||||
lower_slices,
|
||||
upper_slices,
|
||||
lower_layer_polygons_cache,
|
||||
// output:
|
||||
m_perimeters,
|
||||
m_thin_fills,
|
||||
fill_expolygons);
|
||||
|
||||
else
|
||||
PerimeterGenerator::process_classic(
|
||||
// input:
|
||||
params,
|
||||
surface,
|
||||
lower_slices,
|
||||
//w16
|
||||
upper_slices,
|
||||
lower_layer_polygons_cache,
|
||||
upper_layer_polygons_cache,
|
||||
// output:
|
||||
m_perimeters,
|
||||
m_thin_fills,
|
||||
|
||||
@@ -1069,6 +1069,37 @@ std::tuple<std::vector<ExtrusionPaths>, Polygons> generate_extra_perimeters_over
|
||||
return {extra_perims, diff(inset_overhang_area, inset_overhang_area_left_unfilled)};
|
||||
}
|
||||
|
||||
//w16
|
||||
void PerimeterGenerator::add_infill_contour_for_arachne(ExPolygons infill_contour,
|
||||
int loops,
|
||||
coord_t ext_perimeter_spacing,
|
||||
coord_t perimeter_spacing,
|
||||
coord_t min_perimeter_infill_spacing,
|
||||
coord_t spacing,
|
||||
bool is_inner_part,
|
||||
const Parameters ¶ms,
|
||||
ExPolygons &infill_areas,
|
||||
ExPolygons & out_fill_expolygons)
|
||||
{
|
||||
if (offset_ex(infill_contour, -float(spacing / 2.)).empty()) {
|
||||
infill_contour.clear();
|
||||
}
|
||||
coord_t insert = (loops < 0) ? 0 : ext_perimeter_spacing;
|
||||
if (is_inner_part || loops > 0)
|
||||
insert = perimeter_spacing;
|
||||
|
||||
insert = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale<double>(insert))));
|
||||
Polygons inner_pp;
|
||||
for (ExPolygon &ex : infill_contour)
|
||||
ex.simplify_p(params.scaled_resolution, &inner_pp);
|
||||
ExPolygons inner_union = union_ex(inner_pp);
|
||||
float offset1 = -min_perimeter_infill_spacing / 2.;
|
||||
float offset2 = insert + min_perimeter_infill_spacing / 2.;
|
||||
infill_areas = offset2_ex(inner_union, offset1, offset2);
|
||||
append(out_fill_expolygons, std::move(infill_areas));
|
||||
}
|
||||
|
||||
|
||||
// Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper
|
||||
// "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling"
|
||||
void PerimeterGenerator::process_arachne(
|
||||
@@ -1076,6 +1107,7 @@ void PerimeterGenerator::process_arachne(
|
||||
const Parameters ¶ms,
|
||||
const Surface &surface,
|
||||
const ExPolygons *lower_slices,
|
||||
const ExPolygons *upper_slices,
|
||||
// Cache:
|
||||
Polygons &lower_slices_polygons_cache,
|
||||
// Output:
|
||||
@@ -1111,6 +1143,10 @@ void PerimeterGenerator::process_arachne(
|
||||
ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.));
|
||||
Polygons last_p = to_polygons(last);
|
||||
|
||||
//w16
|
||||
if (upper_slices == nullptr && params.object_config.top_one_wall_type == TopOneWallType::Onlytopmost)
|
||||
loop_number = 0;
|
||||
|
||||
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, params.layer_height, params.object_config, params.print_config);
|
||||
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
|
||||
loop_number = int(perimeters.size()) - 1;
|
||||
@@ -1266,10 +1302,21 @@ void PerimeterGenerator::process_arachne(
|
||||
out_loops.append(extrusion_coll);
|
||||
|
||||
ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour());
|
||||
//w17
|
||||
ExPolygons the_layer_surface = infill_contour;
|
||||
const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
||||
if (offset_ex(infill_contour, -float(spacing / 2.)).empty())
|
||||
infill_contour.clear(); // Infill region is too small, so let's filter it out.
|
||||
if (params.object_config.top_one_wall_type != TopOneWallType::Disable) {
|
||||
coord_t perimeter_width = params.perimeter_flow.scaled_width();
|
||||
double min_width_top_surface = (params.object_config.top_area_threshold / 100) *
|
||||
std::max(double(ext_perimeter_spacing / 4 + 10), double(perimeter_width / 4));
|
||||
infill_contour = offset2_ex(infill_contour, -min_width_top_surface, min_width_top_surface + perimeter_width);
|
||||
ExPolygons surface_not_export_to_top = diff_ex(the_layer_surface, infill_contour);
|
||||
}
|
||||
|
||||
// BBS: get real top surface
|
||||
infill_contour = intersection_ex(infill_contour, the_layer_surface);
|
||||
// create one more offset to be used as boundary for fill
|
||||
// we offset by half the perimeter spacing (to get to the actual infill boundary)
|
||||
// and then we offset back and forth by half the infill spacing to only consider the
|
||||
@@ -1317,13 +1364,389 @@ void PerimeterGenerator::process_arachne(
|
||||
append(out_fill_expolygons, std::move(infill_areas));
|
||||
}
|
||||
|
||||
void PerimeterGenerator::process_with_one_wall_arachne(
|
||||
// Inputs:
|
||||
const Parameters ¶ms,
|
||||
const Surface &surface,
|
||||
const ExPolygons *lower_slices,
|
||||
//w16
|
||||
const ExPolygons *upper_slices,
|
||||
// Cache:
|
||||
Polygons &lower_slices_polygons_cache,
|
||||
Polygons &upper_slices_polygons_cache,
|
||||
// Output:
|
||||
// Loops with the external thin walls
|
||||
ExtrusionEntityCollection &out_loops,
|
||||
// Gaps without the thin walls
|
||||
ExtrusionEntityCollection & /* out_gap_fill */,
|
||||
// Infills without the gap fills
|
||||
ExPolygons &out_fill_expolygons)
|
||||
{
|
||||
// other perimeters
|
||||
coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing();
|
||||
// external perimeters
|
||||
coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width();
|
||||
coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing();
|
||||
coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (params.ext_perimeter_flow.spacing() + params.perimeter_flow.spacing()));
|
||||
// solid infill
|
||||
coord_t solid_infill_spacing = params.solid_infill_flow.scaled_spacing();
|
||||
|
||||
// prepare grown lower layer slices for overhang detection
|
||||
if (params.config.overhangs && lower_slices != nullptr && lower_slices_polygons_cache.empty()) {
|
||||
// We consider overhang any part where the entire nozzle diameter is not supported by the
|
||||
// lower layer, so we take lower slices and offset them by half the nozzle diameter used
|
||||
// in the current layer
|
||||
double nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder-1);
|
||||
lower_slices_polygons_cache = offset(*lower_slices, float(scale_(+nozzle_diameter/2)));
|
||||
}
|
||||
if (params.config.overhangs && upper_slices != nullptr && upper_slices_polygons_cache.empty()) {
|
||||
double upper_nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder - 1);
|
||||
upper_slices_polygons_cache = offset(*upper_slices, float(scale_(+upper_nozzle_diameter / 2)));
|
||||
}
|
||||
|
||||
|
||||
// we need to process each island separately because we might have different
|
||||
// extra perimeters for each one
|
||||
// detect how many perimeters must be generated for this island
|
||||
int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops
|
||||
ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.));
|
||||
Polygons last_p = to_polygons(last);
|
||||
|
||||
int remain_loops = -1;
|
||||
if (params.object_config.top_one_wall_type == TopOneWallType::Alltop) {
|
||||
if (upper_slices != nullptr)
|
||||
remain_loops = loop_number - 1;
|
||||
|
||||
loop_number = 0;
|
||||
}
|
||||
|
||||
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, params.layer_height, params.object_config, params.print_config);
|
||||
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
|
||||
loop_number = int(perimeters.size()) - 1;
|
||||
|
||||
|
||||
|
||||
//w16
|
||||
ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour());
|
||||
ExPolygons inner_infill_contour;
|
||||
|
||||
if (remain_loops >= 0) {
|
||||
|
||||
ExPolygons the_layer_surface = infill_contour;
|
||||
BoundingBox infill_contour_box = get_extents(infill_contour);
|
||||
infill_contour_box.offset(SCALED_EPSILON);
|
||||
Polygons upper_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(upper_slices_polygons_cache,
|
||||
infill_contour_box);
|
||||
|
||||
infill_contour = diff_ex(infill_contour, upper_polygons_series_clipped);
|
||||
|
||||
coord_t perimeter_width = params.perimeter_flow.scaled_width();
|
||||
if (lower_slices != nullptr) {
|
||||
BoundingBox infill_contour_box = get_extents(infill_contour);
|
||||
infill_contour_box.offset(SCALED_EPSILON);
|
||||
Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(lower_slices_polygons_cache,
|
||||
infill_contour_box);
|
||||
|
||||
ExPolygons bridge_area = offset_ex(diff_ex(infill_contour, lower_polygons_series_clipped),
|
||||
std::max(ext_perimeter_spacing, perimeter_width));
|
||||
infill_contour = diff_ex(infill_contour, bridge_area);
|
||||
}
|
||||
//w17
|
||||
// double min_width_top_surface = std::max(double(ext_perimeter_spacing / 4 + 10), double(perimeter_width / 4));
|
||||
double min_width_top_surface = (params.object_config.top_area_threshold / 100) * std::max(double(ext_perimeter_spacing / 4 + 10), double(perimeter_width / 4));
|
||||
infill_contour = offset2_ex(infill_contour, -min_width_top_surface, min_width_top_surface + perimeter_width);
|
||||
|
||||
ExPolygons surface_not_export_to_top = diff_ex(the_layer_surface, infill_contour);
|
||||
|
||||
infill_contour = intersection_ex(infill_contour, the_layer_surface);
|
||||
Polygons surface_not_export_to_top_p = to_polygons(surface_not_export_to_top);
|
||||
Arachne::WallToolPaths innerWallToolPaths(surface_not_export_to_top_p, perimeter_spacing, perimeter_spacing,
|
||||
coord_t(remain_loops + 1), 0, params.layer_height, params.object_config, params.print_config);
|
||||
|
||||
std::vector<Arachne::VariableWidthLines> perimeters_inner = innerWallToolPaths.getToolPaths();
|
||||
remain_loops = int(perimeters_inner.size()) - 1;
|
||||
if (!perimeters.empty()) {
|
||||
for (int perimeter_idx = 0; perimeter_idx < perimeters_inner.size(); perimeter_idx++) {
|
||||
if (perimeters_inner[perimeter_idx].empty())
|
||||
continue;
|
||||
|
||||
for (Arachne::ExtrusionLine &wall : perimeters_inner[perimeter_idx]) {
|
||||
wall.inset_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
perimeters.insert(perimeters.end(), perimeters_inner.begin(), perimeters_inner.end());
|
||||
|
||||
inner_infill_contour = union_ex(innerWallToolPaths.getInnerContour());
|
||||
}
|
||||
|
||||
#ifdef ARACHNE_DEBUG
|
||||
{
|
||||
static int iRun = 0;
|
||||
export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour()));
|
||||
}
|
||||
#endif
|
||||
|
||||
// All closed ExtrusionLine should have the same the first and the last point.
|
||||
// But in rare cases, Arachne produce ExtrusionLine marked as closed but without
|
||||
// equal the first and the last point.
|
||||
assert([&perimeters = std::as_const(perimeters)]() -> bool {
|
||||
for (const Arachne::VariableWidthLines &perimeter : perimeters)
|
||||
for (const Arachne::ExtrusionLine &el : perimeter)
|
||||
if (el.is_closed && el.junctions.front().p != el.junctions.back().p)
|
||||
return false;
|
||||
return true;
|
||||
}());
|
||||
|
||||
int start_perimeter = int(perimeters.size()) - 1;
|
||||
int end_perimeter = -1;
|
||||
int direction = -1;
|
||||
|
||||
if (params.config.external_perimeters_first) {
|
||||
start_perimeter = 0;
|
||||
end_perimeter = int(perimeters.size());
|
||||
direction = 1;
|
||||
}
|
||||
|
||||
std::vector<Arachne::ExtrusionLine *> all_extrusions;
|
||||
for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) {
|
||||
if (perimeters[perimeter_idx].empty())
|
||||
continue;
|
||||
for (Arachne::ExtrusionLine &wall : perimeters[perimeter_idx])
|
||||
all_extrusions.emplace_back(&wall);
|
||||
}
|
||||
|
||||
// Find topological order with constraints from extrusions_constrains.
|
||||
std::vector<size_t> blocked(all_extrusions.size(), 0); // Value indicating how many extrusions it is blocking (preceding extrusions) an extrusion.
|
||||
std::vector<std::vector<size_t>> blocking(all_extrusions.size()); // Each extrusion contains a vector of extrusions that are blocked by this extrusion.
|
||||
ankerl::unordered_dense::map<const Arachne::ExtrusionLine *, size_t> map_extrusion_to_idx;
|
||||
for (size_t idx = 0; idx < all_extrusions.size(); idx++)
|
||||
map_extrusion_to_idx.emplace(all_extrusions[idx], idx);
|
||||
|
||||
Arachne::WallToolPaths::ExtrusionLineSet extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, params.config.external_perimeters_first);
|
||||
for (auto [before, after] : extrusions_constrains) {
|
||||
auto after_it = map_extrusion_to_idx.find(after);
|
||||
++blocked[after_it->second];
|
||||
blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second);
|
||||
}
|
||||
|
||||
std::vector<bool> processed(all_extrusions.size(), false); // Indicate that the extrusion was already processed.
|
||||
Point current_position = all_extrusions.empty() ? Point::Zero() : all_extrusions.front()->junctions.front().p; // Some starting position.
|
||||
std::vector<PerimeterGeneratorArachneExtrusion> ordered_extrusions; // To store our result in. At the end we'll std::swap.
|
||||
ordered_extrusions.reserve(all_extrusions.size());
|
||||
|
||||
while (ordered_extrusions.size() < all_extrusions.size()) {
|
||||
size_t best_candidate = 0;
|
||||
double best_distance_sqr = std::numeric_limits<double>::max();
|
||||
bool is_best_closed = false;
|
||||
|
||||
std::vector<size_t> available_candidates;
|
||||
for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) {
|
||||
if (processed[candidate] || blocked[candidate])
|
||||
continue; // Not a valid candidate.
|
||||
available_candidates.push_back(candidate);
|
||||
}
|
||||
|
||||
std::sort(available_candidates.begin(), available_candidates.end(), [&all_extrusions](const size_t a_idx, const size_t b_idx) -> bool {
|
||||
return all_extrusions[a_idx]->is_closed < all_extrusions[b_idx]->is_closed;
|
||||
});
|
||||
|
||||
for (const size_t candidate_path_idx : available_candidates) {
|
||||
auto& path = all_extrusions[candidate_path_idx];
|
||||
|
||||
if (path->junctions.empty()) { // No vertices in the path. Can't find the start position then or really plan it in. Put that at the end.
|
||||
if (best_distance_sqr == std::numeric_limits<double>::max()) {
|
||||
best_candidate = candidate_path_idx;
|
||||
is_best_closed = path->is_closed;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const Point candidate_position = path->junctions.front().p;
|
||||
double distance_sqr = (current_position - candidate_position).cast<double>().norm();
|
||||
if (distance_sqr < best_distance_sqr) { // Closer than the best candidate so far.
|
||||
if (path->is_closed || (!path->is_closed && best_distance_sqr != std::numeric_limits<double>::max()) || (!path->is_closed && !is_best_closed)) {
|
||||
best_candidate = candidate_path_idx;
|
||||
best_distance_sqr = distance_sqr;
|
||||
is_best_closed = path->is_closed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto &best_path = all_extrusions[best_candidate];
|
||||
ordered_extrusions.push_back({best_path, best_path->is_contour(), false});
|
||||
processed[best_candidate] = true;
|
||||
for (size_t unlocked_idx : blocking[best_candidate])
|
||||
blocked[unlocked_idx]--;
|
||||
|
||||
if (!best_path->junctions.empty()) { //If all paths were empty, the best path is still empty. We don't upate the current position then.
|
||||
if(best_path->is_closed)
|
||||
current_position = best_path->junctions[0].p; //We end where we started.
|
||||
else
|
||||
current_position = best_path->junctions.back().p; //Pick the other end from where we started.
|
||||
}
|
||||
}
|
||||
|
||||
if (params.layer_id > 0 && params.config.fuzzy_skin != FuzzySkinType::None) {
|
||||
std::vector<PerimeterGeneratorArachneExtrusion *> closed_loop_extrusions;
|
||||
for (PerimeterGeneratorArachneExtrusion &extrusion : ordered_extrusions)
|
||||
if (extrusion.extrusion->inset_idx == 0) {
|
||||
if (extrusion.extrusion->is_closed && params.config.fuzzy_skin == FuzzySkinType::External) {
|
||||
closed_loop_extrusions.emplace_back(&extrusion);
|
||||
} else {
|
||||
extrusion.fuzzify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.config.fuzzy_skin == FuzzySkinType::External) {
|
||||
ClipperLib_Z::Paths loops_paths;
|
||||
loops_paths.reserve(closed_loop_extrusions.size());
|
||||
for (const auto &cl_extrusion : closed_loop_extrusions) {
|
||||
assert(cl_extrusion->extrusion->junctions.front() == cl_extrusion->extrusion->junctions.back());
|
||||
size_t loop_idx = &cl_extrusion - &closed_loop_extrusions.front();
|
||||
ClipperLib_Z::Path loop_path;
|
||||
loop_path.reserve(cl_extrusion->extrusion->junctions.size() - 1);
|
||||
for (auto junction_it = cl_extrusion->extrusion->junctions.begin(); junction_it != std::prev(cl_extrusion->extrusion->junctions.end()); ++junction_it)
|
||||
loop_path.emplace_back(junction_it->p.x(), junction_it->p.y(), loop_idx);
|
||||
loops_paths.emplace_back(loop_path);
|
||||
}
|
||||
|
||||
ClipperLib_Z::Clipper clipper;
|
||||
clipper.AddPaths(loops_paths, ClipperLib_Z::ptSubject, true);
|
||||
ClipperLib_Z::PolyTree loops_polytree;
|
||||
clipper.Execute(ClipperLib_Z::ctUnion, loops_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
|
||||
|
||||
for (const ClipperLib_Z::PolyNode *child_node : loops_polytree.Childs) {
|
||||
// The whole contour must have the same index.
|
||||
coord_t polygon_idx = child_node->Contour.front().z();
|
||||
bool has_same_idx = std::all_of(child_node->Contour.begin(), child_node->Contour.end(),
|
||||
[&polygon_idx](const ClipperLib_Z::IntPoint &point) -> bool { return polygon_idx == point.z(); });
|
||||
if (has_same_idx)
|
||||
closed_loop_extrusions[polygon_idx]->fuzzify = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions); !extrusion_coll.empty())
|
||||
out_loops.append(extrusion_coll);
|
||||
|
||||
|
||||
//w16
|
||||
if (remain_loops >= 0) {
|
||||
const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
||||
if (offset_ex(infill_contour, -float(spacing / 2.)).empty())
|
||||
infill_contour.clear();
|
||||
coord_t inset = (loop_number < 0) ? 0 :
|
||||
(loop_number == 0) ?
|
||||
// one loop
|
||||
ext_perimeter_spacing :
|
||||
// two or more loops?
|
||||
perimeter_spacing;
|
||||
|
||||
inset = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale<double>(inset))));
|
||||
Polygons pp;
|
||||
for (ExPolygon &ex : infill_contour)
|
||||
ex.simplify_p(params.scaled_resolution, &pp);
|
||||
// collapse too narrow infill areas
|
||||
const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||
// append infill areas to fill_surfaces
|
||||
ExPolygons infill_areas = offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.),
|
||||
float(inset + min_perimeter_infill_spacing / 2.));
|
||||
// ExPolygons infill_areas;
|
||||
|
||||
if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs &&
|
||||
params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) {
|
||||
// Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material
|
||||
auto [extra_perimeters, filled_area] = generate_extra_perimeters_over_overhangs(infill_areas, lower_slices_polygons_cache,
|
||||
loop_number + 1, params.overhang_flow,
|
||||
params.scaled_resolution, params.object_config,
|
||||
params.print_config);
|
||||
if (!extra_perimeters.empty()) {
|
||||
ExtrusionEntityCollection &this_islands_perimeters = static_cast<ExtrusionEntityCollection &>(*out_loops.entities.back());
|
||||
ExtrusionEntitiesPtr old_entities;
|
||||
old_entities.swap(this_islands_perimeters.entities);
|
||||
for (ExtrusionPaths &paths : extra_perimeters)
|
||||
this_islands_perimeters.append(std::move(paths));
|
||||
append(this_islands_perimeters.entities, old_entities);
|
||||
infill_areas = diff_ex(infill_areas, filled_area);
|
||||
}
|
||||
}
|
||||
|
||||
inset = (loop_number < 0) ? 0 :
|
||||
(loop_number == 0) ?
|
||||
// one loop
|
||||
ext_perimeter_spacing :
|
||||
// two or more loops?
|
||||
perimeter_spacing;
|
||||
|
||||
inset = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale<double>(inset))));
|
||||
for (ExPolygon &ex : infill_contour)
|
||||
ex.simplify_p(params.scaled_resolution, &pp);
|
||||
// collapse too narrow infill areas
|
||||
|
||||
|
||||
if (remain_loops >= 0) {
|
||||
add_infill_contour_for_arachne(infill_contour, loop_number, ext_perimeter_spacing, perimeter_spacing,
|
||||
min_perimeter_infill_spacing, spacing, true, params, infill_areas, out_fill_expolygons);
|
||||
}
|
||||
|
||||
|
||||
if (remain_loops >= 0) {
|
||||
if (!inner_infill_contour.empty())
|
||||
add_infill_contour_for_arachne(inner_infill_contour, remain_loops, ext_perimeter_spacing, perimeter_spacing,
|
||||
min_perimeter_infill_spacing, spacing, true, params, infill_areas, out_fill_expolygons);
|
||||
}
|
||||
append(out_fill_expolygons, std::move(infill_areas));
|
||||
} else {
|
||||
infill_contour = union_ex(wallToolPaths.getInnerContour());
|
||||
const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
||||
if (offset_ex(infill_contour, -float(spacing / 2.)).empty())
|
||||
infill_contour.clear(); // Infill region is too small, so let's filter it out.
|
||||
|
||||
coord_t inset = (loop_number < 0) ? 0 : (loop_number == 0) ? ext_perimeter_spacing : perimeter_spacing;
|
||||
|
||||
inset = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale<double>(inset))));
|
||||
Polygons pp;
|
||||
for (ExPolygon &ex : infill_contour)
|
||||
ex.simplify_p(params.scaled_resolution, &pp);
|
||||
// collapse too narrow infill areas
|
||||
const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||
// append infill areas to fill_surfaces
|
||||
ExPolygons infill_areas = offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.),
|
||||
float(inset + min_perimeter_infill_spacing / 2.));
|
||||
|
||||
if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs &&
|
||||
params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) {
|
||||
// Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material
|
||||
auto [extra_perimeters, filled_area] = generate_extra_perimeters_over_overhangs(infill_areas, lower_slices_polygons_cache,
|
||||
loop_number + 1, params.overhang_flow,
|
||||
params.scaled_resolution, params.object_config,
|
||||
params.print_config);
|
||||
if (!extra_perimeters.empty()) {
|
||||
ExtrusionEntityCollection &this_islands_perimeters = static_cast<ExtrusionEntityCollection &>(*out_loops.entities.back());
|
||||
ExtrusionEntitiesPtr old_entities;
|
||||
old_entities.swap(this_islands_perimeters.entities);
|
||||
for (ExtrusionPaths &paths : extra_perimeters)
|
||||
this_islands_perimeters.append(std::move(paths));
|
||||
append(this_islands_perimeters.entities, old_entities);
|
||||
infill_areas = diff_ex(infill_areas, filled_area);
|
||||
}
|
||||
}
|
||||
|
||||
append(out_fill_expolygons, std::move(infill_areas));
|
||||
}
|
||||
}
|
||||
|
||||
void PerimeterGenerator::process_classic(
|
||||
// Inputs:
|
||||
const Parameters ¶ms,
|
||||
const Surface &surface,
|
||||
const ExPolygons *lower_slices,
|
||||
//w16
|
||||
const ExPolygons *upper_slices,
|
||||
// Cache:
|
||||
Polygons &lower_slices_polygons_cache,
|
||||
Polygons &upper_layer_polygons_cache,
|
||||
// Output:
|
||||
// Loops with the external thin walls
|
||||
ExtrusionEntityCollection &out_loops,
|
||||
@@ -1371,6 +1794,11 @@ void PerimeterGenerator::process_classic(
|
||||
int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops
|
||||
ExPolygons last = union_ex(surface.expolygon.simplify_p(params.scaled_resolution));
|
||||
ExPolygons gaps;
|
||||
//w16
|
||||
ExPolygons fill_clip;
|
||||
ExPolygons top_fills;
|
||||
if (loop_number > 0 && params.object_config.top_one_wall_type != TopOneWallType::Disable && upper_slices == nullptr)
|
||||
loop_number = 0;
|
||||
if (loop_number >= 0) {
|
||||
// In case no perimeters are to be generated, loop_number will equal to -1.
|
||||
std::vector<PerimeterGeneratorLoops> contours(loop_number+1); // depth => loops
|
||||
@@ -1410,20 +1838,22 @@ void PerimeterGenerator::process_classic(
|
||||
//FIXME Is this offset correct if the line width of the inner perimeters differs
|
||||
// from the line width of the infill?
|
||||
coord_t distance = (i == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
||||
offsets = params.config.thin_walls ?
|
||||
//w16
|
||||
//offsets = params.config.thin_walls ?
|
||||
// This path will ensure, that the perimeters do not overfill, as in
|
||||
// qidi3d/Slic3r GH #32, but with the cost of rounding the perimeters
|
||||
// excessively, creating gaps, which then need to be filled in by the not very
|
||||
// reliable gap fill algorithm.
|
||||
// Also the offset2(perimeter, -x, x) may sometimes lead to a perimeter, which is larger than
|
||||
// the original.
|
||||
offset2_ex(last,
|
||||
- float(distance + min_spacing / 2. - 1.),
|
||||
float(min_spacing / 2. - 1.)) :
|
||||
//offset2_ex(last,
|
||||
// - float(distance + min_spacing / 2. - 1.),
|
||||
// float(min_spacing / 2. - 1.)) :
|
||||
// If "detect thin walls" is not enabled, this paths will be entered, which
|
||||
// leads to overflows, as in qidi3d/Slic3r GH #32
|
||||
offset_ex(last, - float(distance));
|
||||
// offset_ex(last, - float(distance));
|
||||
// look for gaps
|
||||
offsets = offset2_ex(last, -float(distance + min_spacing / 2. - 1.), float(min_spacing / 2. - 1.));
|
||||
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
|
||||
@@ -1461,6 +1891,55 @@ void PerimeterGenerator::process_classic(
|
||||
}
|
||||
}
|
||||
last = std::move(offsets);
|
||||
|
||||
//w16
|
||||
if (i == 0 && i != loop_number && params.object_config.top_one_wall_type == TopOneWallType::Alltop &&
|
||||
upper_slices != nullptr) {
|
||||
coord_t offset_top_surface = scale_(
|
||||
1.5 * (params.config.perimeters.value == 0 ?
|
||||
0. :
|
||||
unscaled(double(ext_perimeter_width + perimeter_spacing * int(int(params.config.perimeters.value) - int(1))))));
|
||||
if (offset_top_surface > 0.9 * (params.config.perimeters.value <= 1 ? 0. : (perimeter_spacing * (params.config.perimeters.value - 1))))
|
||||
offset_top_surface -= coord_t(
|
||||
0.9 * (params.config.perimeters.value <= 1 ? 0. : (perimeter_spacing * (params.config.perimeters.value - 1))));
|
||||
else
|
||||
offset_top_surface = 0;
|
||||
//w17
|
||||
double min_width_top_surface = (params.object_config.top_area_threshold/100 ) *
|
||||
std::max(double(ext_perimeter_spacing / 2 + 10), 1.0 * (double(perimeter_width)));
|
||||
BoundingBox last_box = get_extents(last);
|
||||
last_box.offset(SCALED_EPSILON);
|
||||
Polygons upper_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(upper_layer_polygons_cache,
|
||||
last_box);
|
||||
upper_polygons_series_clipped = offset(upper_polygons_series_clipped, min_width_top_surface);
|
||||
fill_clip = offset_ex(last, -double(ext_perimeter_spacing));
|
||||
ExPolygons grown_lower_slices;
|
||||
ExPolygons bridge_checker;
|
||||
if (lower_slices != nullptr) {
|
||||
Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(lower_slices_polygons_cache,
|
||||
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);
|
||||
}
|
||||
ExPolygons delete_bridge = diff_ex(last, bridge_checker, ApplySafetyOffset::Yes);
|
||||
|
||||
ExPolygons top_polygons = diff_ex(delete_bridge, upper_polygons_series_clipped, ApplySafetyOffset::Yes);
|
||||
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);
|
||||
top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes);
|
||||
top_fills = union_ex(top_fills, top_polygons);
|
||||
double infill_spacing_unscaled = params.config.infill_extrusion_width.value; // 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);
|
||||
if (has_gap_fill)
|
||||
last = union_ex(last, temp_gap);
|
||||
}
|
||||
|
||||
|
||||
if (i == loop_number && (! has_gap_fill || params.config.fill_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
|
||||
@@ -1590,6 +2069,10 @@ void PerimeterGenerator::process_classic(
|
||||
float(- inset - min_perimeter_infill_spacing / 2.),
|
||||
float(min_perimeter_infill_spacing / 2.));
|
||||
|
||||
ExPolygons top_infill_exp = intersection_ex(fill_clip, offset_ex(top_fills, double(ext_perimeter_spacing / 2)));
|
||||
|
||||
append(out_fill_expolygons, std::move(top_infill_exp));
|
||||
|
||||
if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs &&
|
||||
params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) {
|
||||
// Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material
|
||||
|
||||
@@ -70,8 +70,11 @@ void process_classic(
|
||||
const Parameters ¶ms,
|
||||
const Surface &surface,
|
||||
const ExPolygons *lower_slices,
|
||||
//w16
|
||||
const ExPolygons *upper_slices,
|
||||
// Cache:
|
||||
Polygons &lower_slices_polygons_cache,
|
||||
Polygons &upper_slices_polygons_cache,
|
||||
// Output:
|
||||
// Loops with the external thin walls
|
||||
ExtrusionEntityCollection &out_loops,
|
||||
@@ -81,12 +84,32 @@ void process_classic(
|
||||
ExPolygons &out_fill_expolygons);
|
||||
|
||||
void process_arachne(
|
||||
// Inputs:
|
||||
const Parameters ¶ms,
|
||||
const Surface & surface,
|
||||
const ExPolygons *lower_slices,
|
||||
//w16
|
||||
const ExPolygons *upper_slices,
|
||||
// Cache:
|
||||
Polygons &lower_slices_polygons_cache,
|
||||
// Output:
|
||||
// Loops with the external thin walls
|
||||
ExtrusionEntityCollection &out_loops,
|
||||
// Gaps without the thin walls
|
||||
ExtrusionEntityCollection &out_gap_fill,
|
||||
// Infills without the gap fills
|
||||
ExPolygons &out_fill_expolygons);
|
||||
|
||||
void process_with_one_wall_arachne(
|
||||
// Inputs:
|
||||
const Parameters ¶ms,
|
||||
const Surface &surface,
|
||||
const ExPolygons *lower_slices,
|
||||
//w16
|
||||
const ExPolygons *upper_slices,
|
||||
// Cache:
|
||||
Polygons &lower_slices_polygons_cache,
|
||||
Polygons &upper_slices_polygons_cache,
|
||||
// Output:
|
||||
// Loops with the external thin walls
|
||||
ExtrusionEntityCollection &out_loops,
|
||||
@@ -95,6 +118,18 @@ void process_arachne(
|
||||
// Infills without the gap fills
|
||||
ExPolygons &out_fill_expolygons);
|
||||
|
||||
//w16
|
||||
void add_infill_contour_for_arachne(ExPolygons infill_contour,
|
||||
int loops,
|
||||
coord_t ext_perimeter_spacing,
|
||||
coord_t perimeter_spacing,
|
||||
coord_t min_perimeter_infill_spacing,
|
||||
coord_t spacing,
|
||||
bool is_inner_part,
|
||||
const Parameters ¶ms,
|
||||
ExPolygons & infill_areas,
|
||||
ExPolygons & out_fill_expolygons);
|
||||
|
||||
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance);
|
||||
|
||||
} // namespace PerimeterGenerator
|
||||
|
||||
@@ -473,6 +473,12 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
,"first_layer_infill_speed"
|
||||
//w11
|
||||
,"detect_narrow_internal_solid_infill"
|
||||
//Y21
|
||||
,"seam_gap"
|
||||
//w16
|
||||
, "top_one_wall_type"
|
||||
//w17
|
||||
,"top_area_threshold"
|
||||
};
|
||||
|
||||
static std::vector<std::string> s_Preset_filament_options {
|
||||
|
||||
@@ -142,6 +142,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"retract_restart_extra",
|
||||
"retract_restart_extra_toolchange",
|
||||
"retract_speed",
|
||||
//Y21
|
||||
"seam_gap",
|
||||
"single_extruder_multi_material_priming",
|
||||
"slowdown_below_layer_time",
|
||||
"solid_infill_acceleration",
|
||||
|
||||
@@ -236,6 +236,12 @@ static t_config_enum_values s_keys_map_PerimeterGeneratorType {
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PerimeterGeneratorType)
|
||||
|
||||
//w16
|
||||
static t_config_enum_values s_keys_map_TopOneWallType{{"disable", int(TopOneWallType::Disable)},
|
||||
{"all_top", int(TopOneWallType::Alltop)},
|
||||
{"only_top_most", int(TopOneWallType::Onlytopmost)}};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TopOneWallType)
|
||||
|
||||
static void assign_printer_technology_to_unknown(t_optiondef_map &options, PrinterTechnology printer_technology)
|
||||
{
|
||||
for (std::pair<const t_config_option_key, ConfigOptionDef> &kvp : options)
|
||||
@@ -2533,6 +2539,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionEnum<SeamPosition>(spAligned));
|
||||
|
||||
//Y21
|
||||
def = this->add("seam_gap", coPercent);
|
||||
def->label = L("Seam gap");
|
||||
def->tooltip = L("In order to reduce the visibility of the seam in a closed loop extrusion, the loop is interrupted and shortened by a specified amount.\n" "This amount as a percentage of the current extruder diameter. The default value for this parameter is 15");
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionPercent(15));
|
||||
|
||||
def = this->add("staggered_inner_seams", coBool);
|
||||
def->label = L("Staggered inner seams");
|
||||
// TRN PrintSettings: "Staggered inner seams"
|
||||
@@ -3522,6 +3537,29 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<PerimeterGeneratorType>(PerimeterGeneratorType::Arachne));
|
||||
|
||||
//w16
|
||||
def = this->add("top_one_wall_type", coEnum);
|
||||
def->label = L("Only one wall on top surfaces");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Use only one wall on flat top surface, to give more space to the top infill pattern. Could be applyed on topmost surface or all top surface.");
|
||||
def->set_enum<TopOneWallType>({
|
||||
{ "disable", L("Disable") },
|
||||
{ "all_top", L("All top") },
|
||||
{ "only_top_most", L("Only top most") }
|
||||
});
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<TopOneWallType>(TopOneWallType::Alltop));
|
||||
|
||||
//w17
|
||||
def = this->add("top_area_threshold", coPercent);
|
||||
def->label = L("Top area threshold");
|
||||
def->tooltip = L("This factor affects the acreage of top area. The small the number the big the top area.");
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->max = 500;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionPercent(100));
|
||||
|
||||
def = this->add("wall_transition_length", coFloatOrPercent);
|
||||
def->label = L("Perimeter transition length");
|
||||
def->category = L("Advanced");
|
||||
|
||||
@@ -144,6 +144,9 @@ enum class PerimeterGeneratorType
|
||||
//B3
|
||||
enum class GCodeThumbnailsFormat { QIDI,PNG, JPG, QOI };
|
||||
|
||||
//w16
|
||||
enum class TopOneWallType { Disable, Alltop, Onlytopmost };
|
||||
|
||||
#define CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NAME) \
|
||||
template<> const t_config_enum_names& ConfigOptionEnum<NAME>::get_enum_names(); \
|
||||
template<> const t_config_enum_values& ConfigOptionEnum<NAME>::get_enum_values();
|
||||
@@ -524,6 +527,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionFloat, raft_first_layer_expansion))
|
||||
((ConfigOptionInt, raft_layers))
|
||||
((ConfigOptionEnum<SeamPosition>, seam_position))
|
||||
//Y21
|
||||
((ConfigOptionPercent, seam_gap))
|
||||
((ConfigOptionBool, staggered_inner_seams))
|
||||
// ((ConfigOptionFloat, seam_preferred_direction))
|
||||
// ((ConfigOptionFloat, seam_preferred_direction_jitter))
|
||||
@@ -585,6 +590,10 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionBool, wipe_into_objects))
|
||||
//w11
|
||||
((ConfigOptionBool, detect_narrow_internal_solid_infill))
|
||||
//w16
|
||||
((ConfigOptionEnum<TopOneWallType>, top_one_wall_type))
|
||||
//w17
|
||||
((ConfigOptionPercent, top_area_threshold))
|
||||
)
|
||||
|
||||
PRINT_CONFIG_CLASS_DEFINE(
|
||||
|
||||
@@ -864,10 +864,16 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
|| opt_key == "wall_transition_angle"
|
||||
|| opt_key == "wall_distribution_count"
|
||||
|| opt_key == "min_feature_size"
|
||||
|| opt_key == "min_bead_width") {
|
||||
|| opt_key == "min_bead_width"
|
||||
//w16
|
||||
|| opt_key == "top_one_wall_type"
|
||||
//w17
|
||||
|| opt_key == "top_area_threshold") {
|
||||
steps.emplace_back(posSlice);
|
||||
} else if (
|
||||
opt_key == "seam_position"
|
||||
//Y21
|
||||
|| opt_key == "seam_gap"
|
||||
|| opt_key == "seam_preferred_direction"
|
||||
|| opt_key == "seam_preferred_direction_jitter"
|
||||
|| opt_key == "support_material_speed"
|
||||
|
||||
@@ -403,11 +403,12 @@ wxBitmapBundle* BitmapCache::from_svg(const std::string& bitmap_name, unsigned t
|
||||
return it->second;
|
||||
|
||||
// map of color replaces
|
||||
//B48
|
||||
std::map<std::string, std::string> replaces;
|
||||
if (dark_mode)
|
||||
replaces["#808080"] = "#FFFFFF";
|
||||
if (!new_color.empty())
|
||||
replaces["#ED6B21"] = new_color;
|
||||
replaces["#4479FB"] = new_color;
|
||||
|
||||
replaces["#ButtonBG"] = dark_mode ? "#4E4E4E" : "#828282";
|
||||
|
||||
@@ -461,11 +462,12 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
|
||||
return it->second;
|
||||
|
||||
// map of color replaces
|
||||
//B48
|
||||
std::map<std::string, std::string> replaces;
|
||||
if (dark_mode)
|
||||
replaces["#808080"] = "#FFFFFF";
|
||||
if (!new_color.empty())
|
||||
replaces["#ED6B21"] = new_color;
|
||||
replaces["#4479FB"] = new_color;
|
||||
|
||||
NSVGimage *image = nsvgParseFromFileWithReplace(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f, replaces);
|
||||
if (image == nullptr)
|
||||
|
||||
@@ -244,7 +244,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||
{
|
||||
bool have_perimeters = config->opt_int("perimeters") > 0;
|
||||
for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "thin_walls", "overhangs",
|
||||
"seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
// Y21
|
||||
"seam_position","seam_gap","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds"})
|
||||
toggle_field(el, have_perimeters);
|
||||
|
||||
@@ -370,6 +371,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||
toggle_field("min_feature_size", have_arachne);
|
||||
toggle_field("min_bead_width", have_arachne);
|
||||
toggle_field("thin_walls", !have_arachne);
|
||||
|
||||
bool is_top_one_wall = config->opt_enum<TopOneWallType>("top_one_wall_type") != TopOneWallType::Disable;
|
||||
toggle_field("top_area_threshold", is_top_one_wall);
|
||||
|
||||
}
|
||||
|
||||
void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)
|
||||
|
||||
@@ -321,7 +321,13 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d &mous
|
||||
return ;
|
||||
|
||||
// NOTE: change style manager - be carefull with order changes
|
||||
#if defined(__linux__)
|
||||
m_style_manager.get_font_prop().size_in_mm = 8;
|
||||
#elif defined(__APPLE__)
|
||||
m_style_manager.get_font_prop().size_in_mm = 9.2;
|
||||
#else
|
||||
m_style_manager.get_font_prop().size_in_mm = 7;
|
||||
#endif
|
||||
|
||||
DataBasePtr base = create_emboss_data_base(str, m_style_manager, m_text_lines, m_parent.get_selection(), volume_type, m_job_cancel);
|
||||
CreateVolumeParams input = create_input(m_parent, m_style_manager.get_style(), m_raycast_manager, volume_type);
|
||||
|
||||
@@ -1655,6 +1655,14 @@ void MainFrame::init_menubar_as_editor()
|
||||
m_pa_calib_dlg->ShowModal();
|
||||
},
|
||||
"", nullptr, [this]() { return m_plater->is_view3D_shown(); }, this);
|
||||
|
||||
append_menu_item(calibrationMenu, wxID_ANY, _L("Max Volumetric Speed"), _L("Max Volumetric Speed"),
|
||||
[this](wxCommandEvent &) {
|
||||
if (!m_mvs_calib_dlg)
|
||||
m_mvs_calib_dlg = new MVS_Calibration_Dlg((wxWindow *) this, wxID_ANY, m_plater);
|
||||
m_mvs_calib_dlg->ShowModal();
|
||||
},
|
||||
"", nullptr, [this]() { return m_plater->is_view3D_shown(); }, this);
|
||||
}
|
||||
|
||||
// menubar
|
||||
|
||||
@@ -217,6 +217,7 @@ public:
|
||||
FRF_Calibration_Dlg *m_frf_calib_dlg{nullptr};
|
||||
//B34
|
||||
PA_Calibration_Dlg *m_pa_calib_dlg{nullptr};
|
||||
MVS_Calibration_Dlg *m_mvs_calib_dlg{nullptr};
|
||||
//B4
|
||||
wxString tem_host;
|
||||
PrinterWebView * m_printer_view{nullptr};
|
||||
|
||||
@@ -5543,7 +5543,7 @@ void Plater::calib_pa_line(const double StartPA, double EndPA, double PAStep)
|
||||
// Check step count
|
||||
double step_spacing = 4.62;
|
||||
const Vec2d plate_center = build_volume().bed_center();
|
||||
int count = int((EndPA - StartPA) / PAStep);
|
||||
int count = int((EndPA - StartPA) / PAStep + 0.0001);
|
||||
int max_count = int(plate_center.y() / step_spacing * 2) - 4;
|
||||
if (count > max_count) {
|
||||
count = max_count;
|
||||
@@ -5555,7 +5555,7 @@ void Plater::calib_pa_line(const double StartPA, double EndPA, double PAStep)
|
||||
DynamicPrintConfig new_config;
|
||||
|
||||
//B34 Get parameter
|
||||
double start_x = plate_center.x() - 40;
|
||||
double start_x = plate_center.x() - 38;
|
||||
double start_y = plate_center.y() - count * step_spacing / 2;
|
||||
const double speed_fast = 7200;
|
||||
const double speed_slow = 1200;
|
||||
@@ -5582,9 +5582,11 @@ void Plater::calib_pa_line(const double StartPA, double EndPA, double PAStep)
|
||||
const double e_per_mm = line_flow.mm3_per_mm() / filament_area * print_flow_ratio;
|
||||
|
||||
// Position aided model
|
||||
select_all();
|
||||
wxGetApp().plater()->get_camera().select_view("top");
|
||||
sidebar().obj_manipul()->on_change("position", 0, plate_center.x() - 50);
|
||||
sidebar().obj_manipul()->set_uniform_scaling(false);
|
||||
sidebar().obj_manipul()->on_change("size", 0, 25);
|
||||
sidebar().obj_manipul()->on_change("size", 1, count * step_spacing + pa_line_width);
|
||||
sidebar().obj_manipul()->on_change("size", 2, pa_first_layer_height);
|
||||
sidebar().obj_manipul()->set_uniform_scaling(true);
|
||||
@@ -5648,7 +5650,7 @@ void Plater::calib_pa_pattern(const double StartPA, double EndPA, double PAStep)
|
||||
|
||||
// Check step count
|
||||
const Vec2d plate_center = build_volume().bed_center();
|
||||
int count = int((EndPA - StartPA) / PAStep);
|
||||
int count = int((EndPA - StartPA) / PAStep + 0.0001);
|
||||
|
||||
Tab *tab_printer = wxGetApp().get_tab(Preset::TYPE_PRINTER);
|
||||
|
||||
@@ -5676,7 +5678,7 @@ void Plater::calib_pa_pattern(const double StartPA, double EndPA, double PAStep)
|
||||
const double step_spacing = 4.62;
|
||||
double line_spacing = pa_line_width - pa_layer_height * (1 - M_PI / 4);
|
||||
double line_spacing_xy = line_spacing * 1.4142;
|
||||
const double pa_wall_length = 42 - line_spacing;
|
||||
const double pa_wall_length = 38 - line_spacing;
|
||||
int max_count = int((plate_center.y() * 2 - pa_wall_length / 2) / step_spacing) - 4;
|
||||
if (count > max_count) {
|
||||
count = max_count;
|
||||
@@ -5694,9 +5696,11 @@ void Plater::calib_pa_pattern(const double StartPA, double EndPA, double PAStep)
|
||||
double retract_speed = double(printer_config->opt_float("retract_speed", 0)) * 60;
|
||||
|
||||
// Position aided model
|
||||
select_all();
|
||||
wxGetApp().plater()->get_camera().select_view("top");
|
||||
sidebar().obj_manipul()->on_change("position", 0, plate_center.x() - 31);
|
||||
sidebar().obj_manipul()->set_uniform_scaling(false);
|
||||
sidebar().obj_manipul()->on_change("size", 0, 25);
|
||||
sidebar().obj_manipul()->on_change("size", 1, pa_wall_width + line_spacing);
|
||||
double pa_first_layer_height = print_config->get_abs_value("first_layer_height");
|
||||
sidebar().obj_manipul()->on_change("size", 2, pa_first_layer_height);
|
||||
@@ -5789,13 +5793,14 @@ void Plater::calib_pa_tower(const double StartPA, double EndPA, double PAStep)
|
||||
auto pa_end_gcode = printer_config->opt_string("before_layer_gcode");
|
||||
|
||||
// Check step count
|
||||
double count = floor((EndPA - StartPA) / PAStep);
|
||||
double max_count = floor(max_print_height/5) - 1;
|
||||
double count = floor((EndPA - StartPA) / PAStep + 0.0001);
|
||||
double max_count = floor(max_print_height/5 + 0.0001) - 1;
|
||||
if (count > max_count) {
|
||||
count = max_count;
|
||||
}
|
||||
|
||||
// Scale model height
|
||||
select_all();
|
||||
sidebar().obj_manipul()->set_uniform_scaling(false);
|
||||
sidebar().obj_manipul()->on_change("size", 2, (count + 1) * 5);
|
||||
sidebar().obj_manipul()->set_uniform_scaling(true);
|
||||
@@ -5811,6 +5816,92 @@ void Plater::calib_pa_tower(const double StartPA, double EndPA, double PAStep)
|
||||
std::string message = _u8L("NOTICE: The calibration function modifies some parameters. After calibration, record the best value and restore the other parameters.");
|
||||
get_notification_manager()->push_notification(NotificationType::CustomNotification, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, message);
|
||||
}
|
||||
//Y22
|
||||
void Plater::calib_max_volumetric_speed(const double StartVS, double EndVS, double VSStep)
|
||||
{
|
||||
new_project();
|
||||
wxGetApp().mainframe->select_tab(size_t(0));
|
||||
|
||||
std::vector<fs::path> model_path;
|
||||
model_path.emplace_back(Slic3r::resources_dir() + "/calib/VolumetricSpeed/volumetric_speed.stl");
|
||||
load_files(model_path, true, false, false);
|
||||
p->set_project_filename("Max Volumetric Speed");
|
||||
|
||||
DynamicPrintConfig *printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
double nozzle_diameter = double(printer_config->opt_float("nozzle_diameter", 0));
|
||||
double vs_layer_height = nozzle_diameter * 0.8;
|
||||
double vs_external_perimeter_extrusion_width = nozzle_diameter * 1.75;
|
||||
auto max_print_height = build_volume().max_print_height();
|
||||
|
||||
float res = float(vs_layer_height * (vs_external_perimeter_extrusion_width - vs_layer_height * (1. - 0.25 * PI)));
|
||||
float start_speed = StartVS / res;
|
||||
float end_speed = EndVS / res;
|
||||
float step_speed = VSStep / res;
|
||||
|
||||
double count = floor((EndVS - StartVS) / VSStep + 1.0001);
|
||||
double max_count = floor(max_print_height / vs_layer_height + 0.0001);
|
||||
if (count > max_count) {
|
||||
count = max_count;
|
||||
}
|
||||
|
||||
DynamicPrintConfig new_config;
|
||||
new_config.set_key_value("max_layer_height", new ConfigOptionFloats{vs_layer_height});
|
||||
new_config.set_key_value("layer_height", new ConfigOptionFloat(vs_layer_height));
|
||||
new_config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(vs_layer_height, false));
|
||||
new_config.set_key_value("perimeters", new ConfigOptionInt(1));
|
||||
new_config.set_key_value("top_solid_layers", new ConfigOptionInt(0));
|
||||
new_config.set_key_value("bottom_solid_layers", new ConfigOptionInt(0));
|
||||
new_config.set_key_value("fill_density", new ConfigOptionPercent(0));
|
||||
new_config.set_key_value("brim_width", new ConfigOptionFloat(5));
|
||||
new_config.set_key_value("brim_separation", new ConfigOptionFloat(0));
|
||||
new_config.set_key_value("first_layer_speed", new ConfigOptionFloatOrPercent(start_speed, false));
|
||||
new_config.set_key_value("external_perimeter_extrusion_width", new ConfigOptionFloatOrPercent(vs_external_perimeter_extrusion_width, false));
|
||||
new_config.set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(vs_external_perimeter_extrusion_width, false));
|
||||
new_config.set_key_value("extrusion_multiplier", new ConfigOptionFloats{1});
|
||||
|
||||
Tab *tab_print = wxGetApp().get_tab(Preset::TYPE_PRINT);
|
||||
Tab *tab_filament = wxGetApp().get_tab(Preset::TYPE_FILAMENT);
|
||||
Tab *tab_printer = wxGetApp().get_tab(Preset::TYPE_PRINTER);
|
||||
tab_print->load_config(new_config);
|
||||
tab_filament->load_config(new_config);
|
||||
tab_printer->load_config(new_config);
|
||||
|
||||
select_all();
|
||||
sidebar().obj_manipul()->set_uniform_scaling(false);
|
||||
sidebar().obj_manipul()->on_change("size", 2, count * vs_layer_height);
|
||||
sidebar().obj_manipul()->set_uniform_scaling(true);
|
||||
|
||||
sidebar().obj_list()->layers_editing();
|
||||
|
||||
const int obj_idx = sidebar().obj_list()->get_selected_obj_idx();
|
||||
auto& ranges = sidebar().obj_list()->object(obj_idx)->layer_config_ranges;
|
||||
const auto layers_item = sidebar().obj_list()->GetSelection();
|
||||
|
||||
const t_layer_height_range default_range = {0.0, 2.0};
|
||||
const t_layer_height_range first_range = {vs_layer_height, vs_layer_height * 2};
|
||||
wxDataViewItem layer_item = sidebar().obj_list()->GetModel()->GetItemByLayerRange(obj_idx, default_range);
|
||||
ModelConfig& model_config = sidebar().obj_list()->get_item_config(layer_item);
|
||||
model_config.set_key_value("external_perimeter_speed", new ConfigOptionFloatOrPercent(start_speed + step_speed, false));
|
||||
sidebar().obj_list()->show_settings(sidebar().obj_list()->add_settings_item(layer_item, &model_config.get()));
|
||||
sidebar().obj_list()->edit_layer_range(default_range, first_range, true);
|
||||
|
||||
for (int n = 2; n < count; n++) {
|
||||
const t_layer_height_range new_range = {2.0 * n, 2.0 * (n + 1)};
|
||||
ranges[new_range].assign_config(sidebar().obj_list()->get_default_layer_config(obj_idx));
|
||||
sidebar().obj_list()->add_layer_item(new_range, layers_item);
|
||||
|
||||
wxDataViewItem layer_item = sidebar().obj_list()->GetModel()->GetItemByLayerRange(obj_idx, new_range);
|
||||
ModelConfig& model_config = sidebar().obj_list()->get_item_config(layer_item);
|
||||
model_config.set_key_value("external_perimeter_speed", new ConfigOptionFloatOrPercent(start_speed + step_speed * n, false));
|
||||
sidebar().obj_list()->show_settings(sidebar().obj_list()->add_settings_item(layer_item, &model_config.get()));
|
||||
|
||||
const t_layer_height_range range = {vs_layer_height * n, vs_layer_height * (n + 1)};
|
||||
sidebar().obj_list()->edit_layer_range(new_range, range, true);
|
||||
}
|
||||
|
||||
std::string message = _u8L("NOTICE: The calibration function modifies some parameters. After calibration, record the best value and restore the other parameters.");
|
||||
get_notification_manager()->push_notification(NotificationType::CustomNotification, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, message);
|
||||
}
|
||||
//B34
|
||||
std::string Plater::move_to(const Vec2d &point, double speed, double retract_length, double retract_speed, double height, double retract_lift)
|
||||
{
|
||||
@@ -7820,14 +7911,40 @@ void Plater::send_gcode()
|
||||
wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_notes"));
|
||||
}
|
||||
|
||||
//B53
|
||||
auto pppd = dlg.pppd();
|
||||
auto checkbox_states = dlg.checkbox_states();
|
||||
for (int i = 0; i < pppd.size(); i++) {
|
||||
if (checkbox_states[i]) {
|
||||
PresetBundle &preset_bundle = *wxGetApp().preset_bundle;
|
||||
auto m_collection = &preset_bundle.printers;
|
||||
auto preset_data = pppd[i];
|
||||
|
||||
Preset *preset = m_collection->find_preset((preset_data.name).ToStdString());
|
||||
if (!preset || !preset->is_visible)
|
||||
continue;
|
||||
wxStringTokenizer tokenizer((preset_data.fullname), "*");
|
||||
|
||||
std::string tem_name = (into_u8(tokenizer.GetNextToken().Trim().mb_str()));
|
||||
auto * printer = preset_bundle.physical_printers.find_printer(tem_name);
|
||||
|
||||
if (printer == nullptr)
|
||||
return;
|
||||
DynamicPrintConfig *cfg_t = &(printer->config);
|
||||
|
||||
PrintHostJob upload_job(cfg_t);
|
||||
if (upload_job.empty())
|
||||
return;
|
||||
upload_job.upload_data.upload_path = dlg.filename();
|
||||
upload_job.upload_data.post_action = dlg.post_action();
|
||||
upload_job.upload_data.group = dlg.group();
|
||||
upload_job.upload_data.storage = dlg.storage();
|
||||
|
||||
// Show "Is printer clean" dialog for PrusaConnect - Upload and print.
|
||||
if (std::string(upload_job.printhost->get_name()) == "PrusaConnect" && upload_job.upload_data.post_action == PrintHostPostUploadAction::StartPrint) {
|
||||
GUI::MessageDialog dlg(nullptr, _L("Is the printer ready? Is the print sheet in place, empty and clean?"), _L("Upload and Print"), wxOK | wxCANCEL);
|
||||
if (std::string(upload_job.printhost->get_name()) == "PrusaConnect" &&
|
||||
upload_job.upload_data.post_action == PrintHostPostUploadAction::StartPrint) {
|
||||
GUI::MessageDialog dlg(nullptr, _L("Is the printer ready? Is the print sheet in place, empty and clean?"),
|
||||
_L("Upload and Print"), wxOK | wxCANCEL);
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
return;
|
||||
}
|
||||
@@ -7835,6 +7952,8 @@ void Plater::send_gcode()
|
||||
p->export_gcode(fs::path(), false, std::move(upload_job));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the Eject button is pressed.
|
||||
void Plater::eject_drive()
|
||||
|
||||
@@ -176,6 +176,7 @@ public:
|
||||
void calib_pa_tower(const double StartPA, double EndPA, double PAStep);
|
||||
void calib_flowrate_coarse();
|
||||
void calib_flowrate_fine(const double target_extrusion_multiplier);
|
||||
void calib_max_volumetric_speed(const double StartVS, double EndVS, double VSStep);
|
||||
std::string move_to(const Vec2d &point, double speed, double retract_length, double retract_speed, double height, double retract_lift);
|
||||
std::string move_to(const Vec2d &point, double speed, double retract_length, double retract_speed);
|
||||
std::string move_to(const Vec2d &point, double speed, double e);
|
||||
|
||||
@@ -59,6 +59,41 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo
|
||||
content_sizer->Add(txt_filename, 0, wxEXPAND);
|
||||
content_sizer->Add(label_dir_hint);
|
||||
content_sizer->AddSpacer(VERT_SPACING);
|
||||
//B53
|
||||
wxBoxSizer * checkbox_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
PresetBundle & preset_bundle = *wxGetApp().preset_bundle;
|
||||
|
||||
wxButton* select_all_btn = new wxButton(this, wxID_ANY, _L("Select All"));
|
||||
wxGetApp().SetWindowVariantForButton(select_all_btn);
|
||||
checkbox_sizer->Add(select_all_btn, 0, wxEXPAND | wxALL, 5);
|
||||
select_all_btn->Bind(wxEVT_BUTTON, [checkbox_sizer](wxCommandEvent &event) {
|
||||
for (int i = 0; i < checkbox_sizer->GetItemCount(); i++) {
|
||||
wxCheckBox *checkbox = dynamic_cast<wxCheckBox *>(checkbox_sizer->GetItem(i)->GetWindow());
|
||||
if (checkbox) {
|
||||
checkbox->SetValue(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const PhysicalPrinterCollection & ph_printers = preset_bundle.physical_printers;
|
||||
std::vector<PhysicalPrinterPresetData> preset_data;
|
||||
for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) {
|
||||
for (const std::string &preset_name : it->get_preset_names()) {
|
||||
Preset *preset = wxGetApp().preset_bundle->printers.find_preset(preset_name);
|
||||
if (preset != nullptr) {
|
||||
preset_data.push_back({wxString::FromUTF8(it->get_full_name(preset_name)).Lower(), wxString::FromUTF8(preset_name),
|
||||
wxString::FromUTF8(it->get_full_name(preset_name)), ph_printers.is_selected(it, preset_name)});
|
||||
}
|
||||
}
|
||||
}
|
||||
m_presetData = preset_data;
|
||||
for (const PhysicalPrinterPresetData &data : preset_data) {
|
||||
wxCheckBox *checkbox = new wxCheckBox(this, wxID_ANY, _L(data.fullname));
|
||||
checkbox->SetValue(data.selected);
|
||||
checkbox_sizer->Add(checkbox, 0, wxEXPAND | wxALL, 5);
|
||||
}
|
||||
|
||||
content_sizer->Add(checkbox_sizer);
|
||||
|
||||
if (combo_groups != nullptr) {
|
||||
// Repetier specific: Show a selection of file groups.
|
||||
@@ -109,9 +144,19 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo
|
||||
return true;
|
||||
};
|
||||
|
||||
//B53
|
||||
auto* btn_ok = add_button(wxID_OK, true, _L("Upload"));
|
||||
btn_ok->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
|
||||
btn_ok->Bind(wxEVT_BUTTON, [this, validate_path, checkbox_sizer](wxCommandEvent &) {
|
||||
if (validate_path(txt_filename->GetValue())) {
|
||||
std::vector<bool> checkbox_states;
|
||||
|
||||
for (int i = 0; i < checkbox_sizer->GetItemCount(); i++) {
|
||||
wxCheckBox *checkbox = dynamic_cast<wxCheckBox *>(checkbox_sizer->GetItem(i)->GetWindow());
|
||||
if (checkbox) {
|
||||
checkbox_states.push_back(checkbox->GetValue());
|
||||
}
|
||||
}
|
||||
m_checkbox_states = checkbox_states;
|
||||
post_upload_action = PrintHostPostUploadAction::None;
|
||||
EndDialog(wxID_OK);
|
||||
}
|
||||
@@ -128,10 +173,20 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo
|
||||
});
|
||||
}
|
||||
|
||||
//B53
|
||||
if (post_actions.has(PrintHostPostUploadAction::StartPrint)) {
|
||||
auto* btn_print = add_button(wxID_YES, false, _L("Upload and Print"));
|
||||
btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
|
||||
btn_print->Bind(wxEVT_BUTTON, [this, validate_path, checkbox_sizer](wxCommandEvent &) {
|
||||
if (validate_path(txt_filename->GetValue())) {
|
||||
std::vector<bool> checkbox_states;
|
||||
|
||||
for (int i = 0; i < checkbox_sizer->GetItemCount(); i++) {
|
||||
wxCheckBox *checkbox = dynamic_cast<wxCheckBox *>(checkbox_sizer->GetItem(i)->GetWindow());
|
||||
if (checkbox) {
|
||||
checkbox_states.push_back(checkbox->GetValue());
|
||||
}
|
||||
}
|
||||
m_checkbox_states = checkbox_states;
|
||||
post_upload_action = PrintHostPostUploadAction::StartPrint;
|
||||
EndDialog(wxID_OK);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,15 @@ namespace Slic3r {
|
||||
|
||||
namespace GUI {
|
||||
|
||||
//B53
|
||||
struct PhysicalPrinterPresetData
|
||||
{
|
||||
wxString lower_name; // just for sorting
|
||||
wxString name; // preset_name
|
||||
wxString fullname; // full name
|
||||
bool selected; // is selected
|
||||
int checkboxId;
|
||||
};
|
||||
class PrintHostSendDialog : public GUI::MsgDialog
|
||||
{
|
||||
public:
|
||||
@@ -31,6 +40,9 @@ public:
|
||||
PrintHostPostUploadAction post_action() const;
|
||||
std::string group() const;
|
||||
std::string storage() const;
|
||||
//B53
|
||||
std::vector<PhysicalPrinterPresetData> pppd() { return m_presetData; }
|
||||
std::vector<bool> checkbox_states() { return m_checkbox_states; }
|
||||
|
||||
virtual void EndModal(int ret) override;
|
||||
private:
|
||||
@@ -41,6 +53,9 @@ private:
|
||||
wxString m_valid_suffix;
|
||||
wxString m_preselected_storage;
|
||||
wxArrayString m_paths;
|
||||
//B53
|
||||
std::vector<PhysicalPrinterPresetData> m_presetData;
|
||||
std::vector<bool> m_checkbox_states;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1461,10 +1461,16 @@ void TabPrint::build()
|
||||
|
||||
optgroup = page->new_optgroup(L("Advanced"));
|
||||
optgroup->append_single_option_line("seam_position", category_path + "seam-position");
|
||||
//Y21
|
||||
optgroup->append_single_option_line("seam_gap", category_path + "seam-gap");
|
||||
optgroup->append_single_option_line("staggered_inner_seams", category_path + "staggered-inner-seams");
|
||||
optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first");
|
||||
optgroup->append_single_option_line("gap_fill_enabled", category_path + "fill-gaps");
|
||||
optgroup->append_single_option_line("perimeter_generator");
|
||||
//w16
|
||||
optgroup->append_single_option_line("top_one_wall_type");
|
||||
//w17
|
||||
optgroup->append_single_option_line("top_area_threshold");
|
||||
|
||||
optgroup = page->new_optgroup(L("Fuzzy skin (experimental)"));
|
||||
category_path = "fuzzy-skin_246186/#";
|
||||
|
||||
@@ -328,8 +328,8 @@ MsgUpdateConfig::MsgUpdateConfig(const std::vector<Update> &updates, bool force_
|
||||
// auto changelog_url = (boost::format(update.changelog_url) % lang_code).str();
|
||||
//B51
|
||||
auto changelog_url = "";
|
||||
line->AddSpacer(3*VERT_SPACING);
|
||||
line->Add(new wxHyperlinkCtrl(this, wxID_ANY, _(L("Open changelog page")), changelog_url));
|
||||
//line->AddSpacer(3*VERT_SPACING);
|
||||
//line->Add(new wxHyperlinkCtrl(this, wxID_ANY, _(L("Open changelog page")), changelog_url));
|
||||
versions->Add(line);
|
||||
versions->AddSpacer(1); // empty value for the correct alignment inside a GridSizer
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ static const int clr_border_disabled = 0x646464;//0xDBDBDB;
|
||||
|
||||
static const int clr_background_normal_light = 0xFFFFFF;
|
||||
static const int clr_background_normal_dark = 0x2B2B2B;//0x434343;
|
||||
static const int clr_background_focused = 0xED6B21;//0xEDFAF2;
|
||||
//B48
|
||||
static const int clr_background_focused = 0x4479FB;//0xEDFAF2;
|
||||
static const int clr_background_disabled_dark = 0x404040;//0xF0F0F0;
|
||||
static const int clr_background_disabled_light = 0xD9D9D9;//0xF0F0F0;
|
||||
|
||||
|
||||
@@ -98,32 +98,47 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater*
|
||||
|
||||
// start PA
|
||||
auto start_PA_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto start_pa_text = new wxStaticText(this, wxID_ANY, _L("Start PA: "), wxDefaultPosition, wxSize(80, -1), wxALIGN_LEFT);
|
||||
start_PA_sizer->Add(start_pa_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_tcStartPA = new wxTextCtrl(this, wxID_ANY, wxString::FromDouble(0.0), wxDefaultPosition, wxSize(100, -1), wxBORDER_SIMPLE);
|
||||
m_tcStartPA->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
start_PA_sizer->Add(m_tcStartPA, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
auto start_PA_unit = new wxStaticText(this, wxID_ANY, _L("mm/s"), wxDefaultPosition, wxSize(40, -1), wxALIGN_LEFT);
|
||||
start_PA_sizer->Add(start_PA_unit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
settings_sizer->Add(start_PA_sizer);
|
||||
|
||||
// end PA
|
||||
auto end_PA_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto end_pa_text = new wxStaticText(this, wxID_ANY, _L("End PA: "), wxDefaultPosition, wxSize(80, -1), wxALIGN_LEFT);
|
||||
end_PA_sizer->Add(end_pa_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_tcEndPA = new wxTextCtrl(this, wxID_ANY, wxString::FromDouble(0.04), wxDefaultPosition, wxSize(100, -1), wxBORDER_SIMPLE);
|
||||
m_tcStartPA->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
end_PA_sizer->Add(m_tcEndPA, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
auto end_PA_unit = new wxStaticText(this, wxID_ANY, _L("mm/s"), wxDefaultPosition, wxSize(40, -1), wxALIGN_LEFT);
|
||||
end_PA_sizer->Add(end_PA_unit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
settings_sizer->Add(end_PA_sizer);
|
||||
|
||||
// PA step
|
||||
auto PA_step_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto PA_step_text = new wxStaticText(this, wxID_ANY, _L("PA step: "), wxDefaultPosition, wxSize(80, -1), wxALIGN_LEFT);
|
||||
PA_step_sizer->Add(PA_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_tcPAStep = new wxTextCtrl(this, wxID_ANY, wxString::FromDouble(0.002), wxDefaultPosition, wxSize(100, -1), wxBORDER_SIMPLE);
|
||||
m_tcStartPA->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
PA_step_sizer->Add(m_tcPAStep, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
auto PA_step_unit = new wxStaticText(this, wxID_ANY, _L("mm/s"), wxDefaultPosition, wxSize(40, -1), wxALIGN_LEFT);
|
||||
PA_step_sizer->Add(PA_step_unit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
settings_sizer->Add(PA_step_sizer);
|
||||
|
||||
v_sizer->Add(0, 5, 0, wxEXPAND, 5);
|
||||
@@ -191,4 +206,103 @@ void PA_Calibration_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
|
||||
Fit();
|
||||
}
|
||||
|
||||
MVS_Calibration_Dlg::MVS_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
|
||||
: DPIDialog(parent, id, _L("Max Volumetric Speed"), wxDefaultPosition, wxSize(-1, 280), wxDEFAULT_DIALOG_STYLE | wxNO_BORDER), m_plater(plater)
|
||||
{
|
||||
wxBoxSizer* v_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(v_sizer);
|
||||
|
||||
// Settings
|
||||
wxStaticBoxSizer* settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _L("Settings"));
|
||||
|
||||
// start VS
|
||||
auto start_VS_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto start_VS_text = new wxStaticText(this, wxID_ANY, _L("Start Volumetric Speed: "), wxDefaultPosition, wxSize(160, -1), wxALIGN_LEFT);
|
||||
start_VS_sizer->Add(start_VS_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_tcStartVS = new wxTextCtrl(this, wxID_ANY, wxString::FromDouble(5), wxDefaultPosition, wxSize(100, -1), wxBORDER_SIMPLE);
|
||||
m_tcStartVS->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
start_VS_sizer->Add(m_tcStartVS, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
auto start_VS_unit = new wxStaticText(this, wxID_ANY, _L("mm³/s"), wxDefaultPosition, wxSize(40, -1), wxALIGN_LEFT);
|
||||
start_VS_sizer->Add(start_VS_unit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
settings_sizer->Add(start_VS_sizer);
|
||||
|
||||
// end VS
|
||||
auto end_VS_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto end_VS_text = new wxStaticText(this, wxID_ANY, _L("End Volumetric Speed: "), wxDefaultPosition, wxSize(160, -1), wxALIGN_LEFT);
|
||||
end_VS_sizer->Add(end_VS_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_tcEndVS = new wxTextCtrl(this, wxID_ANY, wxString::FromDouble(15), wxDefaultPosition, wxSize(100, -1), wxBORDER_SIMPLE);
|
||||
m_tcStartVS->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
end_VS_sizer->Add(m_tcEndVS, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
auto end_VS_unit = new wxStaticText(this, wxID_ANY, _L("mm³/s"), wxDefaultPosition, wxSize(40, -1), wxALIGN_LEFT);
|
||||
end_VS_sizer->Add(end_VS_unit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
settings_sizer->Add(end_VS_sizer);
|
||||
|
||||
// VS step
|
||||
auto VS_step_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto VS_step_text = new wxStaticText(this, wxID_ANY, _L("Volumetric Speed step: "), wxDefaultPosition, wxSize(160, -1), wxALIGN_LEFT);
|
||||
VS_step_sizer->Add(VS_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_tcVSStep = new wxTextCtrl(this, wxID_ANY, wxString::FromDouble(0.1), wxDefaultPosition, wxSize(100, -1), wxBORDER_SIMPLE);
|
||||
m_tcStartVS->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
VS_step_sizer->Add(m_tcVSStep, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
auto VS_step_unit = new wxStaticText(this, wxID_ANY, _L("mm³/s"), wxDefaultPosition, wxSize(40, -1), wxALIGN_LEFT);
|
||||
VS_step_sizer->Add(VS_step_unit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
settings_sizer->Add(VS_step_sizer);
|
||||
|
||||
v_sizer->Add(0, 5, 0, wxEXPAND, 5);
|
||||
v_sizer->Add(settings_sizer, 0, wxRIGHT | wxLEFT | wxALIGN_CENTER_VERTICAL, 15);
|
||||
v_sizer->Add(0, 5, 0, wxEXPAND, 5);
|
||||
|
||||
m_btnStart = new wxButton(this, wxID_ANY, _L("OK"));
|
||||
m_btnStart->Bind(wxEVT_BUTTON, &MVS_Calibration_Dlg::on_start, this);
|
||||
v_sizer->Add(m_btnStart, 0, wxRIGHT | wxALIGN_RIGHT, 15);
|
||||
v_sizer->Add(0, 8, 0, wxEXPAND, 5);
|
||||
|
||||
m_btnStart->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MVS_Calibration_Dlg::on_start), NULL, this);
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
MVS_Calibration_Dlg::~MVS_Calibration_Dlg() {
|
||||
// Disconnect Events
|
||||
m_btnStart->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MVS_Calibration_Dlg::on_start), NULL, this);
|
||||
}
|
||||
|
||||
void MVS_Calibration_Dlg::on_start(wxCommandEvent& event) {
|
||||
bool read_double = false;
|
||||
double start_vs;
|
||||
double end_vs;
|
||||
double vs_step;
|
||||
read_double = m_tcStartVS->GetValue().ToDouble(&start_vs);
|
||||
read_double = read_double && m_tcEndVS->GetValue().ToDouble(&end_vs);
|
||||
read_double = read_double && m_tcVSStep->GetValue().ToDouble(&vs_step);
|
||||
if (!read_double || start_vs < 0 || vs_step < 0.01 || end_vs < start_vs + vs_step) {
|
||||
MessageDialog msg_dlg(nullptr, _L("Please input valid values:\nStart Volumetric Speed: >= 0.0\nEnd Volumetric Speed: > Start Volumetric Speed + Volumetric Speed step\nVolumetric Speed step: >= 0.01)"), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
m_plater->calib_max_volumetric_speed( start_vs, end_vs, vs_step);
|
||||
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void MVS_Calibration_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
|
||||
this->Refresh();
|
||||
Fit();
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
@@ -51,6 +51,23 @@ protected:
|
||||
Plater* m_plater;
|
||||
};
|
||||
|
||||
class MVS_Calibration_Dlg : public DPIDialog
|
||||
{
|
||||
public:
|
||||
MVS_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* plater);
|
||||
~MVS_Calibration_Dlg();
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|
||||
protected:
|
||||
virtual void on_start(wxCommandEvent& event);
|
||||
|
||||
wxTextCtrl* m_tcStartVS;
|
||||
wxTextCtrl* m_tcEndVS;
|
||||
wxTextCtrl* m_tcVSStep;
|
||||
wxButton* m_btnStart;
|
||||
Plater* m_plater;
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
#endif
|
||||
|
||||
@@ -55,6 +55,7 @@ SCENARIO("Perimeter nesting", "[Perimeters]")
|
||||
static_cast<const PrintConfig&>(config),
|
||||
false); // spiral_vase
|
||||
Polygons lower_layer_polygons_cache;
|
||||
Polygons upper_layer_polygons_cache;
|
||||
for (const Surface &surface : slices)
|
||||
// FIXME Lukas H.: Disable this test for Arachne because it is failing and needs more investigation.
|
||||
// if (config.perimeter_generator == PerimeterGeneratorType::Arachne)
|
||||
@@ -65,7 +66,9 @@ SCENARIO("Perimeter nesting", "[Perimeters]")
|
||||
perimeter_generator_params,
|
||||
surface,
|
||||
nullptr,
|
||||
nullptr,
|
||||
// cache:
|
||||
upper_layer_polygons_cache,
|
||||
lower_layer_polygons_cache,
|
||||
// output:
|
||||
loops, gap_fill, fill_expolygons);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
set(SLIC3R_APP_NAME "QIDISlicer")
|
||||
set(SLIC3R_APP_KEY "QIDISlicer")
|
||||
set(SLIC3R_VERSION "1.1.0")
|
||||
set(SLIC3R_VERSION "1.1.1")
|
||||
set(SLIC3R_BUILD_ID "QIDISlicer-${SLIC3R_VERSION}+Win64")
|
||||
set(SLIC3R_RC_VERSION "1,1,0,0")
|
||||
set(SLIC3R_RC_VERSION_DOTS "1.1.0.0")
|
||||
set(SLIC3R_RC_VERSION "1,1,1,0")
|
||||
set(SLIC3R_RC_VERSION_DOTS "1.1.1.0")
|
||||
|
||||
Reference in New Issue
Block a user