mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-23 19:56:05 +03:00
Compare commits
7 Commits
fix/api-er
...
fix/cli-se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a2118f696 | ||
|
|
899bbafc99 | ||
|
|
a8e5a6988e | ||
|
|
c5855db578 | ||
|
|
a2341920a1 | ||
|
|
1e4a5589b5 | ||
|
|
9598e1bb9a |
@@ -6,6 +6,7 @@
|
||||
* {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
@@ -16,19 +17,24 @@
|
||||
font-family: sans-serif;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
padding-bottom: 10px;
|
||||
border: 1px solid #ccc;
|
||||
max-width:fit-content(1000px);
|
||||
max-width: fit-content(1000px);
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tip-panel {
|
||||
@@ -36,9 +42,19 @@
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.scroll-wrapper {
|
||||
flex: 1 1 0%;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
flex: 1 1 0%;
|
||||
min-height: 80px;
|
||||
max-width: 100%;
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
@@ -47,6 +63,10 @@
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.description-section {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
@@ -152,7 +172,8 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0px;
|
||||
margin: 10px;
|
||||
margin-top: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 暗色模式样式 */
|
||||
@@ -245,7 +266,7 @@
|
||||
in Orca Slicer > Preferences.
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 10px; display: flex; align-items: center;">
|
||||
<div style="margin-bottom: 10px; display: flex; align-items: center; flex-shrink: 0;">
|
||||
<div
|
||||
class="ButtonStyleConfirm ButtonTypeWindow"
|
||||
onclick="calcFlushingVolumes()"
|
||||
@@ -265,51 +286,54 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-container">
|
||||
<table id="flushTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
<div class="scroll-wrapper">
|
||||
<div class="scroll-container">
|
||||
<table id="flushTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="description-section" style="margin-top: 10px;">
|
||||
<div id="volume_desp_panel" class="normal-text">
|
||||
Flushing volume (mm³) for each filament pair.
|
||||
</div>
|
||||
<div
|
||||
id="volume_range_panel"
|
||||
class="normal-text"
|
||||
style="margin-top: 5px;"
|
||||
>
|
||||
Suggestion: Flushing Volume in range [50, 999]
|
||||
</div>
|
||||
<div style="margin-top: 8px;">
|
||||
<label
|
||||
for="multiplierInput"
|
||||
id="multiplier_label"
|
||||
style="font-size: 12px;"
|
||||
>Multiplier</label
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
id="multiplierInput"
|
||||
class="multiplier-input"
|
||||
value="1.00"
|
||||
oninput="onMultiplierChange()"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="margin-top: 5px; margin-bottom: 5px; color: #666; font-size: 12px;"
|
||||
id="multiplier_range_panel"
|
||||
>
|
||||
The multiplier should be in range [0.50, 3.00].
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px;">
|
||||
<div id="volume_desp_panel" class="normal-text">
|
||||
Flushing volume (mm³) for each filament pair.
|
||||
</div>
|
||||
<div
|
||||
id="volume_range_panel"
|
||||
class="normal-text"
|
||||
style="margin-top: 5px;"
|
||||
>
|
||||
Suggestion: Flushing Volume in range [50, 999]
|
||||
</div>
|
||||
<div style="margin-top: 8px;">
|
||||
<label
|
||||
for="multiplierInput"
|
||||
id="multiplier_label"
|
||||
style="font-size: 12px;"
|
||||
>Multiplier</label
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
id="multiplierInput"
|
||||
class="multiplier-input"
|
||||
value="1.00"
|
||||
oninput="onMultiplierChange()"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="margin-top: 5px; margin-bottom: 5px; color: #666; font-size: 12px;"
|
||||
id="multiplier_range_panel"
|
||||
>
|
||||
The multiplier should be in range [0.50, 3.00].
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-container" style="padding: 0px; margin: 0px;">
|
||||
<div class="ButtonStyleConfirm ButtonTypeChoice" id="ok_btn" onclick="storeData()">
|
||||
Save
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "SVG.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
|
||||
@@ -407,11 +408,31 @@ BoundingBox get_extents(const ExPolygon &expolygon)
|
||||
BoundingBox get_extents(const ExPolygons &expolygons)
|
||||
{
|
||||
BoundingBox bbox;
|
||||
if (! expolygons.empty()) {
|
||||
for (size_t i = 0; i < expolygons.size(); ++ i)
|
||||
if (! expolygons[i].contour.points.empty())
|
||||
bbox.merge(get_extents(expolygons[i]));
|
||||
|
||||
const size_t n = expolygons.size();
|
||||
|
||||
BOOST_LOG_TRIVIAL(info)
|
||||
<< "get_extents ExPolygons addr=" << &expolygons
|
||||
<< " data=" << expolygons.data()
|
||||
<< " size=" << n
|
||||
<< " capacity=" << expolygons.capacity();
|
||||
|
||||
if (n > 1000000) {
|
||||
BOOST_LOG_TRIVIAL(error)
|
||||
<< "Suspicious ExPolygons size=" << n
|
||||
<< " addr=" << &expolygons
|
||||
<< " data=" << expolygons.data()
|
||||
<< " capacity=" << expolygons.capacity();
|
||||
|
||||
assert(false);
|
||||
return bbox;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (!expolygons[i].contour.points.empty())
|
||||
bbox.merge(get_extents(expolygons[i]));
|
||||
}
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
||||
|
||||
@@ -5726,6 +5726,9 @@ std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
|
||||
// if polyline was shorter than the clipping distance we'd get a null polyline, so
|
||||
// we discard it in that case
|
||||
const double seam_gap = scale_(m_config.seam_gap.get_abs_value(nozzle_diameter));
|
||||
const bool seam_gap_applied = enable_seam_slope || m_enable_loop_clipping;
|
||||
const double seam_gap_distance_mm = seam_gap_applied ? unscale_(seam_gap) : 0.0;
|
||||
double seam_scarf_distance_mm = 0.0;
|
||||
const double clip_length = m_enable_loop_clipping && !enable_seam_slope ? seam_gap : 0;
|
||||
|
||||
// get paths
|
||||
@@ -5874,6 +5877,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
|
||||
const double slope_min_length = slope_entire_loop ? loop_length : std::min(m_config.seam_slope_min_length.value, loop_length);
|
||||
const int slope_steps = m_config.seam_slope_steps;
|
||||
const double slope_max_segment_length = scale_(slope_min_length / slope_steps);
|
||||
seam_scarf_distance_mm = slope_min_length;
|
||||
|
||||
// Calculate the sloped loop
|
||||
ExtrusionLoopSloped new_loop(paths, seam_gap, slope_min_length, slope_max_segment_length, start_slope_ratio, loop.loop_role());
|
||||
@@ -5898,6 +5902,11 @@ std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
|
||||
}
|
||||
}
|
||||
|
||||
if (description == "perimeter") {
|
||||
m_processor.result().print_statistics.total_seam_gap_distance += static_cast<float>(seam_gap_distance_mm);
|
||||
m_processor.result().print_statistics.total_seam_scarf_distance += static_cast<float>(seam_scarf_distance_mm);
|
||||
}
|
||||
|
||||
// BBS
|
||||
if (m_wipe.enable && FILAMENT_CONFIG(wipe)) {
|
||||
m_wipe.path = Polyline();
|
||||
|
||||
@@ -3821,9 +3821,10 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
return;
|
||||
|
||||
EMoveType type = move_type(delta_pos);
|
||||
const float delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
|
||||
m_travel_dist = delta_xyz;
|
||||
|
||||
if (type == EMoveType::Extrude) {
|
||||
const float delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
|
||||
m_travel_dist = delta_xyz;
|
||||
float volume_extruded_filament = area_filament_cross_section * delta_pos[E];
|
||||
float area_toolpath_cross_section = volume_extruded_filament / delta_xyz;
|
||||
|
||||
@@ -5445,6 +5446,11 @@ void GCodeProcessor::process_filament_change(int id)
|
||||
int next_extruder_id = m_filament_maps[id];
|
||||
int next_filament_id = id;
|
||||
float extra_time = 0;
|
||||
unsigned int filament_changes_delta = 0;
|
||||
unsigned int extruder_changes_delta = 0;
|
||||
float filament_load_time_delta = 0.0f;
|
||||
float filament_unload_time_delta = 0.0f;
|
||||
float tool_change_time_delta = 0.0f;
|
||||
|
||||
if (prev_filament_id == next_filament_id)
|
||||
return;
|
||||
@@ -5457,12 +5463,14 @@ void GCodeProcessor::process_filament_change(int id)
|
||||
assert(prev_extruder_id != -1);
|
||||
process_filaments(CustomGCode::ToolChange);
|
||||
m_filament_id[next_extruder_id] = next_filament_id;
|
||||
m_result.lock();
|
||||
m_result.print_statistics.total_filament_changes += 1;
|
||||
m_result.unlock();
|
||||
extra_time += get_filament_unload_time(static_cast<size_t>(prev_filament_id));
|
||||
filament_changes_delta += 1;
|
||||
const float filament_unload_time = get_filament_unload_time(static_cast<size_t>(prev_filament_id));
|
||||
extra_time += filament_unload_time;
|
||||
filament_unload_time_delta += filament_unload_time;
|
||||
m_time_processor.extruder_unloaded = false;
|
||||
extra_time += get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
extra_time += filament_load_time;
|
||||
filament_load_time_delta += filament_load_time;
|
||||
}
|
||||
else {
|
||||
if (prev_extruder_id == -1) {
|
||||
@@ -5470,7 +5478,9 @@ void GCodeProcessor::process_filament_change(int id)
|
||||
m_extruder_id = next_extruder_id;
|
||||
m_filament_id[next_extruder_id] = next_filament_id;
|
||||
m_time_processor.extruder_unloaded = false;
|
||||
extra_time += get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
extra_time += filament_load_time;
|
||||
filament_load_time_delta += filament_load_time;
|
||||
}
|
||||
else {
|
||||
//first process cache generated by last extruder
|
||||
@@ -5481,24 +5491,39 @@ void GCodeProcessor::process_filament_change(int id)
|
||||
//no filament in current extruder
|
||||
m_filament_id[next_extruder_id] = next_filament_id;
|
||||
m_time_processor.extruder_unloaded = false;
|
||||
extra_time += get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
extra_time += filament_load_time;
|
||||
filament_load_time_delta += filament_load_time;
|
||||
}
|
||||
else if (m_last_filament_id[next_extruder_id] != next_filament_id) {
|
||||
//need to change filament
|
||||
m_filament_id[next_extruder_id] = next_filament_id;
|
||||
m_result.lock();
|
||||
m_result.print_statistics.total_filament_changes += 1;
|
||||
m_result.unlock();
|
||||
extra_time += get_filament_unload_time(static_cast<size_t>(prev_filament_id));
|
||||
filament_changes_delta += 1;
|
||||
const float filament_unload_time = get_filament_unload_time(static_cast<size_t>(prev_filament_id));
|
||||
extra_time += filament_unload_time;
|
||||
filament_unload_time_delta += filament_unload_time;
|
||||
m_time_processor.extruder_unloaded = false;
|
||||
extra_time += get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
|
||||
extra_time += filament_load_time;
|
||||
filament_load_time_delta += filament_load_time;
|
||||
}
|
||||
m_result.lock();
|
||||
m_result.print_statistics.total_extruder_changes++;
|
||||
m_result.unlock();
|
||||
extra_time += get_extruder_change_time(next_extruder_id);
|
||||
extruder_changes_delta += 1;
|
||||
const float tool_change_time = get_extruder_change_time(next_extruder_id);
|
||||
extra_time += tool_change_time;
|
||||
tool_change_time_delta += tool_change_time;
|
||||
}
|
||||
}
|
||||
|
||||
if (filament_changes_delta > 0 || extruder_changes_delta > 0 || filament_load_time_delta > 0.0f || filament_unload_time_delta > 0.0f || tool_change_time_delta > 0.0f) {
|
||||
m_result.lock();
|
||||
m_result.print_statistics.total_filament_changes += filament_changes_delta;
|
||||
m_result.print_statistics.total_extruder_changes += extruder_changes_delta;
|
||||
m_result.print_statistics.total_filament_load_time += filament_load_time_delta;
|
||||
m_result.print_statistics.total_filament_unload_time += filament_unload_time_delta;
|
||||
m_result.print_statistics.total_tool_change_time += tool_change_time_delta;
|
||||
m_result.unlock();
|
||||
}
|
||||
|
||||
m_cp_color.current = m_extruder_colors[next_filament_id];
|
||||
simulate_st_synchronize(extra_time);
|
||||
// store tool change move
|
||||
@@ -5543,6 +5568,11 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type,
|
||||
m_line_id + 1 :
|
||||
((type == EMoveType::Seam) ? m_last_line_id : m_line_id);
|
||||
|
||||
if (type == EMoveType::Travel) {
|
||||
m_result.print_statistics.total_travel_moves++;
|
||||
m_result.print_statistics.total_travel_distance += m_travel_dist;
|
||||
}
|
||||
|
||||
m_result.moves.push_back({
|
||||
m_last_line_id,
|
||||
type,
|
||||
|
||||
@@ -78,6 +78,13 @@ class Print;
|
||||
std::array<Mode, static_cast<size_t>(ETimeMode::Count)> modes;
|
||||
unsigned int total_filament_changes;
|
||||
unsigned int total_extruder_changes;
|
||||
float total_filament_load_time;
|
||||
float total_filament_unload_time;
|
||||
float total_tool_change_time;
|
||||
float total_travel_distance;
|
||||
unsigned int total_travel_moves;
|
||||
float total_seam_gap_distance;
|
||||
float total_seam_scarf_distance;
|
||||
|
||||
PrintEstimatedStatistics() { reset(); }
|
||||
|
||||
@@ -95,6 +102,13 @@ class Print;
|
||||
used_filaments_per_role.clear();
|
||||
total_filament_changes = 0;
|
||||
total_extruder_changes = 0;
|
||||
total_filament_load_time = 0.0f;
|
||||
total_filament_unload_time = 0.0f;
|
||||
total_tool_change_time = 0.0f;
|
||||
total_travel_distance = 0.0f;
|
||||
total_travel_moves = 0;
|
||||
total_seam_gap_distance = 0.0f;
|
||||
total_seam_scarf_distance = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1832,10 +1832,26 @@ static std::vector<std::vector<ExPolygons>> merge_segmented_layers(const std::ve
|
||||
segmented_regions_merged.assign(num_layers, std::vector<ExPolygons>(num_facets_states - 1));
|
||||
assert(!top_and_bottom_layers.size() || num_facets_states == top_and_bottom_layers.size());
|
||||
|
||||
// Diagnostic: check initial state of second element (index 1) after assign
|
||||
{
|
||||
const size_t check_idx = num_facets_states - 2; // index of last element in inner vector
|
||||
const auto &inner = segmented_regions_merged[0];
|
||||
BOOST_LOG_TRIVIAL(info)
|
||||
<< "merge_segmented_layers after assign"
|
||||
<< " inner_size=" << inner.size()
|
||||
<< " elem[" << check_idx << "].addr=" << &inner[check_idx]
|
||||
<< " data=" << inner[check_idx].data()
|
||||
<< " size=" << inner[check_idx].size()
|
||||
<< " capacity=" << inner[check_idx].capacity()
|
||||
<< " top_and_bottom_size=" << top_and_bottom_layers.size()
|
||||
<< " num_facets_states=" << num_facets_states;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Print object segmentation - Merging segmented layers in parallel - Begin";
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&segmented_regions, &top_and_bottom_layers, &segmented_regions_merged, &num_facets_states, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
|
||||
assert(segmented_regions[layer_idx].size() == num_facets_states);
|
||||
const size_t last_elem_idx = num_facets_states - 2; // index = num_facets_states - 1 - 1
|
||||
// Zero is skipped because it is the default color of the volume
|
||||
for (size_t extruder_id = 1; extruder_id < num_facets_states; ++extruder_id) {
|
||||
throw_on_cancel_callback();
|
||||
@@ -1860,6 +1876,39 @@ static std::vector<std::vector<ExPolygons>> merge_segmented_layers(const std::ve
|
||||
if (!was_top_and_bottom_empty)
|
||||
segmented_regions_merged[layer_idx][extruder_id - 1] = offset2_ex(union_ex(segmented_regions_merged[layer_idx][extruder_id - 1]), float(SCALED_EPSILON), -float(SCALED_EPSILON));
|
||||
}
|
||||
|
||||
// Diagnostic: after processing this extruder_id, check the corresponding merged element
|
||||
const size_t merged_idx = extruder_id - 1;
|
||||
const auto &elem = segmented_regions_merged[layer_idx][merged_idx];
|
||||
if (elem.size() > 1000000) {
|
||||
BOOST_LOG_TRIVIAL(error)
|
||||
<< "merge_segmented_layers CORRUPTION after extruder_id=" << extruder_id
|
||||
<< " layer_idx=" << layer_idx
|
||||
<< " merged_idx=" << merged_idx
|
||||
<< " elem_addr=" << &elem
|
||||
<< " data=" << elem.data()
|
||||
<< " size=" << elem.size()
|
||||
<< " capacity=" << elem.capacity()
|
||||
<< " top_and_bottom_empty=" << top_and_bottom_layers.empty()
|
||||
<< " tb_extruder_exists=" << (extruder_id < top_and_bottom_layers.size())
|
||||
<< " segmented_src_data=" << segmented_regions[layer_idx][extruder_id].data()
|
||||
<< " segmented_src_size=" << segmented_regions[layer_idx][extruder_id].size();
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnostic: final state of the last element after all extruders processed
|
||||
const auto &last_elem = segmented_regions_merged[layer_idx][last_elem_idx];
|
||||
if (last_elem.size() > 1000000 || (last_elem.size() == 0 && last_elem.data() != nullptr && reinterpret_cast<uintptr_t>(last_elem.data()) < 0x1000)) {
|
||||
BOOST_LOG_TRIVIAL(error)
|
||||
<< "merge_segmented_layers BAD FINAL STATE"
|
||||
<< " layer_idx=" << layer_idx
|
||||
<< " last_elem_idx=" << last_elem_idx
|
||||
<< " addr=" << &last_elem
|
||||
<< " data=" << last_elem.data()
|
||||
<< " size=" << last_elem.size()
|
||||
<< " capacity=" << last_elem.capacity()
|
||||
<< " inner_vec_addr=" << &segmented_regions_merged[layer_idx]
|
||||
<< " inner_vec_size=" << segmented_regions_merged[layer_idx].size();
|
||||
}
|
||||
}
|
||||
}); // end of parallel_for
|
||||
@@ -2195,7 +2244,7 @@ std::vector<std::vector<ExPolygons>> segmentation_by_painting(const PrintObject
|
||||
|
||||
// Returns multi-material segmentation based on painting in multi-material segmentation gizmo
|
||||
std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback) {
|
||||
const size_t num_facets_states = print_object.print()->config().filament_colour.size() + 1;
|
||||
const size_t num_facets_states = print_object.print()->config().filament_diameter.size() + 1;
|
||||
const float max_width = float(print_object.config().mmu_segmented_region_max_width.value);
|
||||
const float interlocking_depth = float(print_object.config().mmu_segmented_region_interlocking_depth.value);
|
||||
const bool interlocking_beam = print_object.config().interlocking_beam.value;
|
||||
|
||||
@@ -4272,7 +4272,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->min = 0;
|
||||
def->max = 90;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
def->set_default_value(new ConfigOptionFloat(35));
|
||||
|
||||
def = this->add("zaa_dont_alternate_fill_direction", coBool);
|
||||
def->label = L("Don't alternate fill direction");
|
||||
@@ -6770,7 +6770,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.emplace_back(L("Cone"));
|
||||
def->enum_labels.emplace_back(L("Rib"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<WipeTowerWallType>(wtwRectangle));
|
||||
def->set_default_value(new ConfigOptionEnum<WipeTowerWallType>(wtwRib));
|
||||
|
||||
def = this->add("wipe_tower_extra_rib_length", coFloat);
|
||||
def->label = L("Extra rib length");
|
||||
|
||||
@@ -21,6 +21,32 @@ namespace Slic3r {
|
||||
bool PrintObject::clip_multipart_objects = true;
|
||||
bool PrintObject::infill_only_where_needed = false;
|
||||
|
||||
static coordf_t compute_slice_z(PrintObject* print_object, size_t i_layer, coordf_t lo, coordf_t hi)
|
||||
{
|
||||
bool zaa_active = false;
|
||||
coordf_t z_offset = 0.0;
|
||||
|
||||
size_t num_regions = print_object->num_printing_regions();
|
||||
for (size_t rid = 0; rid < num_regions; ++rid) {
|
||||
const auto& rcfg = print_object->printing_region(rid).config();
|
||||
if (rcfg.zaa_enabled) {
|
||||
if (!zaa_active || rcfg.zaa_min_z < z_offset)
|
||||
z_offset = rcfg.zaa_min_z;
|
||||
zaa_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zaa_active || i_layer == 0) {
|
||||
return 0.5 * (lo + hi);
|
||||
}
|
||||
|
||||
coordf_t slice_z = lo + z_offset;
|
||||
if ((slice_z < lo && !is_approx(slice_z, lo)) || (slice_z > hi && !is_approx(slice_z, hi))) {
|
||||
throw RuntimeError("Bad min Z value");
|
||||
}
|
||||
return slice_z;
|
||||
}
|
||||
|
||||
LayerPtrs new_layers(
|
||||
PrintObject *print_object,
|
||||
// Object layers (pairs of bottom/top Z coordinate), without the raft.
|
||||
@@ -34,24 +60,8 @@ LayerPtrs new_layers(
|
||||
for (size_t i_layer = 0; i_layer < object_layers.size(); i_layer += 2) {
|
||||
coordf_t lo = object_layers[i_layer];
|
||||
coordf_t hi = object_layers[i_layer + 1];
|
||||
coordf_t slice_z = 0.5 * (lo + hi);
|
||||
bool zaa_active = false;
|
||||
coordf_t z_offset = 0.0;
|
||||
size_t num_regions = print_object->num_printing_regions();
|
||||
for (size_t rid = 0; rid < num_regions; ++rid) {
|
||||
const auto &rcfg = print_object->printing_region(rid).config();
|
||||
if (rcfg.zaa_enabled) {
|
||||
if (!zaa_active || rcfg.zaa_min_z < z_offset)
|
||||
z_offset = rcfg.zaa_min_z;
|
||||
zaa_active = true;
|
||||
}
|
||||
}
|
||||
if (zaa_active) {
|
||||
slice_z = lo + z_offset;
|
||||
if ((slice_z < lo && !is_approx(slice_z, lo)) || (slice_z > hi && !is_approx(slice_z, hi))) {
|
||||
throw RuntimeError("Bad min Z value");
|
||||
}
|
||||
}
|
||||
coordf_t slice_z = compute_slice_z(print_object, i_layer, lo, hi);
|
||||
|
||||
Layer *layer = new Layer(id ++, print_object, hi - lo, hi + zmin, slice_z);
|
||||
out.emplace_back(layer);
|
||||
if (prev != nullptr) {
|
||||
@@ -873,7 +883,6 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
|
||||
double z = print_object.get_layer(int(range.begin()))->slice_z;
|
||||
auto it_layer_range = layer_range_first(layer_ranges, z);
|
||||
// BBS
|
||||
const size_t num_extruders = print_object.print()->config().filament_diameter.size();
|
||||
|
||||
struct ByExtruder {
|
||||
ExPolygons expolygons;
|
||||
@@ -893,12 +902,30 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
|
||||
it_layer_range = layer_range_next(layer_ranges, it_layer_range, layer.slice_z);
|
||||
const PrintObjectRegions::LayerRangeRegions &layer_range = *it_layer_range;
|
||||
// Gather per extruder expolygons.
|
||||
const size_t num_extruders = segmentation[layer_id].size();
|
||||
by_extruder.assign(num_extruders, ByExtruder());
|
||||
by_region.assign(layer.region_count(), ByRegion());
|
||||
bool layer_split = false;
|
||||
for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) {
|
||||
ByExtruder ®ion = by_extruder[extruder_id];
|
||||
const auto &src_expolys = segmentation[layer_id][extruder_id];
|
||||
BOOST_LOG_TRIVIAL(info)
|
||||
<< "apply_mm_segmentation before move"
|
||||
<< " layer_id=" << layer_id
|
||||
<< " extruder_id=" << extruder_id
|
||||
<< " src_addr=" << &src_expolys
|
||||
<< " src_data=" << src_expolys.data()
|
||||
<< " src_size=" << src_expolys.size()
|
||||
<< " src_capacity=" << src_expolys.capacity();
|
||||
append(region.expolygons, std::move(segmentation[layer_id][extruder_id]));
|
||||
BOOST_LOG_TRIVIAL(info)
|
||||
<< "apply_mm_segmentation after move"
|
||||
<< " layer_id=" << layer_id
|
||||
<< " extruder_id=" << extruder_id
|
||||
<< " dst_addr=" << ®ion.expolygons
|
||||
<< " dst_data=" << region.expolygons.data()
|
||||
<< " dst_size=" << region.expolygons.size()
|
||||
<< " dst_capacity=" << region.expolygons.capacity();
|
||||
if (! region.expolygons.empty()) {
|
||||
region.bbox = get_extents(region.expolygons);
|
||||
layer_split = true;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
@@ -94,7 +95,7 @@ static std::string get_view_type_string(libvgcode::EViewType view_type)
|
||||
return _u8L("Filament");
|
||||
else if (view_type == libvgcode::EViewType::LayerTimeLinear)
|
||||
return _u8L("Layer Time");
|
||||
else if (view_type == libvgcode::EViewType::LayerTimeLogarithmic)
|
||||
else if (view_type == libvgcode::EViewType::LayerTimeLogarithmic)
|
||||
return _u8L("Layer Time (log)");
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
else if (view_type == libvgcode::EViewType::PressureAdvance)
|
||||
@@ -124,6 +125,29 @@ static int find_close_layer_idx(const std::vector<double> &zs, double &z, double
|
||||
return -1;
|
||||
}
|
||||
|
||||
static std::string format_compact_weight(double value_in_grams, bool imperial_units)
|
||||
{
|
||||
char buffer[64];
|
||||
if (imperial_units) {
|
||||
::sprintf(buffer, "%.2f oz", value_in_grams / GizmoObjectManipulation::oz_to_g);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const double abs_value = value_in_grams < 0.0 ? -value_in_grams : value_in_grams;
|
||||
const char* unit = "g";
|
||||
double scaled_value = abs_value;
|
||||
if (scaled_value >= 1000000.0) {
|
||||
scaled_value /= 1000000.0;
|
||||
unit = "t";
|
||||
} else if (scaled_value >= 1000.0) {
|
||||
scaled_value /= 1000.0;
|
||||
unit = "kg";
|
||||
}
|
||||
|
||||
::sprintf(buffer, "%s%.2f%s", value_in_grams < 0.0 ? "-" : "", scaled_value, unit);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#if ENABLE_ACTUAL_SPEED_DEBUG
|
||||
int GCodeViewer::SequentialView::ActualSpeedImguiWidget::plot(const char* label, const std::array<float, 2>& frame_size)
|
||||
{
|
||||
@@ -1287,6 +1311,25 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
||||
//BBS: move the id to the end of reset
|
||||
m_last_result_id = gcode_result.id;
|
||||
m_gcode_result = &gcode_result;
|
||||
m_move_type_counts.fill(0);
|
||||
for (auto& move_type_times : m_move_type_times)
|
||||
move_type_times.fill(0.0f);
|
||||
m_move_type_distances.fill(0.0f);
|
||||
for (const GCodeProcessorResult::MoveVertex& move : gcode_result.moves) {
|
||||
if (move.internal_only)
|
||||
continue;
|
||||
|
||||
const size_t move_type = static_cast<size_t>(move.type);
|
||||
if (move_type < m_move_type_counts.size()) {
|
||||
++m_move_type_counts[move_type];
|
||||
for (size_t mode = 0; mode < move.time.size(); ++mode)
|
||||
m_move_type_times[move_type][mode] += move.time[mode];
|
||||
if (move.type == EMoveType::Retract || move.type == EMoveType::Unretract)
|
||||
m_move_type_distances[move_type] += std::fabs(move.delta_extruder);
|
||||
else
|
||||
m_move_type_distances[move_type] += move.travel_dist;
|
||||
}
|
||||
}
|
||||
m_only_gcode_in_preview = only_gcode;
|
||||
|
||||
m_sequential_view.gcode_window.load_gcode(gcode_result.filename, gcode_result.lines_ends);
|
||||
@@ -1449,6 +1492,29 @@ void GCodeViewer::load_as_preview(libvgcode::GCodeInputData&& data)
|
||||
{
|
||||
m_loaded_as_preview = true;
|
||||
|
||||
m_move_type_counts.fill(0);
|
||||
for (auto& move_type_times : m_move_type_times)
|
||||
move_type_times.fill(0.0f);
|
||||
m_move_type_distances.fill(0.0f);
|
||||
const size_t normal_time_mode_idx = static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal);
|
||||
for (size_t i = 0; i < data.vertices.size(); ++i) {
|
||||
const libvgcode::PathVertex& vertex = data.vertices[i];
|
||||
const size_t move_type = static_cast<size_t>(vertex.type);
|
||||
if (move_type < m_move_type_counts.size()) {
|
||||
++m_move_type_counts[move_type];
|
||||
for (size_t mode = 0; mode < vertex.times.size(); ++mode)
|
||||
m_move_type_times[move_type][mode] += vertex.times[mode];
|
||||
if (vertex.type == libvgcode::EMoveType::Retract || vertex.type == libvgcode::EMoveType::Unretract) {
|
||||
m_move_type_distances[move_type] += std::fabs(vertex.feedrate) * vertex.times[normal_time_mode_idx];
|
||||
} else if (i > 0) {
|
||||
const float dx = vertex.position[0] - data.vertices[i - 1].position[0];
|
||||
const float dy = vertex.position[1] - data.vertices[i - 1].position[1];
|
||||
const float dz = vertex.position[2] - data.vertices[i - 1].position[2];
|
||||
m_move_type_distances[move_type] += std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::Skirt, { 127, 255, 127 });
|
||||
m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::ExternalPerimeter, { 255, 255, 0 });
|
||||
m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::SupportMaterial, { 127, 255, 127 });
|
||||
@@ -1496,6 +1562,10 @@ void GCodeViewer::reset()
|
||||
m_extruders_count = 0;
|
||||
m_filament_diameters = std::vector<float>();
|
||||
m_filament_densities = std::vector<float>();
|
||||
m_move_type_counts.fill(0);
|
||||
for (auto& move_type_times : m_move_type_times)
|
||||
move_type_times.fill(0.0f);
|
||||
m_move_type_distances.fill(0.0f);
|
||||
m_print_statistics.reset();
|
||||
m_custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
|
||||
m_left_extruder_filament.clear();
|
||||
@@ -2676,39 +2746,42 @@ void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessor
|
||||
columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]});
|
||||
|
||||
char buf[64];
|
||||
double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0;
|
||||
|
||||
float column_sum_m = 0.0f;
|
||||
float column_sum_g = 0.0f;
|
||||
if (displayed_columns & ColumnData::Model) {
|
||||
const std::string weight_text = format_compact_weight(model_used_filaments_g_all_plates[i], imperial_units);
|
||||
if ((displayed_columns & ~ColumnData::Model) > 0)
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m_all_plates[i], model_used_filaments_g_all_plates[i] / unit_conver);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", model_used_filaments_m_all_plates[i], weight_text.c_str());
|
||||
else
|
||||
::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", model_used_filaments_m_all_plates[i], model_used_filaments_g_all_plates[i] / unit_conver);
|
||||
::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m_all_plates[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, offsets[_u8L("Model")] });
|
||||
column_sum_m += model_used_filaments_m_all_plates[i];
|
||||
column_sum_g += model_used_filaments_g_all_plates[i];
|
||||
}
|
||||
if (displayed_columns & ColumnData::Support) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", support_used_filaments_m_all_plates[i], support_used_filaments_g_all_plates[i] / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(support_used_filaments_g_all_plates[i], imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", support_used_filaments_m_all_plates[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, offsets[_u8L("Support")] });
|
||||
column_sum_m += support_used_filaments_m_all_plates[i];
|
||||
column_sum_g += support_used_filaments_g_all_plates[i];
|
||||
}
|
||||
if (displayed_columns & ColumnData::Flushed) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", flushed_filaments_m_all_plates[i], flushed_filaments_g_all_plates[i] / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(flushed_filaments_g_all_plates[i], imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", flushed_filaments_m_all_plates[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, offsets[_u8L("Flushed")] });
|
||||
column_sum_m += flushed_filaments_m_all_plates[i];
|
||||
column_sum_g += flushed_filaments_g_all_plates[i];
|
||||
}
|
||||
if (displayed_columns & ColumnData::WipeTower) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", wipe_tower_used_filaments_m_all_plates[i], wipe_tower_used_filaments_g_all_plates[i] / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(wipe_tower_used_filaments_g_all_plates[i], imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", wipe_tower_used_filaments_m_all_plates[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, offsets[_u8L("Tower")] });
|
||||
column_sum_m += wipe_tower_used_filaments_m_all_plates[i];
|
||||
column_sum_g += wipe_tower_used_filaments_g_all_plates[i];
|
||||
}
|
||||
if ((displayed_columns & ~ColumnData::Model) > 0) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", column_sum_m, column_sum_g / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(column_sum_g, imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", column_sum_m, weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, offsets[_u8L("Total")] });
|
||||
}
|
||||
|
||||
@@ -3072,7 +3145,9 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
const PrintEstimatedStatistics::Mode& time_mode = m_print_statistics.modes[static_cast<size_t>(m_viewer.get_time_mode())];
|
||||
const libvgcode::EViewType curr_view_type = m_viewer.get_view_type();
|
||||
const int curr_view_type_i = static_cast<int>(curr_view_type);
|
||||
bool show_estimated_time = time_mode.time > 0.0f && (curr_view_type == libvgcode::EViewType::FeatureType ||
|
||||
const size_t current_time_mode = static_cast<size_t>(m_viewer.get_time_mode());
|
||||
const float total_estimated_time = time_mode.time > 0.0f ? time_mode.time : m_viewer.get_estimated_time();
|
||||
bool show_estimated_time = total_estimated_time > 0.0f && (curr_view_type == libvgcode::EViewType::FeatureType ||
|
||||
curr_view_type == libvgcode::EViewType::LayerTimeLinear || curr_view_type == libvgcode::EViewType::LayerTimeLogarithmic ||
|
||||
(curr_view_type == libvgcode::EViewType::ColorPrint && !time_mode.custom_gcode_times.empty()));
|
||||
|
||||
@@ -3086,6 +3161,39 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
ImVec2 pos_rect = ImGui::GetCursorScreenPos();
|
||||
float window_padding = 4.0f * m_scale;
|
||||
|
||||
auto format_compact_count = [](unsigned long long value) {
|
||||
static constexpr const char* suffixes[] = { "", "K", "M", "B", "T", "P", "E" };
|
||||
constexpr size_t suffix_count = sizeof(suffixes) / sizeof(suffixes[0]);
|
||||
|
||||
if (value < 1000)
|
||||
return std::to_string(value);
|
||||
|
||||
size_t suffix_index = 0;
|
||||
unsigned long long divisor = 1;
|
||||
while (suffix_index + 1 < suffix_count && value / divisor >= 1000) {
|
||||
divisor *= 1000;
|
||||
++suffix_index;
|
||||
}
|
||||
|
||||
const unsigned long long whole = value / divisor;
|
||||
const unsigned long long tenths = (value % divisor) * 10 / divisor;
|
||||
|
||||
std::string ret = std::to_string(whole);
|
||||
if (tenths != 0)
|
||||
ret += "." + std::to_string(tenths);
|
||||
ret += suffixes[suffix_index];
|
||||
return ret;
|
||||
};
|
||||
|
||||
auto format_percent = [](float percent) {
|
||||
if (percent == 0.0f)
|
||||
return std::string("0");
|
||||
|
||||
char buffer[64];
|
||||
percent > 0.001f ? ::sprintf(buffer, "%.1f", percent * 100.0f) : ::sprintf(buffer, "<0.1");
|
||||
return std::string(buffer);
|
||||
};
|
||||
|
||||
// ORCA dont use background on top bar to give modern look
|
||||
//draw_list->AddRectFilled(ImVec2(pos_rect.x,pos_rect.y - ImGui::GetStyle().WindowPadding.y),
|
||||
//ImVec2(pos_rect.x + ImGui::GetWindowWidth() + ImGui::GetFrameHeight(),pos_rect.y + ImGui::GetFrameHeight() + window_padding * 2.5),
|
||||
@@ -3122,10 +3230,10 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
case EItemType::Line: {
|
||||
draw_list->AddLine({ pos.x + 1, pos.y + icon_size + 2 }, { pos.x + icon_size - 1, pos.y + 4 }, ImGuiWrapper::to_ImU32(color), 3.0f);
|
||||
break;
|
||||
}
|
||||
case EItemType::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0 * m_scale, 6.0 * m_scale));
|
||||
|
||||
@@ -3297,14 +3405,26 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
return _u8L("from") + " " + std::string(buf1) + " " + _u8L("to") + " " + std::string(buf2) + " " + _u8L("mm");
|
||||
};
|
||||
|
||||
auto role_time_and_percent = [this, time_mode](libvgcode::EGCodeExtrusionRole role) {
|
||||
auto role_time_and_percent = [this, total_estimated_time](libvgcode::EGCodeExtrusionRole role) {
|
||||
const float time = m_viewer.get_extrusion_role_estimated_time(role);
|
||||
return std::make_pair(time, time / time_mode.time);
|
||||
return std::make_pair(time, total_estimated_time > 0.0f ? time / total_estimated_time : 0.0f);
|
||||
};
|
||||
|
||||
auto travel_time_and_percent = [this, time_mode]() {
|
||||
auto travel_time_and_percent = [this, total_estimated_time]() {
|
||||
const float time = m_viewer.get_travels_estimated_time();
|
||||
return std::make_pair(time, time / time_mode.time);
|
||||
return std::make_pair(time, total_estimated_time > 0.0f ? time / total_estimated_time : 0.0f);
|
||||
};
|
||||
|
||||
auto format_distance = [imperial_units](float distance_mm) {
|
||||
char buffer[64];
|
||||
if (imperial_units) {
|
||||
::sprintf(buffer, "%.2fin", distance_mm / GizmoObjectManipulation::in_to_mm);
|
||||
} else if (std::fabs(distance_mm) < 1000.0f) {
|
||||
::sprintf(buffer, "%.0fmm", distance_mm);
|
||||
} else {
|
||||
::sprintf(buffer, "%.2fm", distance_mm / 1000.0f);
|
||||
}
|
||||
return std::string(buffer);
|
||||
};
|
||||
|
||||
auto used_filament_per_role = [this, imperial_units](ExtrusionRole role) {
|
||||
@@ -3409,6 +3529,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
std::vector<std::string> used_filaments_length;
|
||||
std::vector<std::string> used_filaments_weight;
|
||||
std::string travel_percent;
|
||||
std::string travel_distance;
|
||||
std::string travel_moves;
|
||||
std::vector<double> model_used_filaments_m;
|
||||
std::vector<double> model_used_filaments_g;
|
||||
double total_model_used_filament_m = 0, total_model_used_filament_g = 0;
|
||||
@@ -3528,8 +3650,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
auto [model_used_filament_m, model_used_filament_g] = used_filament_per_role(convert(role));
|
||||
::sprintf(buffer, imperial_units ? "%.2fin" : "%.2fm", model_used_filament_m); // ORCA dont use spacing between value and unit
|
||||
used_filaments_length.push_back(buffer);
|
||||
::sprintf(buffer, imperial_units ? "%.2foz" : "%.2fg", model_used_filament_g); // ORCA dont use spacing between value and unit
|
||||
used_filaments_weight.push_back(buffer);
|
||||
used_filaments_weight.push_back(format_compact_weight(model_used_filament_g, imperial_units));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3542,10 +3663,19 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
else
|
||||
percent > 0.001 ? ::sprintf(buffer, "%.1f", percent * 100) : ::sprintf(buffer, "<0.1");
|
||||
travel_percent = buffer;
|
||||
percents.push_back(travel_percent);
|
||||
|
||||
// Set travel distance and moves for the Travel row Usage columns
|
||||
travel_distance = format_distance(m_print_statistics.total_travel_distance);
|
||||
used_filaments_length.push_back(travel_distance);
|
||||
|
||||
travel_moves = format_compact_count(m_print_statistics.total_travel_moves);
|
||||
used_filaments_weight.push_back(travel_moves);
|
||||
}
|
||||
|
||||
// ORCA use % symbol for percentage and use "Usage" for "Used filaments"
|
||||
offsets = calculate_offsets({ {_u8L("Line Type"), labels}, {_u8L("Time"), times}, {"%", percents}, {"", used_filaments_length}, {"", used_filaments_weight}, {_u8L("Display"), {""}}}, icon_size);
|
||||
percents.pop_back();
|
||||
append_headers({{_u8L("Line Type"), offsets[0]}, {_u8L("Time"), offsets[1]}, {"%", offsets[2]}, {_u8L("Usage"), offsets[3]}, {_u8L("Display"), offsets[5]}});
|
||||
break;
|
||||
}
|
||||
@@ -3609,7 +3739,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
{
|
||||
std::vector<std::string> total_filaments;
|
||||
char buffer[64];
|
||||
::sprintf(buffer, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", ps.total_used_filament / /*1000*/koef, ps.total_weight / unit_conver);
|
||||
const std::string total_weight_text = format_compact_weight(ps.total_weight, imperial_units);
|
||||
::sprintf(buffer, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", ps.total_used_filament / /*1000*/koef, total_weight_text.c_str());
|
||||
total_filaments.push_back(buffer);
|
||||
|
||||
|
||||
@@ -3644,9 +3775,54 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
auto append_option_item = [this, append_item](libvgcode::EOptionType type, std::vector<float> offsets) {
|
||||
auto append_option_item_with_type = [this, offsets, append_item](libvgcode::EOptionType type, const ColorRGBA& color, const std::string& label, bool visible) {
|
||||
append_item(EItemType::Rect, color, {{ label , offsets[0] }}, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type, visible]() {
|
||||
auto append_option_item = [this, append_item, current_time_mode, total_estimated_time, &format_compact_count, &format_percent, &format_distance](libvgcode::EOptionType type, std::vector<float> offsets) {
|
||||
const bool full_layout = offsets.size() > 4;
|
||||
auto option_stats = [this, current_time_mode, total_estimated_time, &format_compact_count, &format_percent, &format_distance, full_layout](libvgcode::EOptionType option_type) -> std::array<std::string, 4> {
|
||||
libvgcode::EMoveType move_type;
|
||||
bool has_move_type = true;
|
||||
switch (option_type) {
|
||||
case libvgcode::EOptionType::Wipes: { move_type = libvgcode::EMoveType::Wipe; break; }
|
||||
case libvgcode::EOptionType::Retractions: { move_type = libvgcode::EMoveType::Retract; break; }
|
||||
case libvgcode::EOptionType::Unretractions: { move_type = libvgcode::EMoveType::Unretract; break; }
|
||||
case libvgcode::EOptionType::Seams: { move_type = libvgcode::EMoveType::Seam; break; }
|
||||
case libvgcode::EOptionType::ToolChanges: { move_type = libvgcode::EMoveType::ToolChange; break; }
|
||||
default: { has_move_type = false; break; }
|
||||
}
|
||||
|
||||
if (!has_move_type)
|
||||
return { "", "", "", "" };
|
||||
|
||||
const size_t move_type_idx = static_cast<size_t>(move_type);
|
||||
float time = m_move_type_times[move_type_idx][current_time_mode];
|
||||
if (option_type == libvgcode::EOptionType::ToolChanges) {
|
||||
// Toolchange delays are injected via synchronize() and are not attributed to ToolChange move vertices.
|
||||
time = m_print_statistics.total_filament_load_time + m_print_statistics.total_filament_unload_time + m_print_statistics.total_tool_change_time;
|
||||
}
|
||||
const std::string time_text = full_layout && time > 0.0f ? short_time(get_time_dhms(time)) : "";
|
||||
const std::string percent_text = full_layout && total_estimated_time > 0.0f ? format_percent(time / total_estimated_time) : "";
|
||||
const float seam_distance = m_print_statistics.total_seam_gap_distance + m_print_statistics.total_seam_scarf_distance;
|
||||
const float distance = (option_type == libvgcode::EOptionType::Seams && seam_distance > 0.0f) ? seam_distance : m_move_type_distances[move_type_idx];
|
||||
const std::string distance_text = full_layout && (option_type == libvgcode::EOptionType::Wipes || option_type == libvgcode::EOptionType::Retractions || option_type == libvgcode::EOptionType::Unretractions || option_type == libvgcode::EOptionType::Seams)
|
||||
? format_distance(distance)
|
||||
: "";
|
||||
const std::string count_text = full_layout ? format_compact_count(m_move_type_counts[move_type_idx]) : "";
|
||||
|
||||
return { time_text, percent_text, distance_text, count_text };
|
||||
};
|
||||
|
||||
auto append_option_item_with_type = [this, offsets, append_item, full_layout](libvgcode::EOptionType type, const ColorRGBA& color, const std::string& label, bool visible,
|
||||
const std::string& time_text, const std::string& percent_text, const std::string& distance_text, const std::string& count_text) {
|
||||
std::vector<std::pair<std::string, float>> columns_offsets;
|
||||
columns_offsets.push_back({ label , offsets[0] });
|
||||
if (full_layout && !time_text.empty())
|
||||
columns_offsets.push_back({ time_text, offsets[1] });
|
||||
if (full_layout && !percent_text.empty())
|
||||
columns_offsets.push_back({ percent_text, offsets[2] });
|
||||
if (full_layout && !distance_text.empty())
|
||||
columns_offsets.push_back({ distance_text, offsets[3] });
|
||||
if (full_layout && !count_text.empty())
|
||||
columns_offsets.push_back({ count_text, distance_text.empty() ? offsets[3] : offsets[4] });
|
||||
append_item(EItemType::Rect, color, columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type, visible]() {
|
||||
m_viewer.toggle_option_visibility(type);
|
||||
update_moves_slider();
|
||||
});
|
||||
@@ -3654,18 +3830,33 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
const bool visible = m_viewer.is_option_visible(type);
|
||||
if (type == libvgcode::EOptionType::Travels) {
|
||||
//BBS: only display travel time in FeatureType view
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), _u8L("Travel"), visible);
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), _u8L("Travel"), visible, "", "", "", "");
|
||||
}
|
||||
else if (type == libvgcode::EOptionType::Seams) {
|
||||
const auto option_values = option_stats(type);
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Seams)), _u8L("Seams"), visible,
|
||||
option_values[0], option_values[1], option_values[2], option_values[3]);
|
||||
}
|
||||
else if (type == libvgcode::EOptionType::Retractions) {
|
||||
const auto option_values = option_stats(type);
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Retractions)), _u8L("Retract"), visible,
|
||||
option_values[0], option_values[1], option_values[2], option_values[3]);
|
||||
}
|
||||
else if (type == libvgcode::EOptionType::Unretractions) {
|
||||
const auto option_values = option_stats(type);
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Unretractions)), _u8L("Unretract"), visible,
|
||||
option_values[0], option_values[1], option_values[2], option_values[3]);
|
||||
}
|
||||
else if (type == libvgcode::EOptionType::ToolChanges) {
|
||||
const auto option_values = option_stats(type);
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::ToolChanges)), _u8L("Filament Changes"), visible,
|
||||
option_values[0], option_values[1], option_values[2], option_values[3]);
|
||||
}
|
||||
else if (type == libvgcode::EOptionType::Wipes) {
|
||||
const auto option_values = option_stats(type);
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Wipes)), _u8L("Wipe"), visible,
|
||||
option_values[0], option_values[1], option_values[2], option_values[3]);
|
||||
}
|
||||
else if (type == libvgcode::EOptionType::Seams)
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Seams)), _u8L("Seams"), visible);
|
||||
else if (type == libvgcode::EOptionType::Retractions)
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Retractions)), _u8L("Retract"), visible);
|
||||
else if (type == libvgcode::EOptionType::Unretractions)
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Unretractions)), _u8L("Unretract"), visible);
|
||||
else if (type == libvgcode::EOptionType::ToolChanges)
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::ToolChanges)), _u8L("Filament Changes"), visible);
|
||||
else if (type == libvgcode::EOptionType::Wipes)
|
||||
append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Wipes)), _u8L("Wipe"), visible);
|
||||
};
|
||||
|
||||
const libvgcode::EViewType new_view_type = curr_view_type;
|
||||
@@ -3705,6 +3896,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
columns_offsets.push_back({ _u8L("Travel"), offsets[0] });
|
||||
columns_offsets.push_back({ travel_time, offsets[1] });
|
||||
columns_offsets.push_back({ travel_percent, offsets[2] });
|
||||
columns_offsets.push_back({ travel_distance, offsets[3] }); // Usage column
|
||||
columns_offsets.push_back({ travel_moves, offsets[4] }); // Usage column
|
||||
append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, item, visible]() {
|
||||
m_viewer.toggle_option_visibility(item);
|
||||
update_moves_slider();
|
||||
@@ -3796,7 +3989,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
size_t i = 0;
|
||||
const std::vector<uint8_t>& used_extruders_ids = m_viewer.get_used_extruders_ids();
|
||||
for (uint8_t extruder_id : used_extruders_ids) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]);
|
||||
const std::string weight_text = format_compact_weight(model_used_filaments_g[i], imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m[i], weight_text.c_str());
|
||||
append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} });
|
||||
// append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1),
|
||||
// true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]);
|
||||
@@ -3809,7 +4003,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
char buf[64];
|
||||
imgui.text(_u8L("Total") + ":");
|
||||
ImGui::SameLine();
|
||||
::sprintf(buf, imperial_units ? "%.2f in / %.2f oz" : "%.2f m / %.2f g", ps.total_used_filament / koef, ps.total_weight / unit_conver);
|
||||
const std::string total_weight_text = format_compact_weight(ps.total_weight, imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in / %s" : "%.2f m / %s", ps.total_used_filament / koef, total_weight_text.c_str());
|
||||
imgui.text(buf);
|
||||
|
||||
ImGui::Dummy({window_padding, window_padding});
|
||||
@@ -3855,34 +4050,39 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
float column_sum_m = 0.0f;
|
||||
float column_sum_g = 0.0f;
|
||||
if (displayed_columns & ColumnData::Model) {
|
||||
const std::string weight_text = format_compact_weight(model_used_filaments_g[i], imperial_units);
|
||||
if ((displayed_columns & ~ColumnData::Model) > 0)
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m[i], model_used_filaments_g[i] / unit_conver);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", model_used_filaments_m[i], weight_text.c_str());
|
||||
else
|
||||
::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i] / unit_conver);
|
||||
::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Model")] });
|
||||
column_sum_m += model_used_filaments_m[i];
|
||||
column_sum_g += model_used_filaments_g[i];
|
||||
}
|
||||
if (displayed_columns & ColumnData::Support) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", support_used_filaments_m[i], support_used_filaments_g[i] / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(support_used_filaments_g[i], imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", support_used_filaments_m[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Support")] });
|
||||
column_sum_m += support_used_filaments_m[i];
|
||||
column_sum_g += support_used_filaments_g[i];
|
||||
}
|
||||
if (displayed_columns & ColumnData::Flushed) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", flushed_filaments_m[i], flushed_filaments_g[i] / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(flushed_filaments_g[i], imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", flushed_filaments_m[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Flushed")]});
|
||||
column_sum_m += flushed_filaments_m[i];
|
||||
column_sum_g += flushed_filaments_g[i];
|
||||
}
|
||||
if (displayed_columns & ColumnData::WipeTower) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", wipe_tower_used_filaments_m[i], wipe_tower_used_filaments_g[i] / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(wipe_tower_used_filaments_g[i], imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", wipe_tower_used_filaments_m[i], weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Tower")] });
|
||||
column_sum_m += wipe_tower_used_filaments_m[i];
|
||||
column_sum_g += wipe_tower_used_filaments_g[i];
|
||||
}
|
||||
if ((displayed_columns & ~ColumnData::Model) > 0) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", column_sum_m, column_sum_g / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(column_sum_g, imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", column_sum_m, weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Total")] });
|
||||
}
|
||||
|
||||
@@ -3908,27 +4108,32 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
std::vector<std::pair<std::string, float>> columns_offsets;
|
||||
columns_offsets.push_back({ _u8L("Total"), color_print_offsets[_u8L("Filament")]});
|
||||
if (displayed_columns & ColumnData::Model) {
|
||||
const std::string weight_text = format_compact_weight(total_model_used_filament_g, imperial_units);
|
||||
if ((displayed_columns & ~ColumnData::Model) > 0)
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m, total_model_used_filament_g / unit_conver);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_model_used_filament_m, weight_text.c_str());
|
||||
else
|
||||
::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", total_model_used_filament_m, total_model_used_filament_g / unit_conver);
|
||||
::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", total_model_used_filament_m, weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Model")] });
|
||||
}
|
||||
if (displayed_columns & ColumnData::Support) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_support_used_filament_m, total_support_used_filament_g / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(total_support_used_filament_g, imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_support_used_filament_m, weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Support")] });
|
||||
}
|
||||
if (displayed_columns & ColumnData::Flushed) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_flushed_filament_m, total_flushed_filament_g / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(total_flushed_filament_g, imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_flushed_filament_m, weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Flushed")] });
|
||||
}
|
||||
if (displayed_columns & ColumnData::WipeTower) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_wipe_tower_used_filament_m, total_wipe_tower_used_filament_g / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(total_wipe_tower_used_filament_g, imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_wipe_tower_used_filament_m, weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Tower")] });
|
||||
}
|
||||
if ((displayed_columns & ~ColumnData::Model) > 0) {
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m + total_support_used_filament_m + total_flushed_filament_m + total_wipe_tower_used_filament_m,
|
||||
(total_model_used_filament_g + total_support_used_filament_g + total_flushed_filament_g + total_wipe_tower_used_filament_g) / unit_conver);
|
||||
const std::string weight_text = format_compact_weight(total_model_used_filament_g + total_support_used_filament_g + total_flushed_filament_g + total_wipe_tower_used_filament_g, imperial_units);
|
||||
::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_model_used_filament_m + total_support_used_filament_m + total_flushed_filament_m + total_wipe_tower_used_filament_m,
|
||||
weight_text.c_str());
|
||||
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Total")] });
|
||||
}
|
||||
append_item(EItemType::None, libvgcode::convert(tool_colors[0]), columns_offsets);
|
||||
@@ -3939,16 +4144,14 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
ImGui::SameLine();
|
||||
imgui.text(_u8L("Filament change times") + ":");
|
||||
ImGui::SameLine();
|
||||
::sprintf(buf, "%d", m_print_statistics.total_filament_changes);
|
||||
imgui.text(buf);
|
||||
imgui.text(format_compact_count(m_print_statistics.total_filament_changes));
|
||||
|
||||
//display tool change times
|
||||
ImGui::Dummy({window_padding, window_padding});
|
||||
ImGui::SameLine();
|
||||
imgui.text(_u8L("Tool changes") + ":");
|
||||
ImGui::SameLine();
|
||||
::sprintf(buf, "%d", m_print_statistics.total_extruder_changes);
|
||||
imgui.text(buf);
|
||||
imgui.text(format_compact_count(m_print_statistics.total_extruder_changes));
|
||||
|
||||
//BBS display cost
|
||||
ImGui::Dummy({ window_padding, window_padding });
|
||||
@@ -4075,8 +4278,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
imgui.text(buffer);
|
||||
|
||||
ImGui::SameLine(offsets[3]);
|
||||
::sprintf(buffer, "%.2f g", used_filament.second);
|
||||
imgui.text(buffer);
|
||||
imgui.text(format_compact_weight(used_filament.second, imperial_units));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4401,8 +4603,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / koef);
|
||||
imgui.text(buf);
|
||||
ImGui::SameLine();
|
||||
::sprintf(buf, imperial_units ? " %.2f oz" : " %.2f g", ps.total_weight / unit_conver);
|
||||
imgui.text(buf);
|
||||
imgui.text(" " + format_compact_weight(ps.total_weight, imperial_units));
|
||||
ImGui::Dummy({ window_padding, window_padding });
|
||||
ImGui::SameLine();
|
||||
imgui.text(model_filament_str + ":");
|
||||
@@ -4412,8 +4613,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / koef - exlude_m);
|
||||
imgui.text(buf);
|
||||
ImGui::SameLine();
|
||||
::sprintf(buf, imperial_units ? " %.2f oz" : " %.2f g", (ps.total_weight - exlude_g) / unit_conver);
|
||||
imgui.text(buf);
|
||||
imgui.text(" " + format_compact_weight(ps.total_weight - exlude_g, imperial_units));
|
||||
//BBS: display cost of filaments
|
||||
ImGui::Dummy({ window_padding, window_padding });
|
||||
ImGui::SameLine();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// needed for tech VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
#include <libvgcode/include/Types.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <float.h>
|
||||
#include <set>
|
||||
@@ -184,6 +185,9 @@ private:
|
||||
unsigned int m_last_result_id{ 0 };
|
||||
//BBS: save m_gcode_result as well
|
||||
const GCodeProcessorResult* m_gcode_result;
|
||||
std::array<unsigned int, static_cast<size_t>(EMoveType::Count)> m_move_type_counts{};
|
||||
std::array<std::array<float, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)>, static_cast<size_t>(EMoveType::Count)> m_move_type_times{};
|
||||
std::array<float, static_cast<size_t>(EMoveType::Count)> m_move_type_distances{};
|
||||
//BBS: add only gcode mode
|
||||
bool m_only_gcode_in_preview {false};
|
||||
|
||||
|
||||
@@ -279,9 +279,12 @@ ParamsPanel::ParamsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, c
|
||||
});
|
||||
m_mode_icon->SetToolTip(_L("Cycle settings visibility"));
|
||||
m_mode_view = new ModeSwitchButton(m_top_panel);
|
||||
m_mode_view->SetSelection(mode_to_selection(wxGetApp().get_saved_mode()));
|
||||
if (wxGetApp().get_mode() == comDevelop)
|
||||
if (wxGetApp().get_mode() == comDevelop) {
|
||||
m_mode_view->SetSelection(mode_to_selection(comExpert));
|
||||
m_mode_view->Enable(false);
|
||||
} else {
|
||||
m_mode_view->SetSelection(mode_to_selection(wxGetApp().get_saved_mode()));
|
||||
}
|
||||
|
||||
// BBS: new layout
|
||||
//m_search_btn = new ScalableButton(m_top_panel, wxID_ANY, "search", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true);
|
||||
@@ -648,12 +651,13 @@ void ParamsPanel::update_mode()
|
||||
if (mode_view == nullptr)
|
||||
return;
|
||||
|
||||
mode_view->SetSelection(mode_to_selection(Slic3r::GUI::wxGetApp().get_saved_mode()));
|
||||
if (app_mode == comDevelop) {
|
||||
mode_view->SetSelection(mode_to_selection(comExpert));
|
||||
mode_view->Enable(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mode_view->SetSelection(mode_to_selection(Slic3r::GUI::wxGetApp().get_saved_mode()));
|
||||
if (!mode_view->IsEnabled())
|
||||
mode_view->Enable();
|
||||
};
|
||||
|
||||
@@ -424,9 +424,12 @@ void Tab::create_preset_tab()
|
||||
});
|
||||
m_top_sizer->Add(m_mode_icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(SidebarProps::WideSpacing()));
|
||||
m_mode_view = new ModeSwitchButton(m_top_panel);
|
||||
m_mode_view->SetSelection(mode_to_selection(wxGetApp().get_saved_mode()));
|
||||
if (wxGetApp().get_mode() == comDevelop)
|
||||
if (wxGetApp().get_mode() == comDevelop) {
|
||||
m_mode_view->SetSelection(mode_to_selection(comExpert));
|
||||
m_mode_view->Enable(false);
|
||||
} else {
|
||||
m_mode_view->SetSelection(mode_to_selection(wxGetApp().get_saved_mode()));
|
||||
}
|
||||
m_top_sizer->AddSpacer(FromDIP(SidebarProps::ElementSpacing()));
|
||||
m_top_sizer->Add( m_mode_view, 0, wxALIGN_CENTER_VERTICAL);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/Utils/NetworkAgent.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
@@ -371,7 +372,97 @@ void ZUserLogin::OnScriptMessage(wxWebViewEvent &evt)
|
||||
{
|
||||
m_AutotestToken = j["data"]["token"];
|
||||
}
|
||||
if (strCmd == "user_login") {
|
||||
if (strCmd == "user_ticket_login") {
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
if (!agent || !m_cloud_agent || !j.contains("data") || !j["data"].is_object() || !j["data"].contains("ticket")) {
|
||||
wxMessageBox(_L("Login failed. Please try again."), _L("Login"), wxICON_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto provider = m_cloud_agent->get_id();
|
||||
std::string ticket = j["data"]["ticket"].get<std::string>();
|
||||
|
||||
unsigned int token_http_code = 0;
|
||||
std::string token_body;
|
||||
int token_result = agent->get_my_token(ticket, &token_http_code, &token_body, provider);
|
||||
if (token_result != 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "embedded_login: get_my_token failed, http_code=" << token_http_code;
|
||||
wxMessageBox(_L("Login failed. Please try again."), _L("Login"), wxICON_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string access_token;
|
||||
std::string refresh_token;
|
||||
std::string expires_in_str;
|
||||
std::string refresh_expires_in_str;
|
||||
try {
|
||||
json token_j = json::parse(token_body);
|
||||
if (token_j.contains("accessToken"))
|
||||
access_token = token_j["accessToken"].get<std::string>();
|
||||
if (token_j.contains("refreshToken"))
|
||||
refresh_token = token_j["refreshToken"].get<std::string>();
|
||||
if (token_j.contains("expiresIn"))
|
||||
expires_in_str = std::to_string(token_j["expiresIn"].get<double>());
|
||||
if (token_j.contains("refreshExpiresIn"))
|
||||
refresh_expires_in_str = std::to_string(token_j["refreshExpiresIn"].get<double>());
|
||||
} catch (...) {
|
||||
wxMessageBox(_L("Login failed. Please try again."), _L("Login"), wxICON_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (access_token.empty()) {
|
||||
wxMessageBox(_L("Login failed. Please try again."), _L("Login"), wxICON_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int profile_http_code = 0;
|
||||
std::string profile_body;
|
||||
int profile_result = agent->get_my_profile(access_token, &profile_http_code, &profile_body, provider);
|
||||
if (profile_result != 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "embedded_login: get_my_profile failed, http_code=" << profile_http_code;
|
||||
wxMessageBox(_L("Login failed. Please try again."), _L("Login"), wxICON_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string user_id;
|
||||
std::string user_name;
|
||||
std::string user_account;
|
||||
std::string user_avatar;
|
||||
try {
|
||||
json user_j = json::parse(profile_body);
|
||||
if (user_j.contains("uidStr"))
|
||||
user_id = user_j["uidStr"].get<std::string>();
|
||||
if (user_j.contains("name"))
|
||||
user_name = user_j["name"].get<std::string>();
|
||||
if (user_j.contains("avatar"))
|
||||
user_avatar = user_j["avatar"].get<std::string>();
|
||||
if (user_j.contains("account"))
|
||||
user_account = user_j["account"].get<std::string>();
|
||||
} catch (...) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "embedded_login: profile JSON parse failed";
|
||||
}
|
||||
|
||||
json login_j;
|
||||
login_j["command"] = "user_login";
|
||||
login_j["data"]["autotest_token"] = m_AutotestToken;
|
||||
login_j["data"]["refresh_token"] = refresh_token;
|
||||
login_j["data"]["token"] = access_token;
|
||||
login_j["data"]["expires_in"] = expires_in_str;
|
||||
login_j["data"]["refresh_expires_in"] = refresh_expires_in_str;
|
||||
login_j["data"]["user"]["uid"] = user_id;
|
||||
login_j["data"]["user"]["name"] = user_name;
|
||||
login_j["data"]["user"]["account"] = user_account;
|
||||
login_j["data"]["user"]["avatar"] = user_avatar;
|
||||
std::string message_json = login_j.dump();
|
||||
|
||||
// End modal dialog first to unblock event loop before processing callbacks
|
||||
EndModal(wxID_OK);
|
||||
|
||||
// Handle message after modal dialog ends to avoid deadlock
|
||||
// Use wxTheApp->CallAfter to ensure it runs after modal loop exits
|
||||
wxTheApp->CallAfter([message_json, provider]() { wxGetApp().handle_script_message(message_json, provider); });
|
||||
}
|
||||
else if (strCmd == "user_login") {
|
||||
j["data"]["autotest_token"] = m_AutotestToken;
|
||||
std::string message_json = j.dump();
|
||||
|
||||
|
||||
@@ -372,27 +372,31 @@ WipingDialog::WipingDialog(wxWindow* parent, const int max_flush_volume) :
|
||||
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
this->SetSizer(main_sizer);
|
||||
this->SetBackgroundColour(*wxWHITE);
|
||||
auto filament_count= wxGetApp().preset_bundle->project_config.option<ConfigOptionStrings>("filament_colour")->values.size();
|
||||
wxSize extra_size = { FromDIP(100),FromDIP(235) };
|
||||
if (filament_count <= 2)
|
||||
extra_size.y += FromDIP(16) * 3 + FromDIP(32);
|
||||
else if (filament_count == 3)
|
||||
extra_size.y += FromDIP(16) * 3;
|
||||
else if (4 <= filament_count && filament_count <= 8)
|
||||
extra_size.y += FromDIP(16) * 2;
|
||||
else
|
||||
extra_size.y += FromDIP(16);
|
||||
auto filament_count = wxGetApp().preset_bundle->project_config.option<ConfigOptionStrings>("filament_colour")->values.size();
|
||||
|
||||
wxSize max_scroll_size = { FromDIP(1000),FromDIP(500) };
|
||||
wxSize estimate_size = { (int)(filament_count + 1) * FromDIP(60),(int)(filament_count + 1) * FromDIP(30)+FromDIP(2)};
|
||||
wxSize scroll_size ={ std::min(max_scroll_size.x,estimate_size.x),std::min(max_scroll_size.y,estimate_size.y) };
|
||||
wxSize applied_size = scroll_size + extra_size;
|
||||
// Estimate table scroll area size based on filament count
|
||||
// Each table cell is ~60x25 DIP, plus headers and borders
|
||||
wxSize max_scroll_size = { FromDIP(1000), FromDIP(500) };
|
||||
wxSize table_size = { (int)(filament_count + 1) * FromDIP(60), (int)(filament_count + 1) * FromDIP(25) + FromDIP(2) };
|
||||
wxSize scroll_size = { std::min(max_scroll_size.x, table_size.x), std::min(max_scroll_size.y, table_size.y) };
|
||||
|
||||
// Fixed overhead: padding (~30), tip panel (~70), controls row (~50),
|
||||
// description/multiplier section (~130), button row (~45) = ~325 DIP
|
||||
wxSize fixed_overhead = { FromDIP(100), FromDIP(325) };
|
||||
wxSize applied_size = scroll_size + fixed_overhead;
|
||||
|
||||
// Clamp to screen size (leave some margin for window decorations)
|
||||
wxSize scaled_screen_size = wxGetDisplaySize();
|
||||
double scale_factor = wxDisplay().GetScaleFactor();
|
||||
scaled_screen_size = { (int)(scaled_screen_size.x / scale_factor),(int)(scaled_screen_size.y / scale_factor) };
|
||||
scaled_screen_size = { (int)(scaled_screen_size.x / scale_factor), (int)(scaled_screen_size.y / scale_factor) };
|
||||
wxSize screen_margin = { FromDIP(40), FromDIP(60) };
|
||||
scaled_screen_size -= screen_margin;
|
||||
|
||||
applied_size = { std::min(applied_size.x,scaled_screen_size.x),std::min(applied_size.y,scaled_screen_size.y) };
|
||||
applied_size = { std::min(applied_size.x, scaled_screen_size.x), std::min(applied_size.y, scaled_screen_size.y) };
|
||||
|
||||
// Ensure a reasonable minimum size so the dialog is usable even when clamped
|
||||
applied_size.x = std::max(applied_size.x, FromDIP(350));
|
||||
applied_size.y = std::max(applied_size.y, FromDIP(450));
|
||||
m_webview = wxWebView::New(this, wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
|
||||
Reference in New Issue
Block a user