OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::GCodeViewer Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/GCodeViewer.hpp>

Collaboration diagram for Slic3r::GUI::GCodeViewer:

Classes

struct  SequentialView
struct  ExtruderFilament
struct  Shells
struct  ImexMarkerPlan
struct  ImexMarkerKey

Public Member Functions

 GCodeViewer ()
 ~GCodeViewer ()
void on_change_color_mode (bool is_dark)
void set_scale (float scale=1.0)
void init (ConfigOptionMode mode, Slic3r::PresetBundle *preset_bundle)
void update_by_mode (ConfigOptionMode mode)
void load_as_gcode (const GCodeProcessorResult &gcode_result, const Print &print, const std::vector< std::string > &str_tool_colors, const std::vector< std::string > &str_color_print_colors, const BuildVolume &build_volume, const std::vector< BoundingBoxf3 > &exclude_bounding_box, ConfigOptionMode mode, bool only_gcode=false)
void load_as_preview (libvgcode::GCodeInputData &&data)
void update_shells_color_by_extruder (const DynamicPrintConfig *config)
void set_shell_transparency (float alpha=0.15f)
void reset ()
void reset_shell ()
void load_shells (const Print &print, bool initialized, bool force_previewing=false)
void set_shells_on_preview (bool is_previewing)
void render_all_plates_stats (const std::vector< const GCodeProcessorResult * > &gcode_result_list, bool show=true) const
void render_scene (int canvas_width, int canvas_height)
void render_translucent_toolpaths (int canvas_width, int canvas_height)
void render_overlay (int canvas_width, int canvas_height, int right_margin)
void render_shadow_casters (const Transform3d &light_view_matrix, const Transform3d &light_projection_matrix, const Vec3d &light_position)
void set_shadow_map (int texture_unit, const Transform3d &light_view_projection, float intensity, float texel_size)
void set_tone (float exposure, float saturation)
void set_clipping_plane (const ClippingPlane &plane)
void set_light_top_dir (const Vec3d &direction)
void set_gloss (bool gloss)
bool has_data () const
bool can_export_toolpaths () const
std::vector< int > get_plater_extruder ()
const float get_max_print_height () const
bool is_machine_frame_transform_active () const
const BoundingBoxf3 & get_paths_bounding_box () const
const BoundingBoxf3 & get_max_bounding_box () const
const BoundingBoxf3 & get_shell_bounding_box () const
std::vector< double > get_layers_zs () const
std::vector< float > get_layers_times () const
const std::array< size_t, 2 > & get_layers_z_range () const
const GCodeProcessorResult::ObjectMass & get_plate_mass () const
const std::vector< GCodeProcessorResult::ObjectMass > & get_object_masses () const
const std::vector< GCodeProcessorResult::ObjectMass > & get_body_masses () const
const std::vector< GCodeProcessorResult::ObjectMass > & get_support_masses () const
size_t get_vertices_count () const
size_t get_layers_count () const
size_t shadow_casters_signature () const
const SequentialView & get_sequential_view () const
void update_sequential_view_current (unsigned int first, unsigned int last)
IMSlider * get_moves_slider ()
IMSlider * get_layers_slider ()
void enable_moves_slider (bool enable) const
void update_moves_slider (bool set_to_max=false)
void update_layers_slider_mode ()
const libvgcode::Interval & get_gcode_view_full_range () const
const libvgcode::Interval & get_gcode_view_enabled_range () const
const libvgcode::Interval & get_gcode_view_visible_range () const
const libvgcode::PathVertex & get_gcode_vertex_at (size_t id) const
bool is_contained_in_bed () const
bool is_only_gcode_in_preview () const
void set_view_type (libvgcode::EViewType type)
void select_view_type (libvgcode::EViewType type)
void apply_default_view_type ()
void reset_visible (libvgcode::EViewType type)
libvgcode::EViewType get_view_type () const
void set_dim_previous_layers (bool value)
bool is_dim_previous_layers () const
void set_dim_previous_layers_brightness (float value)
float get_dim_previous_layers_brightness () const
void set_translucent_filaments (bool value)
void set_layers_z_range (const std::array< unsigned int, 2 > &layers_z_range)
bool is_legend_shown () const
void show_legend (bool show)
void enable_legend (bool enable)
float get_legend_height ()
void export_toolpaths_to_obj (const char *filename) const
void set_belt_printer (bool enabled, float angle_deg)
bool is_belt_view () const
void toggle_belt_show_designed ()
bool is_belt_show_designed () const
size_t get_extruders_count ()
void push_combo_style ()
void pop_combo_style ()
void invalidate_legend ()

Static Public Member Functions

static std::string view_type_to_config_name (libvgcode::EViewType type)
static bool view_type_from_config_name (const std::string &name, libvgcode::EViewType &type)
static std::vector< std::pair< std::string, std::string > > default_view_type_choices ()

Public Attributes

ConflictResultOpt m_conflict_result
GCodeCheckResult m_gcode_check_result
FilamentPrintableResult filament_printable_reuslt
Shells m_shells
float m_scale = 1.0

Private Member Functions

int sequential_view_height (int canvas_height) const
void render_toolpaths ()
void render_markers (int canvas_width, int canvas_height)
void render_shells (int canvas_width, int canvas_height)
ColorRGBA shown_filament_color (ColorRGBA color) const
void render_legend (float &legend_height, int canvas_width, int canvas_height, int right_margin)
void render_legend_color_arr_recommen (float window_padding)
void render_slider (int canvas_width, int canvas_height)

Static Private Member Functions

static ImexMarkerPlan resolve_imex_marker_plan (const DynamicPrintConfig &printer_cfg, const std::string &mode, const BoundingBoxf &bed_extents)

Private Attributes

std::vector< int > m_plater_extruder
bool m_gl_data_initialized { false }
unsigned int m_last_result_id { 0 }
bool m_last_belt_show_designed { true }
std::vector< double > m_belt_layer_zs
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 {}
bool m_only_gcode_in_preview {false}
std::vector< ExtruderFilament > m_left_extruder_filament
std::vector< ExtruderFilament > m_right_extruder_filament
size_t m_nozzle_nums
BoundingBoxf3 m_paths_bounding_box
BoundingBoxf3 m_max_bounding_box
BoundingBoxf3 m_shell_bounding_box
float m_max_print_height { 0.0f }
bool m_machine_frame_transform_active { false }
float m_z_offset { 0.0f }
ConfigOptionMode m_user_mode
bool m_fold = {false}
std::string m_marker_filename
ImexMarkerKey m_imex_marker_key
ImexMarkerPlan m_imex_marker_plan
GLModel m_imex_toolhead_box
float m_imex_box_mesh_wx { 0.0f }
float m_imex_box_mesh_wy { 0.0f }
size_t m_extruders_count
std::vector< float > m_filament_diameters
std::vector< float > m_filament_densities
SequentialView m_sequential_view
IMSlider * m_moves_slider
IMSlider * m_layers_slider
std::vector< libvgcode::EViewType > view_type_items
std::vector< std::string > view_type_items_str
int m_view_type_sel = 0
std::string m_applied_default_view_type_key
std::vector< EMoveType > options_items
bool m_legend_visible { true }
bool m_legend_enabled { true }
float m_legend_height
PrintEstimatedStatistics m_print_statistics
std::array< float, 2 > m_detected_point_sizes = { 0.0f, 0.0f }
GCodeProcessorResult::SettingsIds m_settings_ids
std::vector< CustomGCode::Item > m_custom_gcode_per_print_z
GCodeProcessorResult::ObjectMass m_plate_mass
std::vector< GCodeProcessorResult::ObjectMass > m_object_masses
std::vector< GCodeProcessorResult::ObjectMass > m_body_masses
std::vector< GCodeProcessorResult::ObjectMass > m_support_masses
bool m_contained_in_bed { true }
bool m_no_render_path { false }
bool m_is_dark = false
bool m_belt_view_enabled = false
bool m_belt_show_designed = true
float m_belt_angle_deg = 0.f
libvgcode::Viewer m_viewer
std::array< float, 4 > m_clipping_plane { 0.0f, 0.0f, 0.0f, 1.0f }
bool m_loaded_as_preview { false }

Detailed Description


Class Documentation

◆ Slic3r::GUI::GCodeViewer::ExtruderFilament

struct Slic3r::GUI::GCodeViewer::ExtruderFilament
Collaboration diagram for Slic3r::GUI::GCodeViewer::ExtruderFilament:
Class Members
unsigned char filament_id
string hex_color
bool is_support_filament
string type

◆ Slic3r::GUI::GCodeViewer::Shells

struct Slic3r::GUI::GCodeViewer::Shells
Collaboration diagram for Slic3r::GUI::GCodeViewer::Shells:
Class Members
bool previewing {false}
int print_id {-1}
int print_modify_count {-1}
bool visible {false}
GLVolumeCollection volumes

◆ Slic3r::GUI::GCodeViewer::ImexMarkerPlan

struct Slic3r::GUI::GCodeViewer::ImexMarkerPlan
Collaboration diagram for Slic3r::GUI::GCodeViewer::ImexMarkerPlan:
Class Members
float box_wx = 0.0f
float box_wy = 0.0f
vector< Carriage > carriages
float pri_box_offset_x = 0.0f
float pri_box_offset_y = 0.0f
int pri_head = -1

◆ Slic3r::GUI::GCodeViewer::ImexMarkerKey

struct Slic3r::GUI::GCodeViewer::ImexMarkerKey
Collaboration diagram for Slic3r::GUI::GCodeViewer::ImexMarkerKey:
Class Members
string mode
vector< string > mode_active_tools
vector< string > mode_names
Scalars s

Constructor & Destructor Documentation

◆ GCodeViewer()

Slic3r::GUI::GCodeViewer::GCodeViewer ( )
1142{
1143 m_moves_slider = new IMSlider(0, 0, 0, 100, wxSL_HORIZONTAL);
1144 m_layers_slider = new IMSlider(0, 0, 0, 100, wxSL_VERTICAL);
1145}
IMSlider * m_layers_slider
Definition GCodeViewer.hpp:334
IMSlider * m_moves_slider
Definition GCodeViewer.hpp:333

References m_layers_slider, and m_moves_slider.

◆ ~GCodeViewer()

Slic3r::GUI::GCodeViewer::~GCodeViewer ( )
1148{
1149 reset();
1150 if (m_moves_slider) {
1151 delete m_moves_slider;
1152 m_moves_slider = nullptr;
1153 }
1154 if (m_layers_slider) {
1155 delete m_layers_slider;
1156 m_layers_slider = nullptr;
1157 }
1158}
void reset()
Definition GCodeViewer.cpp:1959

References m_layers_slider, m_moves_slider, and reset().

Here is the call graph for this function:

Member Function Documentation

◆ apply_default_view_type()

void Slic3r::GUI::GCodeViewer::apply_default_view_type ( )
1279{
1280 const std::string preference = wxGetApp().app_config->get("preview_default_view_type");
1281
1282 std::string key = preference;
1284 if (preference == "last") {
1285 if (!view_type_from_config_name(wxGetApp().app_config->get("preview_last_view_type"), type))
1287 }
1288 else if (!view_type_from_config_name(preference, type)) {
1289 // "auto", or an unknown value written by a newer version
1290 const bool multi_material = m_viewer.get_used_extruders_count() > 1;
1292 key = multi_material ? "auto_multi_material" : "auto_single_material";
1293 }
1294
1296 return;
1297
1299 select_view_type(type);
1300}
static bool view_type_from_config_name(const std::string &name, libvgcode::EViewType &type)
Definition GCodeViewer.cpp:1245
void select_view_type(libvgcode::EViewType type)
Definition GCodeViewer.cpp:1267
libvgcode::Viewer m_viewer
Definition GCodeViewer.hpp:374
std::string m_applied_default_view_type_key
Definition GCodeViewer.hpp:348
EViewType
Definition Types.hpp:91
@ ColorPrint
Definition Types.hpp:94
@ FeatureType
Definition Types.hpp:93

References libvgcode::ColorPrint, libvgcode::FeatureType, m_applied_default_view_type_key, m_viewer, select_view_type(), and view_type_from_config_name().

Referenced by init(), and load_as_gcode().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ can_export_toolpaths()

bool Slic3r::GUI::GCodeViewer::can_export_toolpaths ( ) const
2616{
2617 const libvgcode::Interval& visible_range = m_viewer.get_view_visible_range();
2618 for (size_t i = visible_range[0]; i <= visible_range[1]; ++i) {
2619 if (m_viewer.get_vertex_at(i).is_extrusion())
2620 return true;
2621 }
2622 return false;
2623}
std::array< std::size_t, 2 > Interval
Definition Types.hpp:85

References m_viewer.

◆ default_view_type_choices()

std::vector< std::pair< std::string, std::string > > Slic3r::GUI::GCodeViewer::default_view_type_choices ( )
static
1257{
1258 std::vector<std::pair<std::string, std::string>> choices = {
1259 { "auto", _u8L("Automatic") },
1260 { "last", _u8L("Last used") },
1261 };
1262 for (const auto& [name, type] : view_type_config_map())
1263 choices.push_back({ name, get_view_type_string(type) });
1264 return choices;
1265}
static const std::vector< std::pair< std::string, libvgcode::EViewType > > & view_type_config_map()
Definition GCodeViewer.cpp:183
static std::string get_view_type_string(libvgcode::EViewType view_type)
Definition GCodeViewer.cpp:141
#define _u8L(s)
Definition I18N.hpp:11

References _u8L, Slic3r::GUI::get_view_type_string(), and Slic3r::GUI::view_type_config_map().

Referenced by Slic3r::GUI::PreferencesDialog::create_items().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ enable_legend()

void Slic3r::GUI::GCodeViewer::enable_legend ( bool enable)
inline
519{ m_legend_enabled = enable; }
bool m_legend_enabled
Definition GCodeViewer.hpp:352

References m_legend_enabled.

◆ enable_moves_slider()

void Slic3r::GUI::GCodeViewer::enable_moves_slider ( bool enable) const
2707{
2708 bool render_as_disabled = !enable;
2709 if (m_moves_slider != nullptr && m_moves_slider->is_rendering_as_disabled() != render_as_disabled) {
2710 m_moves_slider->set_render_as_disabled(render_as_disabled);
2711 m_moves_slider->set_as_dirty();
2712 }
2713}

References m_moves_slider.

Referenced by update_sequential_view_current().

Here is the caller graph for this function:

◆ export_toolpaths_to_obj()

void Slic3r::GUI::GCodeViewer::export_toolpaths_to_obj ( const char * filename) const
3123{
3124 if (filename == nullptr)
3125 return;
3126
3127 if (!has_data())
3128 return;
3129
3130 wxBusyCursor busy;
3131 ToolpathsObjExporter exporter(m_viewer);
3132 exporter.export_to(filename);
3133}
bool has_data() const
Definition GCodeViewer.hpp:428

References Slic3r::GUI::ToolpathsObjExporter::export_to(), has_data(), and m_viewer.

Here is the call graph for this function:

◆ get_body_masses()

const std::vector< GCodeProcessorResult::ObjectMass > & Slic3r::GUI::GCodeViewer::get_body_masses ( ) const
inline
453{ return m_body_masses; }
std::vector< GCodeProcessorResult::ObjectMass > m_body_masses
Definition GCodeViewer.hpp:362

References m_body_masses.

Referenced by Slic3r::GUI::GLCanvas3D::CenterOfMass::render().

Here is the caller graph for this function:

◆ get_dim_previous_layers_brightness()

float Slic3r::GUI::GCodeViewer::get_dim_previous_layers_brightness ( ) const
inline
511{ return m_viewer.get_dim_previous_layers_brightness(); }

References m_viewer.

◆ get_extruders_count()

size_t Slic3r::GUI::GCodeViewer::get_extruders_count ( )
inline
529{ return m_extruders_count; }
size_t m_extruders_count
Definition GCodeViewer.hpp:329

References m_extruders_count.

◆ get_gcode_vertex_at()

const libvgcode::PathVertex & Slic3r::GUI::GCodeViewer::get_gcode_vertex_at ( size_t id) const
inline
473{ return m_viewer.get_vertex_at(id); }

References m_viewer.

Referenced by update_moves_slider().

Here is the caller graph for this function:

◆ get_gcode_view_enabled_range()

const libvgcode::Interval & Slic3r::GUI::GCodeViewer::get_gcode_view_enabled_range ( ) const
inline
471{ return m_viewer.get_view_enabled_range(); }

References m_viewer.

◆ get_gcode_view_full_range()

const libvgcode::Interval & Slic3r::GUI::GCodeViewer::get_gcode_view_full_range ( ) const
inline
470{ return m_viewer.get_view_full_range(); }

References m_viewer.

◆ get_gcode_view_visible_range()

const libvgcode::Interval & Slic3r::GUI::GCodeViewer::get_gcode_view_visible_range ( ) const
inline
472{ return m_viewer.get_view_visible_range(); }

References m_viewer.

◆ get_layers_count()

size_t Slic3r::GUI::GCodeViewer::get_layers_count ( ) const
inline
456{ return m_viewer.get_layers_count(); }

References m_viewer.

Referenced by Slic3r::GUI::anonymous_namespace{SceneBenchmark.cpp}::SceneBenchmarkDialog::report().

Here is the caller graph for this function:

◆ get_layers_slider()

IMSlider * Slic3r::GUI::GCodeViewer::get_layers_slider ( )
inline

◆ get_layers_times()

std::vector< float > Slic3r::GUI::GCodeViewer::get_layers_times ( ) const
inline
448{ return m_viewer.get_layers_estimated_times(); }

References m_viewer.

◆ get_layers_z_range()

const std::array< size_t, 2 > & Slic3r::GUI::GCodeViewer::get_layers_z_range ( ) const
inline
450{ return m_viewer.get_layers_view_range(); }

References m_viewer.

Referenced by Slic3r::GUI::GLCanvas3D::CenterOfMass::render().

Here is the caller graph for this function:

◆ get_layers_zs()

std::vector< double > Slic3r::GUI::GCodeViewer::get_layers_zs ( ) const
inline
438 {
439 // Belt printers: the layer Z the slider labels and the colour-change ticks
440 // use is the layer's print Z (see load_as_gcode), not a toolpath height.
441 if (! m_belt_layer_zs.empty())
442 return m_belt_layer_zs;
443 const std::vector<float> zs = m_viewer.get_layers_zs();
444 std::vector<double> ret;
445 std::transform(zs.begin(), zs.end(), std::back_inserter(ret), [](float z) { return static_cast<double>(z); });
446 return ret;
447 }
std::vector< double > m_belt_layer_zs
Definition GCodeViewer.hpp:213

References m_belt_layer_zs, and m_viewer.

◆ get_legend_height()

float Slic3r::GUI::GCodeViewer::get_legend_height ( )
inline
520{ return m_legend_height; }
float m_legend_height
Definition GCodeViewer.hpp:354

References m_legend_height.

◆ get_max_bounding_box()

const BoundingBoxf3 & Slic3r::GUI::GCodeViewer::get_max_bounding_box ( ) const
inline
436{ return m_max_bounding_box; }
BoundingBoxf3 m_max_bounding_box
Definition GCodeViewer.hpp:230

References m_max_bounding_box.

◆ get_max_print_height()

const float Slic3r::GUI::GCodeViewer::get_max_print_height ( ) const
inline
433{ return m_max_print_height; }
float m_max_print_height
Definition GCodeViewer.hpp:233

References m_max_print_height.

◆ get_moves_slider()

IMSlider * Slic3r::GUI::GCodeViewer::get_moves_slider ( )
inline
464{ return m_moves_slider; }

References m_moves_slider.

Referenced by Slic3r::GUI::anonymous_namespace{NativeCommands.cpp}::go_to_layer(), Slic3r::GUI::GLCanvas3D::handle_shortcut(), Slic3r::GUI::GLCanvas3D::on_change_color_mode(), and Slic3r::GUI::GLCanvas3D::on_mouse_wheel().

Here is the caller graph for this function:

◆ get_object_masses()

const std::vector< GCodeProcessorResult::ObjectMass > & Slic3r::GUI::GCodeViewer::get_object_masses ( ) const
inline
452{ return m_object_masses; }
std::vector< GCodeProcessorResult::ObjectMass > m_object_masses
Definition GCodeViewer.hpp:361

References m_object_masses.

Referenced by Slic3r::GUI::GLCanvas3D::CenterOfMass::render().

Here is the caller graph for this function:

◆ get_paths_bounding_box()

const BoundingBoxf3 & Slic3r::GUI::GCodeViewer::get_paths_bounding_box ( ) const
inline
435{ return m_paths_bounding_box; }
BoundingBoxf3 m_paths_bounding_box
Definition GCodeViewer.hpp:228

References m_paths_bounding_box.

◆ get_plate_mass()

const GCodeProcessorResult::ObjectMass & Slic3r::GUI::GCodeViewer::get_plate_mass ( ) const
inline
451{ return m_plate_mass; }
GCodeProcessorResult::ObjectMass m_plate_mass
Definition GCodeViewer.hpp:360

References m_plate_mass.

Referenced by Slic3r::GUI::GLCanvas3D::CenterOfMass::render().

Here is the caller graph for this function:

◆ get_plater_extruder()

std::vector< int > Slic3r::GUI::GCodeViewer::get_plater_extruder ( )
1349{
1350 return m_plater_extruder;
1351}
std::vector< int > m_plater_extruder
Definition GCodeViewer.hpp:207

References m_plater_extruder.

◆ get_sequential_view()

const SequentialView & Slic3r::GUI::GCodeViewer::get_sequential_view ( ) const
inline
460{ return m_sequential_view; }
SequentialView m_sequential_view
Definition GCodeViewer.hpp:332

References m_sequential_view.

◆ get_shell_bounding_box()

const BoundingBoxf3 & Slic3r::GUI::GCodeViewer::get_shell_bounding_box ( ) const
inline
437{ return m_shell_bounding_box; }
BoundingBoxf3 m_shell_bounding_box
Definition GCodeViewer.hpp:232

References m_shell_bounding_box.

◆ get_support_masses()

const std::vector< GCodeProcessorResult::ObjectMass > & Slic3r::GUI::GCodeViewer::get_support_masses ( ) const
inline
454{ return m_support_masses; }
std::vector< GCodeProcessorResult::ObjectMass > m_support_masses
Definition GCodeViewer.hpp:363

References m_support_masses.

Referenced by Slic3r::GUI::GLCanvas3D::CenterOfMass::render().

Here is the caller graph for this function:

◆ get_vertices_count()

size_t Slic3r::GUI::GCodeViewer::get_vertices_count ( ) const
inline
455{ return m_viewer.get_vertices_count(); }

References m_viewer.

Referenced by Slic3r::GUI::anonymous_namespace{SceneBenchmark.cpp}::SceneBenchmarkDialog::report().

Here is the caller graph for this function:

◆ get_view_type()

libvgcode::EViewType Slic3r::GUI::GCodeViewer::get_view_type ( ) const
inline
504{ return m_viewer.get_view_type(); }

References m_viewer.

◆ has_data()

bool Slic3r::GUI::GCodeViewer::has_data ( ) const
inline
428{ return !m_viewer.get_extrusion_roles().empty(); }

References m_viewer.

Referenced by export_toolpaths_to_obj(), Slic3r::GUI::anonymous_namespace{SceneBenchmark.cpp}::SceneBenchmarkDialog::on_timer(), render_shadow_casters(), and Slic3r::GUI::anonymous_namespace{SceneBenchmark.cpp}::SceneBenchmarkDialog::report().

Here is the caller graph for this function:

◆ init()

void Slic3r::GUI::GCodeViewer::init ( ConfigOptionMode mode,
Slic3r::PresetBundle * preset_bundle )
1161{
1163 return;
1164
1165 // initializes tool marker
1166 std::string filename;
1167 if (preset_bundle != nullptr) {
1168 const Preset* curr = &preset_bundle->printers.get_selected_preset();
1169 if (curr->is_system)
1171 else {
1172 auto *printer_model = curr->config.opt<ConfigOptionString>("printer_model");
1173 if (printer_model != nullptr && ! printer_model->value.empty()) {
1174 filename = preset_bundle->get_hotend_model_for_printer_model(printer_model->value);
1175 }
1176
1177 if (filename.empty()) {
1179 }
1180 }
1181 }
1182
1183 m_marker_filename = filename;
1184 m_sequential_view.marker.init(filename);
1185
1186 // initializes point sizes
1187 std::array<int, 2> point_sizes;
1188 ::glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_sizes.data());
1189 m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
1190
1191 // BBS initialzed view_type items
1192 m_user_mode = mode;
1194
1195 m_layers_slider->init_texture();
1196
1197 m_gl_data_initialized = true;
1198
1199 try
1200 {
1201 m_viewer.init(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
1202 glcheck();
1203 }
1204 catch (const std::exception& e)
1205 {
1206 MessageDialog msg_dlg(wxGetApp().plater(), e.what(), _L("Error"), wxICON_ERROR | wxOK);
1207 msg_dlg.ShowModal();
1208 }
1209
1210 // Orca:
1211 // Default view type at first slice.
1212 // May be overridden in load() once we know how many tools are actually used in the G-code.
1213 m_nozzle_nums = preset_bundle ? preset_bundle->get_printer_extruder_count() : 1;
1215
1216 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": finished");
1217}
#define _L(s)
Definition OBJ.cpp:34
#define glcheck()
Definition OpenGLUtils.hpp:26
ConfigOptionMode m_user_mode
Definition GCodeViewer.hpp:237
size_t m_nozzle_nums
Definition GCodeViewer.hpp:225
void apply_default_view_type()
Definition GCodeViewer.cpp:1278
bool m_gl_data_initialized
Definition GCodeViewer.hpp:208
std::string m_marker_filename
Definition GCodeViewer.hpp:239
std::array< float, 2 > m_detected_point_sizes
Definition GCodeViewer.hpp:356
void update_by_mode(ConfigOptionMode mode)
Definition GCodeViewer.cpp:1302
PrinterPresetCollection printers
Definition PresetBundle.hpp:503
static const char * ORCA_DEFAULT_PRINTER_MODEL
Definition PresetBundle.hpp:687
std::string get_hotend_model_for_printer_model(std::string model_name)
Definition PresetBundle.cpp:1360
int get_printer_extruder_count() const
Definition PresetBundle.cpp:5364
Preset & get_selected_preset()
Definition Preset.hpp:731
#define GL_VERSION
Definition gl.h:1987
#define GL_ALIASED_POINT_SIZE_RANGE
Definition gl.h:213
#define glGetIntegerv
Definition gl.h:3873
#define glGetString
Definition gl.h:3987
static Plater * plater()
Definition GUI_Factories.cpp:400
std::string system_printer_hotend_model(const Preset &preset)
Definition Preset.cpp:5119
@ Preset
Definition calib.hpp:39
zaa_minimize_perimeter_height ConfigOptionString
Definition PrintConfig.hpp:1702

References _L, apply_default_view_type(), Slic3r::Preset::config, Slic3r::PresetBundle::get_hotend_model_for_printer_model(), Slic3r::PresetBundle::get_printer_extruder_count(), Slic3r::PresetCollection::get_selected_preset(), GL_ALIASED_POINT_SIZE_RANGE, GL_VERSION, glcheck, glGetIntegerv, glGetString, Slic3r::Preset::is_system, m_detected_point_sizes, m_gl_data_initialized, m_layers_slider, m_marker_filename, m_nozzle_nums, m_sequential_view, m_user_mode, m_viewer, Slic3r::DynamicConfig::opt(), Slic3r::PresetBundle::ORCA_DEFAULT_PRINTER_MODEL, Slic3r::GUI::plater(), Slic3r::PresetBundle::printers, Slic3r::GUI::DPIAware< P >::ShowModal(), Slic3r::PresetUtils::system_printer_hotend_model(), and update_by_mode().

Here is the call graph for this function:

◆ invalidate_legend()

void Slic3r::GUI::GCodeViewer::invalidate_legend ( )
inline
533{ /*TODO: m_legend_resizer.reset();*/ }

◆ is_belt_show_designed()

bool Slic3r::GUI::GCodeViewer::is_belt_show_designed ( ) const
inline
527{ return m_belt_show_designed; }
bool m_belt_show_designed
Definition GCodeViewer.hpp:370

References m_belt_show_designed.

◆ is_belt_view()

bool Slic3r::GUI::GCodeViewer::is_belt_view ( ) const
inline
525{ return m_belt_view_enabled && m_belt_angle_deg > 0.f; }
float m_belt_angle_deg
Definition GCodeViewer.hpp:372
bool m_belt_view_enabled
Definition GCodeViewer.hpp:369

References m_belt_angle_deg, and m_belt_view_enabled.

◆ is_contained_in_bed()

bool Slic3r::GUI::GCodeViewer::is_contained_in_bed ( ) const
inline
475{ return m_contained_in_bed; }
bool m_contained_in_bed
Definition GCodeViewer.hpp:365

References m_contained_in_bed.

◆ is_dim_previous_layers()

bool Slic3r::GUI::GCodeViewer::is_dim_previous_layers ( ) const
inline
508{ return m_viewer.is_dim_previous_layers(); }

References m_viewer.

◆ is_legend_shown()

bool Slic3r::GUI::GCodeViewer::is_legend_shown ( ) const
inline
bool m_legend_visible
Definition GCodeViewer.hpp:351

References m_legend_enabled, and m_legend_visible.

Referenced by render_legend(), render_overlay(), and render_toolpaths().

Here is the caller graph for this function:

◆ is_machine_frame_transform_active()

bool Slic3r::GUI::GCodeViewer::is_machine_frame_transform_active ( ) const
inline
bool m_machine_frame_transform_active
Definition GCodeViewer.hpp:234

References m_machine_frame_transform_active.

◆ is_only_gcode_in_preview()

bool Slic3r::GUI::GCodeViewer::is_only_gcode_in_preview ( ) const
inline
477{ return m_only_gcode_in_preview; }
bool m_only_gcode_in_preview
Definition GCodeViewer.hpp:220

References m_only_gcode_in_preview.

◆ load_as_gcode()

void Slic3r::GUI::GCodeViewer::load_as_gcode ( const GCodeProcessorResult & gcode_result,
const Print & print,
const std::vector< std::string > & str_tool_colors,
const std::vector< std::string > & str_color_print_colors,
const BuildVolume & build_volume,
const std::vector< BoundingBoxf3 > & exclude_bounding_box,
ConfigOptionMode mode,
bool only_gcode = false )
1403{
1404 m_loaded_as_preview = false;
1405
1406 // Belt printers: drive the designed/raw view UI (legend checkbox, hotkey B, canvas-toolbar
1407 // menu item) from the G-code itself. Only BeltGCode writes the belt header, so its tilt
1408 // (gcode_result.belt_tilt_angle, abs of the slicing rotation) says whether this is belt
1409 // G-code; the selected printer does not, for a file opened from disk. The back-transform
1410 // below still reads print.config(), which Plater::load_gcode() fills from the file's own
1411 // config block (GCodeProcessor::export_config_for_render).
1412 m_belt_view_enabled = gcode_result.belt_tilt_angle > 0.f;
1413 m_belt_angle_deg = gcode_result.belt_tilt_angle;
1414
1415 // The tool position readout shows coordinates with the precision the G-code was exported with.
1416 // For a file opened from disk, print.config() holds the value from its config block as well.
1417 m_sequential_view.marker.set_high_precision_gcode(print.config().high_precision_gcode.value);
1418
1419 const bool current_top_layer_only = m_viewer.is_top_layer_only_view_range();
1420 const bool required_top_layer_only = get_app_config()->get_bool("seq_top_layer_only");
1421 if (current_top_layer_only != required_top_layer_only)
1422 m_viewer.toggle_top_layer_only_view_range();
1423
1424 // ORCA: darken the layers the preview layer slider is not scrubbed to
1425 m_viewer.set_dim_previous_layers(get_app_config()->get_bool("preview_dim_previous_layers"));
1426 m_viewer.set_dim_previous_layers_brightness(0.01f * std::stoi(get_app_config()->get("preview_dim_previous_layers_brightness")));
1427 m_viewer.set_translucent_filaments(get_app_config()->get_bool("preview_translucent_filaments"));
1428
1429 // avoid processing if called with the same gcode_result.
1430 // On a belt printer the toolpath geometry fed to libvgcode also depends on the
1431 // designed/raw view state (the back-transform is applied in convert), so the
1432 // same result is converted again only when that view has been toggled.
1433 const bool same_belt_view = !m_belt_view_enabled || m_last_belt_show_designed == m_belt_show_designed;
1434 if (m_last_result_id == gcode_result.id && wxGetApp().is_editor() && same_belt_view) {
1435 //BBS: add logs
1436 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": the same id %1%, return directly, result %2% ") % m_last_result_id % (&gcode_result);
1437
1438 m_viewer.set_tool_colors(libvgcode::convert_filament_colors(str_tool_colors));
1439 m_viewer.set_color_print_colors(libvgcode::convert_filament_colors(str_color_print_colors.empty() ? str_tool_colors : str_color_print_colors));
1440 return;
1441 }
1442
1443 //BBS: add logs
1444 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": gcode result %1%, new id %2%, gcode file %3% ") % (&gcode_result) % m_last_result_id % gcode_result.filename;
1445
1446 // release gpu memory, if used
1447 reset();
1448
1449 //BBS: add mutex for protection of gcode result
1450 wxGetApp().plater()->suppress_background_process(true);
1451 gcode_result.lock();
1452 //BBS: add safe check
1453 if (gcode_result.moves.size() == 0) {
1454 //result cleaned before slicing ,should return here
1455 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": gcode result reset before, return directly!");
1456 gcode_result.unlock();
1457 wxGetApp().plater()->schedule_background_process();
1458 return;
1459 }
1460 m_plate_mass = gcode_result.plate_mass;
1461 m_object_masses = gcode_result.object_masses;
1462 m_body_masses = gcode_result.body_masses;
1463 m_support_masses = gcode_result.support_masses;
1464
1465 // convert data from PrusaSlicer format to libvgcode format.
1466 // Belt printers: when the designed (upright) view is active, back-transform
1467 // the toolpath geometry into model/Cartesian space using the general belt
1468 // inverse (handles the mesh rotation, shear and axis remap). When off, the
1469 // raw machine-frame G-code is shown (useful for checking the transform itself).
1470 const bool is_belt = m_belt_view_enabled && print.config().belt_printer.value;
1471 Transform3d belt_inv = (is_belt && m_belt_show_designed)
1472 ? compute_belt_back_transform(print.config()) : Transform3d::Identity();
1473 // Belt: move positions are stored as gcode_Z + belt_z_origin (the start G-code's
1474 // purge-blob advance baked into the machine-Z origin by its G92 Z0 resets). Subtract
1475 // that constant before the linear back-transform so every toolpath maps to the model's
1476 // belt coordinate. Without it the back-transform mixes the offset with the gantry-Y
1477 // term, leaving a per-move designed-Y error that min-corner anchoring cannot remove
1478 // when a bridge/keel move happens to cancel it at the bbox minimum.
1479 if (is_belt && m_belt_show_designed && gcode_result.belt_z_origin != 0.0f)
1480 belt_inv = belt_inv * Transform3d(Eigen::Translation3d(Vec3d(0.0, 0.0, -double(gcode_result.belt_z_origin))));
1481 const bool apply_belt = is_belt && m_belt_show_designed
1482 && !belt_inv.matrix().isApprox(Transform3d::Identity().matrix());
1483 if (apply_belt) {
1484 // The linear belt back-transform recovers the print's shape and orientation but not
1485 // the per-object placement/lift translation: the object's position on the belt, the
1486 // BeltSliceStrategy min-Z lift, and the centering pre-translate are applied OUTSIDE
1487 // build_forward_transform() (see PrintObjectSlice.cpp), so its linear inverse leaves
1488 // them un-undone. Uncorrected, the upright toolpaths float a fixed offset from the
1489 // model shell. Recover the translation generally — independent of the offset's exact
1490 // source or the axis remap — by anchoring the back-transformed object body onto the
1491 // upright model bounding box (the same space the shells render in).
1492 BoundingBoxf3 model_bb;
1493 for (const PrintObject* po : print.objects())
1494 for (const ModelInstance* mi : po->model_object()->instances)
1495 model_bb.merge(po->model_object()->instance_bounding_box(*mi));
1496 // Build the anchor bbox from surface toolpaths only. After the belt_z_origin
1497 // correction the surface back-transforms onto the model, but a few elevated
1498 // features (bridges/overhangs over the chevron gap) are mis-mapped by the linear
1499 // inverse to well outside the model body; if one becomes the bbox minimum it
1500 // drags the min-corner anchor by ~20mm. Drop moves that land clearly outside the
1501 // (correct) model bbox — a geometric filter, not a role guess.
1502 // Tolerance around the model bbox for outlier rejection, and the minimum fraction
1503 // of MOVES (by count) the clip must retain before we trust it over the full bbox.
1504 // Count, not bbox extent: a single far-flung outlier move (e.g. a belt-entry purge
1505 // that maps to y~0) inflates the full bbox so much that a size-fraction test would
1506 // wrongly reject the clip and re-include the outlier, dragging the min-corner anchor
1507 // by ~the offset. By count the clip keeps ~100% of moves here and ~0% only when the
1508 // object is genuinely offset from the belt entry (the real fall-back-to-full case).
1509 constexpr double ANCHOR_CLIP_MARGIN_MM = 10.0;
1510 constexpr double ANCHOR_CLIP_MIN_KEEP = 0.5;
1511 BoundingBoxf3 tp_bb_clip, tp_bb_full;
1512 size_t n_filtered = 0, n_clip = 0;
1513 const double y_lo = model_bb.defined ? model_bb.min.y() - ANCHOR_CLIP_MARGIN_MM : -1e30;
1514 const double y_hi = model_bb.defined ? model_bb.max.y() + ANCHOR_CLIP_MARGIN_MM : 1e30;
1515 // The anchor aligns the toolpath body onto the object-only model bbox, so it must be
1516 // built from OBJECT-body toolpaths only. Support, skirt, brim and wipe-tower extrusions
1517 // are not part of the model mesh and extend past it (support especially reaches well
1518 // beyond the object on a belt), so including them drags tp_bb.min and shifts the whole
1519 // back-transformed g-code off the mesh — but only when those features are present. That
1520 // is the "g-code shifts vs mesh as soon as supports are enabled" bug. Filter them out.
1521 auto is_object_body = [](ExtrusionRole r) {
1523 && r != erSupportTransition
1524 && r != erSkirt && r != erBrim && r != erWipeTower;
1525 };
1526 auto accumulate = [&](bool body_only) {
1527 tp_bb_clip = BoundingBoxf3();
1528 tp_bb_full = BoundingBoxf3();
1529 n_filtered = 0;
1530 n_clip = 0;
1531 for (const GCodeProcessorResult::MoveVertex& mv : gcode_result.moves)
1532 if (mv.type == EMoveType::Extrude && mv.layer_id >= 1 // skip layer-0 prime/skirt
1533 && (!body_only || is_object_body(mv.extrusion_role))) {
1534 ++n_filtered;
1535 const Vec3d p = belt_inv * mv.position.cast<double>();
1536 tp_bb_full.merge(p);
1537 if (p.y() >= y_lo && p.y() <= y_hi) {
1538 tp_bb_clip.merge(p);
1539 ++n_clip;
1540 }
1541 }
1542 };
1543 accumulate(/*body_only=*/true);
1544 // Fallback: a plate with no object-body extrusions above layer 0 (e.g. a
1545 // support-only object) would leave tp_bb undefined and silently skip the
1546 // anchor. Re-accumulate over ALL extrude moves so the min-corner anchor is
1547 // still computed rather than letting the preview float by the placement offset.
1548 if (n_filtered == 0)
1549 accumulate(/*body_only=*/false);
1550 // Use the clipped bbox when it still holds the bulk of the moves (outliers removed).
1551 // If the object sits far from the belt entry the toolpaths are grossly offset and the
1552 // clip drops most of them — fall back to the full bbox so the min-corner anchor still
1553 // recovers that gross translation rather than breaking.
1554 const BoundingBoxf3& tp_bb =
1555 (tp_bb_clip.defined && n_filtered > 0 &&
1556 double(n_clip) >= ANCHOR_CLIP_MIN_KEEP * double(n_filtered)) ? tp_bb_clip : tp_bb_full;
1557 if (model_bb.defined && tp_bb.defined) {
1558 // Anchor the back-transformed toolpath body onto the upright model bbox by
1559 // its MIN corner. (Center anchoring was tried and regressed when the toolpath
1560 // and model bounding boxes differ in extent.) With the belt_z_origin
1561 // correction above and the outlier-robust bbox below, the surface overlaps the
1562 // shell to well under a millimetre when the object is at the belt entry; an
1563 // object placed elsewhere in global-rotation mode still carries the placement
1564 // translation, which this min-corner step recovers.
1565 const Vec3d d = model_bb.min - tp_bb.min;
1566 belt_inv = Transform3d(Eigen::Translation3d(d)) * belt_inv;
1567 }
1568 }
1569 libvgcode::GCodeInputData data = libvgcode::convert(gcode_result, str_tool_colors, str_color_print_colors, m_viewer,
1570 apply_belt ? &belt_inv : nullptr);
1571
1572//#define ENABLE_DATA_EXPORT 1
1573//#if ENABLE_DATA_EXPORT
1574// auto extrusion_role_to_string = [](libvgcode::EGCodeExtrusionRole role) {
1575// switch (role) {
1576// case libvgcode::EGCodeExtrusionRole::None: { return "EGCodeExtrusionRole::None"; }
1577// case libvgcode::EGCodeExtrusionRole::Perimeter: { return "EGCodeExtrusionRole::Perimeter"; }
1578// case libvgcode::EGCodeExtrusionRole::ExternalPerimeter: { return "EGCodeExtrusionRole::ExternalPerimeter"; }
1579// case libvgcode::EGCodeExtrusionRole::OverhangPerimeter: { return "EGCodeExtrusionRole::OverhangPerimeter"; }
1580// case libvgcode::EGCodeExtrusionRole::InternalInfill: { return "EGCodeExtrusionRole::InternalInfill"; }
1581// case libvgcode::EGCodeExtrusionRole::SolidInfill: { return "EGCodeExtrusionRole::SolidInfill"; }
1582// case libvgcode::EGCodeExtrusionRole::TopSolidInfill: { return "EGCodeExtrusionRole::TopSolidInfill"; }
1583// case libvgcode::EGCodeExtrusionRole::Ironing: { return "EGCodeExtrusionRole::Ironing"; }
1584// case libvgcode::EGCodeExtrusionRole::BridgeInfill: { return "EGCodeExtrusionRole::BridgeInfill"; }
1585// case libvgcode::EGCodeExtrusionRole::GapFill: { return "EGCodeExtrusionRole::GapFill"; }
1586// case libvgcode::EGCodeExtrusionRole::Skirt: { return "EGCodeExtrusionRole::Skirt"; }
1587// case libvgcode::EGCodeExtrusionRole::SupportMaterial: { return "EGCodeExtrusionRole::SupportMaterial"; }
1588// case libvgcode::EGCodeExtrusionRole::SupportMaterialInterface: { return "EGCodeExtrusionRole::SupportMaterialInterface"; }
1589// case libvgcode::EGCodeExtrusionRole::WipeTower: { return "EGCodeExtrusionRole::WipeTower"; }
1590// case libvgcode::EGCodeExtrusionRole::Custom: { return "EGCodeExtrusionRole::Custom"; }
1591// case libvgcode::EGCodeExtrusionRole::COUNT: { return "EGCodeExtrusionRole::COUNT"; }
1592// }
1593// };
1594//
1595// auto move_type_to_string = [](libvgcode::EMoveType type) {
1596// switch (type) {
1597// case libvgcode::EMoveType::Noop: { return "EMoveType::Noop"; }
1598// case libvgcode::EMoveType::Retract: { return "EMoveType::Retract"; }
1599// case libvgcode::EMoveType::Unretract: { return "EMoveType::Unretract"; }
1600// case libvgcode::EMoveType::Seam: { return "EMoveType::Seam"; }
1601// case libvgcode::EMoveType::ToolChange: { return "EMoveType::ToolChange"; }
1602// case libvgcode::EMoveType::ColorChange: { return "EMoveType::ColorChange"; }
1603// case libvgcode::EMoveType::PausePrint: { return "EMoveType::PausePrint"; }
1604// case libvgcode::EMoveType::CustomGCode: { return "EMoveType::CustomGCode"; }
1605// case libvgcode::EMoveType::Travel: { return "EMoveType::Travel"; }
1606// case libvgcode::EMoveType::Wipe: { return "EMoveType::Wipe"; }
1607// case libvgcode::EMoveType::Extrude: { return "EMoveType::Extrude"; }
1608// case libvgcode::EMoveType::COUNT: { return "EMoveType::COUNT"; }
1609// }
1610// };
1611//
1612// FilePtr out{ boost::nowide::fopen("C:/prusa/slicer/test_output/spe1872/test.data", "wb") };
1613// if (out.f != nullptr) {
1614// const uint32_t vertices_count = static_cast<uint32_t>(data.vertices.size());
1615// fwrite((void*)&vertices_count, 1, sizeof(uint32_t), out.f);
1616// for (const libvgcode::PathVertex& v : data.vertices) {
1617// fwrite((void*)&v.position[0], 1, sizeof(float), out.f);
1618// fwrite((void*)&v.position[1], 1, sizeof(float), out.f);
1619// fwrite((void*)&v.position[2], 1, sizeof(float), out.f);
1620// fwrite((void*)&v.height, 1, sizeof(float), out.f);
1621// fwrite((void*)&v.width, 1, sizeof(float), out.f);
1622// fwrite((void*)&v.feedrate, 1, sizeof(float), out.f);
1623// fwrite((void*)&v.actual_feedrate, 1, sizeof(float), out.f);
1624// fwrite((void*)&v.mm3_per_mm, 1, sizeof(float), out.f);
1625// fwrite((void*)&v.fan_speed, 1, sizeof(float), out.f);
1626// fwrite((void*)&v.temperature, 1, sizeof(float), out.f);
1627// fwrite((void*)&v.role, 1, sizeof(uint8_t), out.f);
1628// fwrite((void*)&v.type, 1, sizeof(uint8_t), out.f);
1629// fwrite((void*)&v.gcode_id, 1, sizeof(uint32_t), out.f);
1630// fwrite((void*)&v.layer_id, 1, sizeof(uint32_t), out.f);
1631// fwrite((void*)&v.extruder_id, 1, sizeof(uint32_t), out.f);
1632// fwrite((void*)&v.color_id, 1, sizeof(uint32_t), out.f);
1633// fwrite((void*)&v.times[0], 1, sizeof(float), out.f);
1634// fwrite((void*)&v.times[1], 1, sizeof(float), out.f);
1635//#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
1636// const float weight = v.weight;
1637//#else
1638// const float weight = 0.0f;
1639//#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
1640// fwrite((void*)&weight, 1, sizeof(float), out.f);
1641// }
1642//
1643// const uint8_t spiral_vase_mode = data.spiral_vase_mode ? 1 : 0;
1644// fwrite((void*)&spiral_vase_mode, 1, sizeof(uint8_t), out.f);
1645//
1646// const uint32_t tool_colors_count = static_cast<uint32_t>(data.tools_colors.size());
1647// fwrite((void*)&tool_colors_count, 1, sizeof(uint32_t), out.f);
1648// for (const libvgcode::Color& c : data.tools_colors) {
1649// fwrite((void*)&c[0], 1, sizeof(uint8_t), out.f);
1650// fwrite((void*)&c[1], 1, sizeof(uint8_t), out.f);
1651// fwrite((void*)&c[2], 1, sizeof(uint8_t), out.f);
1652// }
1653//
1654// const uint32_t color_print_colors_count = static_cast<uint32_t>(data.color_print_colors.size());
1655// fwrite((void*)&color_print_colors_count, 1, sizeof(uint32_t), out.f);
1656// for (const libvgcode::Color& c : data.color_print_colors) {
1657// fwrite((void*)&c[0], 1, sizeof(uint8_t), out.f);
1658// fwrite((void*)&c[1], 1, sizeof(uint8_t), out.f);
1659// fwrite((void*)&c[2], 1, sizeof(uint8_t), out.f);
1660// }
1661// }
1662//#endif // ENABLE_DATA_EXPORT
1663
1664 // send data to the viewer
1665 m_viewer.reset_default_extrusion_roles_colors();
1666 m_viewer.load(std::move(data));
1667
1668 // Belt printers: libvgcode labels a layer with the height of its toolpaths, which
1669 // on a tilted layer is wherever its last extrusion happened to end, and the layer
1670 // slider looks its labels and the colour-change ticks up in that list assuming it
1671 // increases. Give it the layers' print Z instead (the slicer's layer Z, which
1672 // increases along the belt), numbered the way libvgcode::convert() numbers the
1673 // layers: consecutively over the moves that exist.
1674 m_belt_layer_zs.clear();
1675 if (is_belt) {
1676 unsigned int src_layer_id = std::numeric_limits<unsigned int>::max();
1677 for (size_t i = 1; i < gcode_result.moves.size(); ++ i) {
1678 const GCodeProcessorResult::MoveVertex &mv = gcode_result.moves[i];
1679 if (mv.layer_id != src_layer_id) {
1680 src_layer_id = mv.layer_id;
1681 m_belt_layer_zs.emplace_back(double(mv.print_z));
1682 }
1683 }
1684 if (m_belt_layer_zs.size() != m_viewer.get_layers_count())
1685 m_belt_layer_zs.clear();
1686 }
1687
1688// #if !VGCODE_ENABLE_COG_AND_TOOL_MARKERS
1689// const size_t vertices_count = m_viewer.get_vertices_count();
1690// m_cog.reset();
1691// for (size_t i = 1; i < vertices_count; ++i) {
1692// const libvgcode::PathVertex& curr = m_viewer.get_vertex_at(i);
1693// if (curr.type == libvgcode::EMoveType::Extrude &&
1694// curr.role != libvgcode::EGCodeExtrusionRole::Skirt &&
1695// curr.role != libvgcode::EGCodeExtrusionRole::SupportMaterial &&
1696// curr.role != libvgcode::EGCodeExtrusionRole::SupportMaterialInterface &&
1697// curr.role != libvgcode::EGCodeExtrusionRole::WipeTower &&
1698// curr.role != libvgcode::EGCodeExtrusionRole::Custom) {
1699// const Vec3d curr_pos = libvgcode::convert(curr.position).cast<double>();
1700// const Vec3d prev_pos = libvgcode::convert(m_viewer.get_vertex_at(i - 1).position).cast<double>();
1701// m_cog.add_segment(curr_pos, prev_pos, gcode_result.filament_densities[curr.extruder_id] * curr.mm3_per_mm * (curr_pos - prev_pos).norm());
1702// }
1703// }
1704// #endif // !VGCODE_ENABLE_COG_AND_TOOL_MARKERS
1705
1706 const libvgcode::AABox bbox = wxGetApp().is_gcode_viewer() ?
1707 m_viewer.get_bounding_box() :
1708 m_viewer.get_extrusion_bounding_box({
1714 // ORCA
1717 });
1720
1721 if (wxGetApp().is_editor()) {
1722 if (is_belt) {
1723 // The moves are machine-frame coordinates (Z is belt travel), so the per-move
1724 // test inside all_paths_inside() can never pass on a belt. Judge the
1725 // back-transformed box instead, with room for the designed view's min-corner
1726 // anchor, which is only accurate to a fraction of a millimetre.
1727 BoundingBoxf3 bed = wxGetApp().plater()->build_volume().bounding_volume();
1728 bed.offset(1.);
1729 m_contained_in_bed = !m_paths_bounding_box.defined || (bed.contains(m_paths_bounding_box.min) && bed.contains(m_paths_bounding_box.max));
1730 } else
1731 m_contained_in_bed = wxGetApp().plater()->build_volume().all_paths_inside(gcode_result, m_paths_bounding_box);
1732 }
1733
1734 m_extruders_count = gcode_result.filaments_count;
1735
1736 //BBS: move the id to the end of reset
1737 m_last_result_id = gcode_result.id;
1739 m_gcode_result = &gcode_result;
1740 m_move_type_counts.fill(0);
1741 for (auto& move_type_times : m_move_type_times)
1742 move_type_times.fill(0.0f);
1743 m_move_type_distances.fill(0.0f);
1744 for (const GCodeProcessorResult::MoveVertex& move : gcode_result.moves) {
1745 if (move.internal_only)
1746 continue;
1747
1748 const size_t move_type = static_cast<size_t>(move.type);
1749 if (move_type < m_move_type_counts.size()) {
1750 ++m_move_type_counts[move_type];
1751 for (size_t mode = 0; mode < move.time.size(); ++mode)
1752 m_move_type_times[move_type][mode] += move.time[mode];
1753 if (move.type == EMoveType::Retract || move.type == EMoveType::Unretract)
1754 m_move_type_distances[move_type] += std::fabs(move.delta_extruder);
1755 else
1756 m_move_type_distances[move_type] += move.travel_dist;
1757 }
1758 }
1759 m_only_gcode_in_preview = only_gcode;
1760
1761 m_sequential_view.gcode_window.load_gcode(gcode_result.filename, gcode_result.lines_ends);
1762
1763 //BBS: add only gcode mode
1764 //if (wxGetApp().is_gcode_viewer())
1766 m_custom_gcode_per_print_z = gcode_result.custom_gcode_per_print_z;
1767
1768 m_max_print_height = gcode_result.printable_height;
1769 m_machine_frame_transform_active = gcode_result.machine_frame_transform_active;
1770 m_z_offset = gcode_result.z_offset;
1771
1772
1773 // load_toolpaths(gcode_result, build_volume, exclude_bounding_box);
1774
1775 // ORCA: Apply the default view type now that we know how many tools the G-code actually uses.
1777
1778 // BBS: data for rendering color arrangement recommendation
1779 m_nozzle_nums = print.config().option<ConfigOptionFloats>("nozzle_diameter")->values.size();
1780 // Orca hack: Hide filament group for non-bbl printers
1781 if (!print.is_BBL_printer()) m_nozzle_nums = 1;
1782 std::vector<int> filament_maps = print.get_filament_maps();
1783 std::vector<std::string> color_opt = print.config().option<ConfigOptionStrings>("filament_colour")->values;
1784 std::vector<std::string> type_opt = print.config().option<ConfigOptionStrings>("filament_type")->values;
1785 std::vector<unsigned char> support_filament_opt = print.config().option<ConfigOptionBools>("filament_is_support")->values;
1786 for (auto extruder_id : m_viewer.get_used_extruders_ids()) {
1787 if (filament_maps[extruder_id] == 1) {
1788 m_left_extruder_filament.push_back({type_opt[extruder_id], color_opt[extruder_id], extruder_id, (bool)(support_filament_opt[extruder_id])});
1789 } else {
1790 m_right_extruder_filament.push_back({type_opt[extruder_id], color_opt[extruder_id], extruder_id, (bool)(support_filament_opt[extruder_id])});
1791 }
1792 }
1793
1794 m_settings_ids = gcode_result.settings_ids;
1795 m_filament_diameters = gcode_result.filament_diameters;
1796 m_filament_densities = gcode_result.filament_densities;
1797 m_sequential_view.m_show_marker = false;
1798
1799 //BBS: always load shell at preview
1800 /*if (wxGetApp().is_editor())
1801 {
1802 load_shells(print);
1803 }
1804 else {*/
1805 //BBS: add only gcode mode
1806 // When the file's own settings were loaded into the presets, the bed already is the file's, with the
1807 // model and texture of a user or custom printer too, which the lookup below cannot resolve.
1808 if (m_only_gcode_in_preview && !wxGetApp().plater()->gcode_settings_loaded()) {
1810 //BBS: add bed exclude area
1811 Pointfs bed_exclude_area = Pointfs();
1812 Pointfs wrapping_exclude_area = Pointfs();
1813 std::vector<Pointfs> extruder_areas;
1814 std::vector<double> extruder_heights;
1815 std::string texture;
1816 std::string model;
1817
1818 if (!gcode_result.printable_area.empty()) {
1819 // bed shape detected in the gcode
1820 printable_area = gcode_result.printable_area;
1821 const auto bundle = wxGetApp().preset_bundle;
1822 if (bundle != nullptr && !m_settings_ids.printer.empty()) {
1823 const Preset* preset = bundle->printers.find_preset(m_settings_ids.printer);
1824 if (preset != nullptr) {
1826 texture = PresetUtils::system_printer_bed_texture(*preset);
1827 }
1828 }
1829
1830 //BBS: add bed exclude area
1831 if (!gcode_result.bed_exclude_area.empty())
1832 bed_exclude_area = gcode_result.bed_exclude_area;
1833
1834 if (!gcode_result.wrapping_exclude_area.empty())
1835 wrapping_exclude_area = gcode_result.wrapping_exclude_area;
1836
1837 if (!gcode_result.extruder_areas.empty())
1838 extruder_areas = gcode_result.extruder_areas;
1839 if (!gcode_result.extruder_heights.empty())
1840 extruder_heights = gcode_result.extruder_heights;
1841
1842 wxGetApp().plater()->set_bed_shape(printable_area, bed_exclude_area, wrapping_exclude_area, gcode_result.printable_height, extruder_areas, extruder_heights, texture, model, gcode_result.printable_area.empty());
1843 }
1844 /*else {
1845 // adjust printbed size in dependence of toolpaths bbox
1846 const double margin = 10.0;
1847 const Vec2d min(m_paths_bounding_box.min.x() - margin, m_paths_bounding_box.min.y() - margin);
1848 const Vec2d max(m_paths_bounding_box.max.x() + margin, m_paths_bounding_box.max.y() + margin);
1849
1850 const Vec2d size = max - min;
1851 printable_area = {
1852 { min.x(), min.y() },
1853 { max.x(), min.y() },
1854 { max.x(), min.y() + 0.442265 * size.y()},
1855 { max.x() - 10.0, min.y() + 0.4711325 * size.y()},
1856 { max.x() + 10.0, min.y() + 0.5288675 * size.y()},
1857 { max.x(), min.y() + 0.557735 * size.y()},
1858 { max.x(), max.y() },
1859 { min.x() + 0.557735 * size.x(), max.y()},
1860 { min.x() + 0.5288675 * size.x(), max.y() - 10.0},
1861 { min.x() + 0.4711325 * size.x(), max.y() + 10.0},
1862 { min.x() + 0.442265 * size.x(), max.y()},
1863 { min.x(), max.y() } };
1864 }*/
1865 }
1866
1867 m_print_statistics = gcode_result.print_statistics;
1868
1869 PrintEstimatedStatistics::ETimeMode time_mode = convert(m_viewer.get_time_mode());
1870 if (m_viewer.get_time_mode() != libvgcode::ETimeMode::Normal) {
1871 const float time = m_print_statistics.modes[static_cast<size_t>(time_mode)].time;
1872 if (time == 0.0f ||
1875 }
1876
1877 bool only_gcode_3mf = false;
1878 PartPlate* current_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate();
1879 bool current_has_print_instances = current_plate->has_printable_instances();
1880 if (current_plate->is_slice_result_valid() && wxGetApp().model().objects.empty() && !current_has_print_instances)
1881 only_gcode_3mf = true;
1882 m_layers_slider->set_menu_enable(!(only_gcode || only_gcode_3mf));
1883 m_layers_slider->set_as_dirty();
1884 m_moves_slider->set_as_dirty();
1885
1886 //BBS
1887 m_conflict_result = gcode_result.conflict_result;
1888 if (m_conflict_result) { m_conflict_result.value().layer = m_viewer.get_layer_id_at(static_cast<float>(m_conflict_result.value()._height)); }
1889
1890 m_gcode_check_result = gcode_result.gcode_check_result;
1891
1892 filament_printable_reuslt = gcode_result.filament_printable_reuslt;
1893 //BBS: add mutex for protection of gcode result
1894 gcode_result.unlock();
1895 wxGetApp().plater()->schedule_background_process();
1896}
bool get_bool(const std::string &section, const std::string &key) const
Definition AppConfig.hpp:163
size_t size() const override
Definition Config.hpp:722
std::vector< ExtruderFilament > m_left_extruder_filament
Definition GCodeViewer.hpp:223
GCodeCheckResult m_gcode_check_result
Definition GCodeViewer.hpp:202
std::vector< ExtruderFilament > m_right_extruder_filament
Definition GCodeViewer.hpp:224
std::array< float, static_cast< size_t >(EMoveType::Count)> m_move_type_distances
Definition GCodeViewer.hpp:218
PrintEstimatedStatistics m_print_statistics
Definition GCodeViewer.hpp:355
const GCodeProcessorResult * m_gcode_result
Definition GCodeViewer.hpp:215
GCodeProcessorResult::SettingsIds m_settings_ids
Definition GCodeViewer.hpp:357
std::vector< CustomGCode::Item > m_custom_gcode_per_print_z
Definition GCodeViewer.hpp:359
bool m_last_belt_show_designed
Definition GCodeViewer.hpp:211
FilamentPrintableResult filament_printable_reuslt
Definition GCodeViewer.hpp:203
std::vector< float > m_filament_densities
Definition GCodeViewer.hpp:331
float m_z_offset
Definition GCodeViewer.hpp:235
unsigned int m_last_result_id
Definition GCodeViewer.hpp:209
std::vector< float > m_filament_diameters
Definition GCodeViewer.hpp:330
bool m_loaded_as_preview
Definition GCodeViewer.hpp:377
ConflictResultOpt m_conflict_result
Definition GCodeViewer.hpp:201
std::array< unsigned int, static_cast< size_t >(EMoveType::Count)> m_move_type_counts
Definition GCodeViewer.hpp:216
std::array< std::array< float, static_cast< size_t >(PrintEstimatedStatistics::ETimeMode::Count)>, static_cast< size_t >(EMoveType::Count)> m_move_type_times
Definition GCodeViewer.hpp:217
static Transform3d compute_belt_back_transform(const PrintConfig &cfg)
Definition GCodeViewer.cpp:1361
AppConfig * get_app_config()
Definition GUI.cpp:539
std::string system_printer_bed_model(const Preset &preset)
Definition Preset.cpp:5095
std::string system_printer_bed_texture(const Preset &preset)
Definition Preset.cpp:5107
T accumulate(const EP &ep, I from, I to, const T &init, AccessFn &&accessfn, size_t granularity=1)
Definition Execution.hpp:99
zaa_minimize_perimeter_height printable_area((ConfigOptionPointsGroups, extruder_printable_area))((ConfigOptionBool
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
std::string short_time(const std::string &time)
Definition Utils.hpp:563
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:96
std::vector< Vec2d > Pointfs
Definition Point.hpp:77
ExtrusionRole
Definition ExtrusionEntity.hpp:26
@ erSupportMaterialInterface
Definition ExtrusionEntity.hpp:42
@ erSupportMaterial
Definition ExtrusionEntity.hpp:41
@ erWipeTower
Definition ExtrusionEntity.hpp:44
@ erBrim
Definition ExtrusionEntity.hpp:40
@ erSkirt
Definition ExtrusionEntity.hpp:39
@ erSupportTransition
Definition ExtrusionEntity.hpp:43
@ Retract
Definition GCodeProcessor.hpp:55
@ Unretract
Definition GCodeProcessor.hpp:56
@ Extrude
Definition GCodeProcessor.hpp:64
ConfigOptionBoolsTempl< false > ConfigOptionBools
Definition Config.hpp:2066
std::string get_time_dhms(float time_in_secs)
Definition Utils.hpp:609
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299
ConfigOptionFloatsTempl< false > ConfigOptionFloats
Definition Config.hpp:1015
id get(id object, const void *key)
Definition MacIME.mm:22
@ SolidInfill
Definition Types.hpp:150
@ InternalInfill
Definition Types.hpp:149
@ ExternalPerimeter
Definition Types.hpp:147
@ Brim
Definition Types.hpp:163
@ SupportTransition
Definition Types.hpp:164
@ SupportMaterialInterface
Definition Types.hpp:157
@ InternalBridgeInfill
Definition Types.hpp:162
@ Mixed
Definition Types.hpp:165
@ GapFill
Definition Types.hpp:154
@ TopSolidInfill
Definition Types.hpp:151
@ Perimeter
Definition Types.hpp:146
@ OverhangPerimeter
Definition Types.hpp:148
@ BridgeInfill
Definition Types.hpp:153
@ WipeTower
Definition Types.hpp:158
@ Skirt
Definition Types.hpp:155
@ Ironing
Definition Types.hpp:152
@ BottomSurface
Definition Types.hpp:161
@ SupportMaterial
Definition Types.hpp:156
PaletteWithAlpha convert_filament_colors(const std::vector< std::string > &colors_str)
Definition LibVGCodeWrapper.cpp:83
@ Normal
Definition Types.hpp:201
std::array< Vec3, 2 > AABox
Definition Types.hpp:78
Vec3 convert(const Slic3r::Vec3f &v)
Definition LibVGCodeWrapper.cpp:45
ETimeMode
Definition GCodeProcessor.hpp:88
@ Normal
Definition GCodeProcessor.hpp:89

References apply_default_view_type(), Slic3r::GCodeProcessorResult::bed_exclude_area, Slic3r::GCodeProcessorResult::belt_tilt_angle, Slic3r::GCodeProcessorResult::belt_z_origin, Slic3r::GCodeProcessorResult::body_masses, libvgcode::BottomSurface, libvgcode::BridgeInfill, libvgcode::Brim, Slic3r::cast(), Slic3r::GUI::compute_belt_back_transform(), Slic3r::Print::config(), Slic3r::GCodeProcessorResult::conflict_result, Slic3r::BoundingBox3Base< PointType >::contains(), libvgcode::convert(), libvgcode::convert_filament_colors(), Slic3r::GCodeProcessorResult::custom_gcode_per_print_z, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::defined, Slic3r::GCodeProcessorResult::MoveVertex::delta_extruder, Slic3r::erBrim, Slic3r::erSkirt, Slic3r::erSupportMaterial, Slic3r::erSupportMaterialInterface, Slic3r::erSupportTransition, Slic3r::erWipeTower, libvgcode::ExternalPerimeter, Slic3r::Extrude, Slic3r::GCodeProcessorResult::extruder_areas, Slic3r::GCodeProcessorResult::extruder_heights, Slic3r::GCodeProcessorResult::MoveVertex::extrusion_role, Slic3r::GCodeProcessorResult::filament_densities, Slic3r::GCodeProcessorResult::filament_diameters, Slic3r::GCodeProcessorResult::filament_printable_reuslt, filament_printable_reuslt, Slic3r::GCodeProcessorResult::filaments_count, Slic3r::GCodeProcessorResult::filename, libvgcode::GapFill, Slic3r::GCodeProcessorResult::gcode_check_result, Slic3r::GUI::get_app_config(), Slic3r::AppConfig::get_bool(), Slic3r::Print::get_filament_maps(), Slic3r::get_time_dhms(), Slic3r::GUI::PartPlate::has_printable_instances(), Slic3r::GCodeProcessorResult::id, Slic3r::GCodeProcessorResult::MoveVertex::internal_only, libvgcode::InternalBridgeInfill, libvgcode::InternalInfill, libvgcode::Ironing, Slic3r::Print::is_BBL_printer(), Slic3r::GUI::PartPlate::is_slice_result_valid(), Slic3r::GCodeProcessorResult::MoveVertex::layer_id, Slic3r::GCodeProcessorResult::lines_ends, Slic3r::GCodeProcessorResult::lock(), m_belt_angle_deg, m_belt_layer_zs, m_belt_show_designed, m_belt_view_enabled, m_body_masses, m_conflict_result, m_contained_in_bed, m_custom_gcode_per_print_z, m_extruders_count, m_filament_densities, m_filament_diameters, m_gcode_check_result, m_gcode_result, m_last_belt_show_designed, m_last_result_id, m_layers_slider, m_left_extruder_filament, m_loaded_as_preview, m_machine_frame_transform_active, m_max_bounding_box, m_max_print_height, m_move_type_counts, m_move_type_distances, m_move_type_times, m_moves_slider, m_nozzle_nums, m_object_masses, m_only_gcode_in_preview, m_paths_bounding_box, m_plate_mass, m_print_statistics, m_right_extruder_filament, m_sequential_view, m_settings_ids, m_support_masses, m_viewer, m_z_offset, Slic3r::GCodeProcessorResult::machine_frame_transform_active, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max, Slic3r::BoundingBox3Base< PointType >::merge(), Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min, libvgcode::Mixed, Slic3r::GCodeProcessorResult::moves, libvgcode::Normal, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::GCodeProcessorResult::object_masses, Slic3r::Print::objects(), Slic3r::BoundingBox3Base< PointType >::offset(), libvgcode::OverhangPerimeter, libvgcode::Perimeter, Slic3r::GCodeProcessorResult::plate_mass, Slic3r::GUI::plater(), Slic3r::GCodeProcessorResult::MoveVertex::position, Slic3r::GCodeProcessorResult::print_statistics, Slic3r::GCodeProcessorResult::MoveVertex::print_z, Slic3r::GCodeProcessorResult::printable_area, Slic3r::printable_area(), Slic3r::GCodeProcessorResult::printable_height, reset(), Slic3r::Retract, Slic3r::GCodeProcessorResult::settings_ids, Slic3r::short_time(), libvgcode::Skirt, libvgcode::SolidInfill, Slic3r::GCodeProcessorResult::support_masses, libvgcode::SupportMaterial, libvgcode::SupportMaterialInterface, libvgcode::SupportTransition, Slic3r::PresetUtils::system_printer_bed_model(), Slic3r::PresetUtils::system_printer_bed_texture(), Slic3r::GCodeProcessorResult::MoveVertex::time, libvgcode::TopSolidInfill, Slic3r::GCodeProcessorResult::MoveVertex::travel_dist, Slic3r::GCodeProcessorResult::MoveVertex::type, Slic3r::GCodeProcessorResult::unlock(), Slic3r::Unretract, libvgcode::WipeTower, Slic3r::GCodeProcessorResult::wrapping_exclude_area, and Slic3r::GCodeProcessorResult::z_offset.

Here is the call graph for this function:

◆ load_as_preview()

void Slic3r::GUI::GCodeViewer::load_as_preview ( libvgcode::GCodeInputData && data)
1899{
1900 m_loaded_as_preview = true;
1901 m_plate_mass = {};
1902 m_object_masses.clear();
1903 m_body_masses.clear();
1904 m_support_masses.clear();
1905
1906 m_move_type_counts.fill(0);
1907 for (auto& move_type_times : m_move_type_times)
1908 move_type_times.fill(0.0f);
1909 m_move_type_distances.fill(0.0f);
1910 const size_t normal_time_mode_idx = static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal);
1911 for (size_t i = 0; i < data.vertices.size(); ++i) {
1912 const libvgcode::PathVertex& vertex = data.vertices[i];
1913 const size_t move_type = static_cast<size_t>(vertex.type);
1914 if (move_type < m_move_type_counts.size()) {
1915 ++m_move_type_counts[move_type];
1916 for (size_t mode = 0; mode < vertex.times.size(); ++mode)
1917 m_move_type_times[move_type][mode] += vertex.times[mode];
1919 m_move_type_distances[move_type] += std::fabs(vertex.feedrate) * vertex.times[normal_time_mode_idx];
1920 } else if (i > 0) {
1921 const float dx = vertex.position[0] - data.vertices[i - 1].position[0];
1922 const float dy = vertex.position[1] - data.vertices[i - 1].position[1];
1923 const float dz = vertex.position[2] - data.vertices[i - 1].position[2];
1924 m_move_type_distances[move_type] += std::sqrt(dx * dx + dy * dy + dz * dz);
1925 }
1926 }
1927 }
1928
1929 m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::Skirt, { 127, 255, 127 });
1930 m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::ExternalPerimeter, { 255, 255, 0 });
1931 m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::SupportMaterial, { 127, 255, 127 });
1932 m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::SupportMaterialInterface, { 127, 255, 127 });
1933 m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::InternalInfill, { 255, 127, 127 });
1934 m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::SolidInfill, { 255, 127, 127 });
1935 m_viewer.set_extrusion_role_color(libvgcode::EGCodeExtrusionRole::WipeTower, { 127, 255, 127 });
1936 m_viewer.load(std::move(data));
1937
1938 const libvgcode::AABox bbox = m_viewer.get_extrusion_bounding_box();
1939 const BoundingBoxf3 paths_bounding_box(libvgcode::convert(bbox[0]).cast<double>(), libvgcode::convert(bbox[1]).cast<double>());
1940 m_contained_in_bed = wxGetApp().plater()->build_volume().all_paths_inside(GCodeProcessorResult(), paths_bounding_box);
1941}
@ Retract
Definition Types.hpp:123
@ Unretract
Definition Types.hpp:124
std::vector< PathVertex > vertices
Definition GCodeInputData.hpp:25
float feedrate
Definition PathVertex.hpp:36
EMoveType type
Definition PathVertex.hpp:66
Vec3 position
Definition PathVertex.hpp:24
std::array< float, TIME_MODES_COUNT > times
Definition PathVertex.hpp:86

References Slic3r::cast(), libvgcode::convert(), libvgcode::ExternalPerimeter, libvgcode::PathVertex::feedrate, libvgcode::InternalInfill, m_body_masses, m_contained_in_bed, m_loaded_as_preview, m_move_type_counts, m_move_type_distances, m_move_type_times, m_object_masses, m_plate_mass, m_support_masses, m_viewer, Slic3r::PrintEstimatedStatistics::Normal, libvgcode::PathVertex::position, libvgcode::Retract, libvgcode::Skirt, libvgcode::SolidInfill, libvgcode::SupportMaterial, libvgcode::SupportMaterialInterface, libvgcode::PathVertex::times, libvgcode::PathVertex::type, libvgcode::Unretract, and libvgcode::WipeTower.

Here is the call graph for this function:

◆ load_shells()

void Slic3r::GUI::GCodeViewer::load_shells ( const Print & print,
bool initialized,
bool force_previewing = false )
3136{
3137 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": initialized=%1%, force_previewing=%2%")%initialized %force_previewing;
3138 if ((print.id().id == m_shells.print_id)&&(print.get_modified_count() == m_shells.print_modify_count)) {
3139 //BBS: update force previewing logic
3140 if (force_previewing)
3141 m_shells.previewing = force_previewing;
3142 //already loaded
3143 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": already loaded, print=%1% print_id=%2%, print_modify_count=%3%, force_previewing %4%")%(&print) %m_shells.print_id %m_shells.print_modify_count %force_previewing;
3144 return;
3145 }
3146
3147 //reset shell firstly
3148 reset_shell();
3149
3150 //BBS: move behind of reset_shell, to clear previous shell for empty plate
3151 if (print.objects().empty()) {
3152 // no shells, return
3153 return;
3154 }
3155 // adds objects' volumes
3156 // BBS: fix the issue that object_idx is not assigned as index of Model.objects array
3157 int object_count = 0;
3158 const ModelObjectPtrs& model_objs = wxGetApp().model().objects;
3159 for (const PrintObject* obj : print.objects()) {
3160 const ModelObject* model_obj = obj->model_object();
3161
3162 int object_idx = -1;
3163 for (int idx = 0; idx < model_objs.size(); idx++) {
3164 if (model_objs[idx]->id() == model_obj->id()) {
3165 object_idx = idx;
3166 break;
3167 }
3168 }
3169
3170 // BBS: object may be deleted when this method is called when deleting an object
3171 if (object_idx == -1)
3172 continue;
3173
3174 std::vector<int> instance_ids(model_obj->instances.size());
3175 //BBS: only add the printable instance
3176 int instance_index = 0;
3177 for (int i = 0; i < (int)model_obj->instances.size(); ++i) {
3178 //BBS: only add the printable instance
3179 if (model_obj->instances[i]->is_printable())
3180 instance_ids[instance_index++] = i;
3181 }
3182 instance_ids.resize(instance_index);
3183
3184 size_t current_volumes_count = m_shells.volumes.volumes.size();
3185 m_shells.volumes.load_object(model_obj, object_idx, instance_ids, "object", initialized, false);
3186
3187 // adjust shells' z if raft is present
3188 const SlicingParameters& slicing_parameters = obj->slicing_parameters();
3189 if (slicing_parameters.object_print_z_min != 0.0) {
3190 const Vec3d z_offset = slicing_parameters.object_print_z_min * Vec3d::UnitZ();
3191 for (size_t i = current_volumes_count; i < m_shells.volumes.volumes.size(); ++i) {
3192 GLVolume* v = m_shells.volumes.volumes[i];
3193 auto offset = v->get_instance_transformation().get_matrix_no_offset().inverse() * z_offset;
3194 v->set_volume_offset(v->get_volume_offset() + offset);
3195 }
3196 }
3197
3198 object_count++;
3199 }
3200
3201 // Orca: disable wipe tower shell
3202 // if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) {
3203 // // BBS: adds wipe tower's volume
3204 // std::vector<unsigned int> print_extruders = print.extruders(true);
3205 // int extruders_count = print_extruders.size();
3206
3207 // const double max_z = print.objects()[0]->model_object()->get_model()->bounding_box().max(2);
3208 // const PrintConfig& config = print.config();
3209 // if (config.enable_prime_tower &&
3210 // (print.enable_timelapse_print() || (extruders_count > 1 && (config.print_sequence == PrintSequence::ByLayer)))) {
3211 // const float depth = print.wipe_tower_data(extruders_count).depth;
3212 // const float brim_width = print.wipe_tower_data(extruders_count).brim_width;
3213
3214 // int plate_idx = print.get_plate_index();
3215 // Vec3d plate_origin = print.get_plate_origin();
3216 // double wipe_tower_x = config.wipe_tower_x.get_at(plate_idx) + plate_origin(0);
3217 // double wipe_tower_y = config.wipe_tower_y.get_at(plate_idx) + plate_origin(1);
3218 // m_shells.volumes.load_wipe_tower_preview(1000, wipe_tower_x, wipe_tower_y, config.prime_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
3219 // !print.is_step_done(psWipeTower), brim_width, initialized);
3220 // }
3221 // }
3222
3223 // remove modifiers
3224 while (true) {
3225 GLVolumePtrs::iterator it = std::find_if(m_shells.volumes.volumes.begin(), m_shells.volumes.volumes.end(), [](GLVolume* volume) { return volume->is_modifier; });
3226 if (it != m_shells.volumes.volumes.end()) {
3227 delete (*it);
3228 m_shells.volumes.volumes.erase(it);
3229 }
3230 else
3231 break;
3232 }
3233
3234 for (GLVolume* volume : m_shells.volumes.volumes) {
3235 volume->zoom_to_volumes = false;
3236 volume->color.a(0.5f);
3237 volume->force_native_color = true;
3238 volume->set_render_color();
3239 //BBS: add shell bounding box logic
3240 m_shell_bounding_box.merge(volume->transformed_bounding_box());
3241 }
3242
3243 //BBS: always load shell when preview
3244 m_shells.print_id = print.id().id;
3245 m_shells.print_modify_count = print.get_modified_count();
3246 m_shells.previewing = true;
3247 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": shell loaded, id change to %1%, modify_count %2%, object count %3%, glvolume count %4%")
3248 % m_shells.print_id % m_shells.print_modify_count % object_count %m_shells.volumes.volumes.size();
3249}
void reset_shell()
Definition GCodeViewer.cpp:1952
Shells m_shells
Definition GCodeViewer.hpp:204
static bool initialized
Definition minilzo_extension.cpp:10
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
std::vector< ModelObject * > ModelObjectPtrs
Definition CutUtils.hpp:13

References Slic3r::ColorRGBA::a(), Slic3r::GLVolume::color, Slic3r::ConstVectorOfPtrsAdaptor< T >::empty(), Slic3r::GLVolume::get_instance_transformation(), Slic3r::Geometry::Transformation::get_matrix_no_offset(), Slic3r::Print::get_modified_count(), Slic3r::GLVolume::get_volume_offset(), Slic3r::ObjectBase::id(), Slic3r::ObjectID::id, initialized, Slic3r::ModelObject::instances, m_shell_bounding_box, m_shells, Slic3r::SlicingParameters::object_print_z_min, Slic3r::Print::objects(), Slic3r::offset(), reset_shell(), Slic3r::GLVolume::set_render_color(), Slic3r::GLVolume::set_volume_offset(), and Slic3r::GLVolume::transformed_bounding_box().

Here is the call graph for this function:

◆ on_change_color_mode()

void Slic3r::GUI::GCodeViewer::on_change_color_mode ( bool is_dark)
1219 {
1221 m_sequential_view.marker.on_change_color_mode(m_is_dark);
1222 m_sequential_view.gcode_window.on_change_color_mode(m_is_dark);
1223}
static bool is_dark()
Definition TextureImportDialog.cpp:85
bool m_is_dark
Definition GCodeViewer.hpp:367

References is_dark(), m_is_dark, and m_sequential_view.

Here is the call graph for this function:

◆ pop_combo_style()

void Slic3r::GUI::GCodeViewer::pop_combo_style ( )
5675{
5676 ImGui::PopStyleVar(3);
5677 ImGui::PopStyleColor(8);
5678}

◆ push_combo_style()

void Slic3r::GUI::GCodeViewer::push_combo_style ( )
5661{
5662 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f * m_scale); // ORCA scale rounding
5663 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * m_scale); // ORCA scale frame size
5664 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0,8.0));
5665 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
5666 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
5667 ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
5668 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
5669 ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.0f, 0.0f, 0.0f, 0.8f));
5670 ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
5671 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.59f, 0.53f, 0.0f));
5672 ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
5673}
float m_scale
Definition GCodeViewer.hpp:384

References m_scale.

◆ render_all_plates_stats()

void Slic3r::GUI::GCodeViewer::render_all_plates_stats ( const std::vector< const GCodeProcessorResult * > & gcode_result_list,
bool show = true ) const
3478 {
3479 if (!show)
3480 return;
3481 for (auto gcode_result : gcode_result_list) {
3482 if (gcode_result->moves.size() == 0)
3483 return;
3484 }
3485 ImGuiWrapper& imgui = *wxGetApp().imgui();
3486
3487 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f * m_scale); // ORCA add window rounding to modernize / match style
3488 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0, 10.0 * m_scale));
3489 ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(1.0f, 1.0f, 1.0f, 0.6f));
3490 ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f));
3491 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.0f));
3492 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f));
3493 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
3494 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
3495 ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(340.f * m_scale * imgui.scaled(1.0f / 15.0f), 0));
3496
3497 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), 0, ImVec2(0.5f, 0.5f));
3498 ImGui::Begin(_L("Statistics of All Plates").c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
3499 ImDrawList* draw_list = ImGui::GetWindowDrawList();
3500
3501 std::vector<float> filament_diameters = gcode_result_list.front()->filament_diameters;
3502 std::vector<float> filament_densities = gcode_result_list.front()->filament_densities;
3503 std::vector<ColorRGBA> filament_colors;
3504 decode_colors(wxGetApp().plater()->get_extruder_colors_from_plater_config(gcode_result_list.back()), filament_colors);
3505
3506 for (int i = 0; i < filament_colors.size(); i++) {
3507 filament_colors[i] = adjust_color_for_rendering(filament_colors[i]);
3508 }
3509
3510 bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
3511 float window_padding = 4.0f * m_scale;
3512 const float icon_size = ImGui::GetTextLineHeight() * 0.7;
3513 std::map<std::string, float> offsets;
3514 std::map<int, double> model_volume_of_extruders_all_plates; // map<extruder_idx, volume>
3515 std::map<int, double> flushed_volume_of_extruders_all_plates; // map<extruder_idx, flushed volume>
3516 std::map<int, double> wipe_tower_volume_of_extruders_all_plates; // map<extruder_idx, flushed volume>
3517 std::map<int, double> support_volume_of_extruders_all_plates; // map<extruder_idx, flushed volume>
3518 std::vector<double> model_used_filaments_m_all_plates;
3519 std::vector<double> model_used_filaments_g_all_plates;
3520 std::vector<double> flushed_filaments_m_all_plates;
3521 std::vector<double> flushed_filaments_g_all_plates;
3522 std::vector<double> wipe_tower_used_filaments_m_all_plates;
3523 std::vector<double> wipe_tower_used_filaments_g_all_plates;
3524 std::vector<double> support_used_filaments_m_all_plates;
3525 std::vector<double> support_used_filaments_g_all_plates;
3526 float total_time_all_plates = 0.0f;
3527 float total_cost_all_plates = 0.0f;
3528 bool show_detailed_statistics_page = false;
3529 struct ColumnData {
3530 enum {
3531 Model = 1,
3532 Flushed = 2,
3533 WipeTower = 4,
3534 Support = 1 << 3,
3535 };
3536 };
3537 int displayed_columns = 0;
3538 auto max_width = [](const std::vector<std::string>& items, const std::string& title, float extra_size = 0.0f) {
3539 float ret = ImGui::CalcTextSize(title.c_str()).x;
3540 for (const std::string& item : items) {
3541 ret = std::max(ret, extra_size + ImGui::CalcTextSize(item.c_str()).x);
3542 }
3543 return ret;
3544 };
3545 auto calculate_offsets = [max_width, window_padding](const std::vector<std::pair<std::string, std::vector<std::string>>>& title_columns, float extra_size = 0.0f) {
3546 const ImGuiStyle& style = ImGui::GetStyle();
3547 std::vector<float> offsets;
3548 offsets.push_back(max_width(title_columns[0].second, title_columns[0].first, extra_size) + 3.0f * style.ItemSpacing.x + style.WindowPadding.x);
3549 for (size_t i = 1; i < title_columns.size() - 1; i++)
3550 offsets.push_back(offsets.back() + max_width(title_columns[i].second, title_columns[i].first) + style.ItemSpacing.x);
3551 if (title_columns.back().first == _u8L("Display"))
3552 offsets.back() = ImGui::GetWindowWidth() - ImGui::CalcTextSize(_u8L("Display").c_str()).x - ImGui::GetFrameHeight() / 2 - 2 * window_padding;
3553
3554 float average_col_width = ImGui::GetWindowWidth() / static_cast<float>(title_columns.size());
3555 std::vector<float> ret;
3556 ret.push_back(0);
3557 for (size_t i = 1; i < title_columns.size(); i++) {
3558 ret.push_back(std::max(offsets[i - 1], i * average_col_width));
3559 }
3560
3561 return ret;
3562 };
3563 auto append_item = [icon_size, &imgui, &window_padding, &draw_list, this](const ColorRGBA& color, const std::vector<std::pair<std::string, float>>& columns_offsets)
3564 {
3565 // render icon
3566 ImVec2 pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y);
3567
3568 add_swatch(draw_list, { pos.x + 1.0f * m_scale, pos.y + 3.0f * m_scale }, { pos.x + icon_size - 1.0f * m_scale, pos.y + icon_size + 1.0f * m_scale }, color);
3569
3570 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0 * m_scale, 6.0 * m_scale));
3571
3572 // render selectable
3573 ImGui::Dummy({ 0.0, 0.0 });
3574 ImGui::SameLine();
3575
3576 // render column item
3577 {
3578 float dummy_size = ImGui::GetStyle().ItemSpacing.x + icon_size;
3579 ImGui::SameLine(dummy_size);
3580 imgui.text(columns_offsets[0].first);
3581
3582 for (auto i = 1; i < columns_offsets.size(); i++) {
3583 ImGui::SameLine(columns_offsets[i].second);
3584 imgui.text(columns_offsets[i].first);
3585 }
3586 }
3587
3588 ImGui::PopStyleVar(1);
3589 };
3590 auto append_headers = [&imgui](const std::vector<std::pair<std::string, float>>& title_offsets) {
3591 for (size_t i = 0; i < title_offsets.size(); i++) {
3592 ImGui::SameLine(title_offsets[i].second);
3593 imgui.bold_text(title_offsets[i].first);
3594 }
3595 ImGui::Separator();
3596 };
3597 auto get_used_filament_from_volume = [imperial_units, &filament_diameters, &filament_densities](double volume, int extruder_id) {
3598 double koef = imperial_units ? 1.0 / GizmoObjectManipulation::in_to_mm : 0.001;
3599 std::pair<double, double> ret = { koef * volume / (PI * sqr(0.5 * filament_diameters[extruder_id])),
3600 volume * filament_densities[extruder_id] * 0.001 };
3601 return ret;
3602 };
3603
3604 ImGui::Dummy({ window_padding, window_padding });
3605 ImGui::SameLine();
3606 // title and item data
3607 {
3608 PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
3609 for (auto plate : plate_list.get_nonempty_plate_list())
3610 {
3611 auto plate_print_statistics = plate->get_slice_result()->print_statistics;
3612 auto plate_extruders = plate->get_extruders(true);
3613 auto max_extruders_colors = wxGetApp().plater()->get_extruders_colors().size();
3614 for (size_t extruder_id : plate_extruders) {
3615 extruder_id -= 1;
3616 // Skip stale/overflow extruder indices (e.g. from object assignments that outlived a
3617 // filament-count change) so downstream per-extruder lookups stay in range. Ported
3618 // from BambuStudio (STUDIO-15763).
3619 if (extruder_id >= max_extruders_colors)
3620 continue;
3621 if (plate_print_statistics.model_volumes_per_extruder.find(extruder_id) == plate_print_statistics.model_volumes_per_extruder.end())
3622 model_volume_of_extruders_all_plates[extruder_id] += 0;
3623 else {
3624 double model_volume = plate_print_statistics.model_volumes_per_extruder.at(extruder_id);
3625 model_volume_of_extruders_all_plates[extruder_id] += model_volume;
3626 }
3627 if (plate_print_statistics.flush_per_filament.find(extruder_id) == plate_print_statistics.flush_per_filament.end())
3628 flushed_volume_of_extruders_all_plates[extruder_id] += 0;
3629 else {
3630 double flushed_volume = plate_print_statistics.flush_per_filament.at(extruder_id);
3631 flushed_volume_of_extruders_all_plates[extruder_id] += flushed_volume;
3632 }
3633 if (plate_print_statistics.wipe_tower_volumes_per_extruder.find(extruder_id) == plate_print_statistics.wipe_tower_volumes_per_extruder.end())
3634 wipe_tower_volume_of_extruders_all_plates[extruder_id] += 0;
3635 else {
3636 double wipe_tower_volume = plate_print_statistics.wipe_tower_volumes_per_extruder.at(extruder_id);
3637 wipe_tower_volume_of_extruders_all_plates[extruder_id] += wipe_tower_volume;
3638 }
3639 if (plate_print_statistics.support_volumes_per_extruder.find(extruder_id) == plate_print_statistics.support_volumes_per_extruder.end())
3640 support_volume_of_extruders_all_plates[extruder_id] += 0;
3641 else {
3642 double support_volume = plate_print_statistics.support_volumes_per_extruder.at(extruder_id);
3643 support_volume_of_extruders_all_plates[extruder_id] += support_volume;
3644 }
3645 }
3646 const PrintEstimatedStatistics::Mode& plate_time_mode = plate_print_statistics.modes[static_cast<size_t>(m_viewer.get_time_mode())];
3647 total_time_all_plates += plate_time_mode.time;
3648
3649 Print *print;
3650 plate->get_print((PrintBase **) &print, nullptr, nullptr);
3651 total_cost_all_plates += print->print_statistics().total_cost;
3652 }
3653
3654 for (auto it = model_volume_of_extruders_all_plates.begin(); it != model_volume_of_extruders_all_plates.end(); it++) {
3655 auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(it->second, it->first);
3656 if (model_used_filament_m != 0.0 || model_used_filament_g != 0.0)
3657 displayed_columns |= ColumnData::Model;
3658 model_used_filaments_m_all_plates.push_back(model_used_filament_m);
3659 model_used_filaments_g_all_plates.push_back(model_used_filament_g);
3660 }
3661 for (auto it = flushed_volume_of_extruders_all_plates.begin(); it != flushed_volume_of_extruders_all_plates.end(); it++) {
3662 auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(it->second, it->first);
3663 if (flushed_filament_m != 0.0 || flushed_filament_g != 0.0)
3664 displayed_columns |= ColumnData::Flushed;
3665 flushed_filaments_m_all_plates.push_back(flushed_filament_m);
3666 flushed_filaments_g_all_plates.push_back(flushed_filament_g);
3667 }
3668 for (auto it = wipe_tower_volume_of_extruders_all_plates.begin(); it != wipe_tower_volume_of_extruders_all_plates.end(); it++) {
3669 auto [wipe_tower_filament_m, wipe_tower_filament_g] = get_used_filament_from_volume(it->second, it->first);
3670 if (wipe_tower_filament_m != 0.0 || wipe_tower_filament_g != 0.0)
3671 displayed_columns |= ColumnData::WipeTower;
3672 wipe_tower_used_filaments_m_all_plates.push_back(wipe_tower_filament_m);
3673 wipe_tower_used_filaments_g_all_plates.push_back(wipe_tower_filament_g);
3674 }
3675 for (auto it = support_volume_of_extruders_all_plates.begin(); it != support_volume_of_extruders_all_plates.end(); it++) {
3676 auto [support_filament_m, support_filament_g] = get_used_filament_from_volume(it->second, it->first);
3677 if (support_filament_m != 0.0 || support_filament_g != 0.0)
3678 displayed_columns |= ColumnData::Support;
3679 support_used_filaments_m_all_plates.push_back(support_filament_m);
3680 support_used_filaments_g_all_plates.push_back(support_filament_g);
3681 }
3682
3683 char buff[64];
3684 double longest_str = 0.0;
3685 for (auto i : model_used_filaments_g_all_plates) {
3686 if (i > longest_str)
3687 longest_str = i;
3688 }
3689 ::sprintf(buff, "%.2f", longest_str);
3690
3691 std::vector<std::pair<std::string, std::vector<std::string>>> title_columns;
3692 if (displayed_columns & ColumnData::Model) {
3693 title_columns.push_back({ _u8L("Filament"), {""} });
3694 title_columns.push_back({ _u8L("Model"), {buff} });
3695 }
3696 if (displayed_columns & ColumnData::Support) {
3697 title_columns.push_back({ _u8L("Support"), {buff} });
3698 }
3699 if (displayed_columns & ColumnData::Flushed) {
3700 title_columns.push_back({ _u8L("Flushed"), {buff} });
3701 }
3702 if (displayed_columns & ColumnData::WipeTower) {
3703 title_columns.push_back({ _u8L("Tower"), {buff} });
3704 }
3705 if ((displayed_columns & ~ColumnData::Model) > 0) {
3706 title_columns.push_back({ _u8L("Total"), {buff} });
3707 }
3708 auto offsets_ = calculate_offsets(title_columns, icon_size);
3709 std::vector<std::pair<std::string, float>> title_offsets;
3710 for (int i = 0; i < offsets_.size(); i++) {
3711 title_offsets.push_back({ title_columns[i].first, offsets_[i] });
3712 offsets[title_columns[i].first] = offsets_[i];
3713 }
3714 append_headers(title_offsets);
3715 }
3716
3717 // item
3718 {
3719 size_t i = 0;
3720 for (auto it = model_volume_of_extruders_all_plates.begin(); it != model_volume_of_extruders_all_plates.end(); it++) {
3721 if (i < model_used_filaments_m_all_plates.size() && i < model_used_filaments_g_all_plates.size()) {
3722 std::vector<std::pair<std::string, float>> columns_offsets;
3723 columns_offsets.push_back({ std::to_string(it->first + 1), offsets[_u8L("Filament")]});
3724
3725 char buf[64];
3726 float column_sum_m = 0.0f;
3727 float column_sum_g = 0.0f;
3728 if (displayed_columns & ColumnData::Model) {
3729 const std::string weight_text = format_compact_weight(model_used_filaments_g_all_plates[i], imperial_units);
3730 if ((displayed_columns & ~ColumnData::Model) > 0)
3731 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", model_used_filaments_m_all_plates[i], weight_text.c_str());
3732 else
3733 ::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m_all_plates[i], weight_text.c_str());
3734 columns_offsets.push_back({ buf, offsets[_u8L("Model")] });
3735 column_sum_m += model_used_filaments_m_all_plates[i];
3736 column_sum_g += model_used_filaments_g_all_plates[i];
3737 }
3738 if (displayed_columns & ColumnData::Support) {
3739 const std::string weight_text = format_compact_weight(support_used_filaments_g_all_plates[i], imperial_units);
3740 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", support_used_filaments_m_all_plates[i], weight_text.c_str());
3741 columns_offsets.push_back({ buf, offsets[_u8L("Support")] });
3742 column_sum_m += support_used_filaments_m_all_plates[i];
3743 column_sum_g += support_used_filaments_g_all_plates[i];
3744 }
3745 if (displayed_columns & ColumnData::Flushed) {
3746 const std::string weight_text = format_compact_weight(flushed_filaments_g_all_plates[i], imperial_units);
3747 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", flushed_filaments_m_all_plates[i], weight_text.c_str());
3748 columns_offsets.push_back({ buf, offsets[_u8L("Flushed")] });
3749 column_sum_m += flushed_filaments_m_all_plates[i];
3750 column_sum_g += flushed_filaments_g_all_plates[i];
3751 }
3752 if (displayed_columns & ColumnData::WipeTower) {
3753 const std::string weight_text = format_compact_weight(wipe_tower_used_filaments_g_all_plates[i], imperial_units);
3754 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", wipe_tower_used_filaments_m_all_plates[i], weight_text.c_str());
3755 columns_offsets.push_back({ buf, offsets[_u8L("Tower")] });
3756 column_sum_m += wipe_tower_used_filaments_m_all_plates[i];
3757 column_sum_g += wipe_tower_used_filaments_g_all_plates[i];
3758 }
3759 if ((displayed_columns & ~ColumnData::Model) > 0) {
3760 const std::string weight_text = format_compact_weight(column_sum_g, imperial_units);
3761 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", column_sum_m, weight_text.c_str());
3762 columns_offsets.push_back({ buf, offsets[_u8L("Total")] });
3763 }
3764
3765 append_item(filament_colors[it->first], columns_offsets);
3766 }
3767 i++;
3768 }
3769
3770 ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
3771 ImGui::Dummy({ window_padding, window_padding });
3772 ImGui::SameLine();
3773 imgui.title(_u8L("Total estimation"));
3774
3775 ImGui::Dummy({ window_padding, window_padding });
3776 ImGui::SameLine();
3777 imgui.text(_u8L("Total time") + ":");
3778 ImGui::SameLine();
3779 imgui.text(short_time(get_time_dhms(total_time_all_plates)));
3780
3781 ImGui::Dummy({ window_padding, window_padding });
3782 ImGui::SameLine();
3783 imgui.text(_u8L("Total cost") + ":");
3784 ImGui::SameLine();
3785 char buf[64];
3786 ::sprintf(buf, "%.2f", total_cost_all_plates);
3787 imgui.text(buf);
3788
3789 }
3790 ImGui::End();
3791 ImGui::PopStyleColor(6);
3792 ImGui::PopStyleVar(3);
3793 return;
3794}
Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors)
Definition 3DScene.cpp:112
#define style
Definition WipeTowerDialog.cpp:101
static const double in_to_mm
Definition GizmoObjectManipulation.hpp:30
static constexpr double PI
Definition libslic3r.h:81
static void add_swatch(ImDrawList *draw_list, const ImVec2 &min, const ImVec2 &max, const ColorRGBA &color)
Definition GCodeViewer.cpp:130
static std::string format_compact_weight(double value_in_grams, bool imperial_units)
Definition GCodeViewer.cpp:228
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16
@ Support
Definition SupportTree.hpp:117
bool decode_colors(const std::vector< std::string > &colors_in, std::vector< ColorRGB > &colors_out)
Definition Color.cpp:377
constexpr T sqr(T x)
Definition libslic3r.h:301

References _L, _u8L, Slic3r::GUI::add_swatch(), adjust_color_for_rendering(), Slic3r::GUI::ImGuiWrapper::bold_text(), Slic3r::decode_colors(), Slic3r::GUI::format_compact_weight(), Slic3r::GUI::PartPlateList::get_nonempty_plate_list(), Slic3r::get_time_dhms(), Slic3r::GUI::GizmoObjectManipulation::in_to_mm, m_scale, m_viewer, PI, Slic3r::GUI::plater(), Slic3r::Print::print_statistics(), Slic3r::GUI::ImGuiWrapper::scaled(), Slic3r::short_time(), Slic3r::sqr(), style, Slic3r::GUI::ImGuiWrapper::text(), Slic3r::PrintEstimatedStatistics::Mode::time, Slic3r::GUI::ImGuiWrapper::title(), and Slic3r::PrintStatistics::total_cost.

Here is the call graph for this function:

◆ render_legend()

void Slic3r::GUI::GCodeViewer::render_legend ( float & legend_height,
int canvas_width,
int canvas_height,
int right_margin )
private
4066{
4067 if (!is_legend_shown())
4068 return;
4069
4070 const Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
4071
4072 ImGuiWrapper& imgui = *wxGetApp().imgui();
4073
4074 //BBS: GUI refactor: move to the right
4075 imgui.set_next_window_pos(float(canvas_width - right_margin * m_scale), 4.0f * m_scale, ImGuiCond_Always, 1.0f, 0.0f); // ORCA add a small gap to top to create seperation with main toolbar
4076 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f * m_scale); // ORCA add window rounding to modernize / match style
4077 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0,0.0));
4078 ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(1.0f,1.0f,1.0f,0.6f));
4079 ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
4080 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
4081 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f));
4082 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
4083 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
4084 //ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.f, 1.f, 1.f, 1.0f));
4085 ImGui::PushStyleColor(ImGuiCol_Border, {1, 0, 0, 0});
4086 ImGui::SetNextWindowBgAlpha(0.8f);
4087 const float max_height = 0.75f * static_cast<float>(cnv_size.get_height());
4088 const float child_height = 0.3333f * max_height;
4089 ImGui::SetNextWindowSizeConstraints({ 0.0f, 0.0f }, { -1.0f, max_height });
4090 imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove);
4091
4092 enum class EItemType : unsigned char
4093 {
4094 Rect,
4095 Circle,
4096 Hexagon,
4097 Line,
4098 None
4099 };
4100
4101 const PrintEstimatedStatistics::Mode& time_mode = m_print_statistics.modes[static_cast<size_t>(m_viewer.get_time_mode())];
4102 const libvgcode::EViewType curr_view_type = m_viewer.get_view_type();
4103 const int curr_view_type_i = static_cast<int>(curr_view_type);
4104 const size_t current_time_mode = static_cast<size_t>(m_viewer.get_time_mode());
4105 const float total_estimated_time = time_mode.time > 0.0f ? time_mode.time : m_viewer.get_estimated_time();
4106 bool show_estimated_time = total_estimated_time > 0.0f && (curr_view_type == libvgcode::EViewType::FeatureType ||
4108 (curr_view_type == libvgcode::EViewType::ColorPrint && !time_mode.custom_gcode_times.empty()));
4109
4110 const float icon_size = ImGui::GetTextLineHeight() * 0.7;
4111 //BBS GUI refactor
4112 //const float percent_bar_size = 2.0f * ImGui::GetTextLineHeight();
4113 const float percent_bar_size = 0;
4114
4115 bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
4116 ImDrawList* draw_list = ImGui::GetWindowDrawList();
4117 ImVec2 pos_rect = ImGui::GetCursorScreenPos();
4118 float window_padding = 4.0f * m_scale;
4119
4120 auto format_compact_count = [](unsigned long long value) {
4121 static constexpr const char* suffixes[] = { "", "K", "M", "B", "T", "P", "E" };
4122 constexpr size_t suffix_count = sizeof(suffixes) / sizeof(suffixes[0]);
4123
4124 if (value < 1000)
4125 return std::to_string(value);
4126
4127 size_t suffix_index = 0;
4128 unsigned long long divisor = 1;
4129 while (suffix_index + 1 < suffix_count && value / divisor >= 1000) {
4130 divisor *= 1000;
4131 ++suffix_index;
4132 }
4133
4134 const unsigned long long whole = value / divisor;
4135 const unsigned long long tenths = (value % divisor) * 10 / divisor;
4136
4137 std::string ret = std::to_string(whole);
4138 if (tenths != 0)
4139 ret += "." + std::to_string(tenths);
4140 ret += suffixes[suffix_index];
4141 return ret;
4142 };
4143
4144 auto format_percent = [](float percent) {
4145 if (percent == 0.0f)
4146 return std::string("0");
4147
4148 char buffer[64];
4149 percent > 0.001f ? ::sprintf(buffer, "%.1f", percent * 100.0f) : ::sprintf(buffer, "<0.1");
4150 return std::string(buffer);
4151 };
4152
4153 // ORCA dont use background on top bar to give modern look
4154 //draw_list->AddRectFilled(ImVec2(pos_rect.x,pos_rect.y - ImGui::GetStyle().WindowPadding.y),
4155 //ImVec2(pos_rect.x + ImGui::GetWindowWidth() + ImGui::GetFrameHeight(),pos_rect.y + ImGui::GetFrameHeight() + window_padding * 2.5),
4156 //ImGui::GetColorU32(ImVec4(0,0,0,0.3)));
4157
4158 auto append_item = [icon_size, &imgui, &window_padding, &draw_list, this](
4159 EItemType type,
4160 const ColorRGBA& color,
4161 const std::vector<std::pair<std::string, float>>& columns_offsets,
4162 bool checkbox = true,
4163 float checkbox_pos = 0.f, // ORCA use calculated value for eye icon. Aligned to "Display" header or end of combo box
4164 bool visible = true,
4165 std::function<void()> callback = nullptr)
4166 {
4167 // render icon
4168 ImVec2 pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y);
4169 switch (type) {
4170 default:
4171 case EItemType::Rect: {
4172 add_swatch(draw_list, { pos.x + 1.0f * m_scale, pos.y + 3.0f * m_scale }, { pos.x + icon_size - 1.0f * m_scale, pos.y + icon_size + 1.0f * m_scale }, color);
4173 break;
4174 }
4175 case EItemType::Circle: {
4176 ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size + 5.0f));
4177 draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGuiWrapper::to_ImU32(color), 16);
4178 break;
4179 }
4180 case EItemType::Hexagon: {
4181 ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size + 5.0f));
4182 draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGuiWrapper::to_ImU32(color), 6);
4183 break;
4184 }
4185 case EItemType::Line: {
4186 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);
4187 break;
4188 }
4189 case EItemType::None:
4190 break;
4191 }
4192
4193 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0 * m_scale, 6.0 * m_scale));
4194
4195 // BBS render selectable
4196 ImGui::Dummy({ 0.0, 0.0 });
4197 ImGui::SameLine();
4198 if (callback) {
4199 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * m_scale);
4200 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0 * m_scale, 0.0));
4201 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(1.00f, 0.68f, 0.26f, 0.0f));
4202 ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(1.00f, 0.68f, 0.26f, 0.0f));
4203 ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
4204 float max_height = 0.f;
4205 for (auto column_offset : columns_offsets) {
4206 if (ImGui::CalcTextSize(column_offset.first.c_str()).y > max_height)
4207 max_height = ImGui::CalcTextSize(column_offset.first.c_str()).y;
4208 }
4209 bool b_menu_item = ImGui::BBLMenuItem(("##" + columns_offsets[0].first).c_str(), nullptr, false, true, max_height);
4210 ImGui::PopStyleVar(2);
4211 ImGui::PopStyleColor(3);
4212 if (b_menu_item)
4213 callback();
4214 if (checkbox) {
4215 // ORCA replace checkboxes with eye icon
4216 // Use calculated position from argument. this method has predictable result compared to alingning button using window width
4217 // fixes slowly resizing window and endlessly expanding window when there is a miscalculation on position
4218 ImGui::SameLine(checkbox_pos);
4219 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0, 0.0)); // ensure no padding active
4220 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0, 0.0)); // ensure no item spacing active
4221 ImGui::Text("%s", into_u8(visible ? ImGui::VisibleIcon : ImGui::HiddenIcon).c_str());
4222 ImGui::PopStyleVar(2);
4223 }
4224 }
4225
4226 // BBS render column item
4227 {
4228 if(callback && !checkbox && !visible)
4229 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(172 / 255.0f, 172 / 255.0f, 172 / 255.0f, 1.00f));
4230 float dummy_size = type == EItemType::None ? window_padding * 3 : ImGui::GetStyle().ItemSpacing.x + icon_size;
4231 ImGui::SameLine(dummy_size);
4232 imgui.text(columns_offsets[0].first);
4233
4234 for (auto i = 1; i < columns_offsets.size(); i++) {
4235 ImGui::SameLine(columns_offsets[i].second);
4236 imgui.text(columns_offsets[i].first);
4237 }
4238 if (callback && !checkbox && !visible)
4239 ImGui::PopStyleColor(1);
4240 }
4241
4242 ImGui::PopStyleVar(1);
4243
4244 };
4245
4246 auto append_range = [append_item](const libvgcode::ColorRange& range, unsigned int decimals) {
4247 auto append_range_item = [append_item, &range](int i, float value, unsigned int decimals) {
4248 char buf[1024];
4249 ::sprintf(buf, "%.*f", decimals, value);
4250 append_item(EItemType::Rect, libvgcode::convert(range.get_palette()[i]), { { buf , 0} });
4251 };
4252
4253 std::vector<float> values = range.get_values();
4254 if (values.size() == 1)
4255 // single item use case
4256 append_range_item(0, values.front(), decimals);
4257 else if (values.size() == 2) {
4258 append_range_item(static_cast<int>(range.get_palette().size()) - 1, values.back(), decimals);
4259 append_range_item(0, values.front(), decimals);
4260 }
4261 else {
4262 for (int i = static_cast<int>(range.get_palette().size()) - 1; i >= 0; --i) {
4263 append_range_item(i, values[i], decimals);
4264 }
4265 }
4266 };
4267
4268 auto append_headers = [&imgui, window_padding, this](const std::vector<std::pair<std::string, float>>& title_offsets) {
4269 for (size_t i = 0; i < title_offsets.size(); i++) {
4270 if (title_offsets[i].first == _u8L("Display")) { // ORCA Hide Display header
4271 ImGui::SameLine(title_offsets[i].second);
4272 ImGui::Dummy({16.f * m_scale, 1}); // 16(icon_size)
4273 continue;
4274 }
4275 ImGui::SameLine(title_offsets[i].second);
4276 imgui.bold_text(title_offsets[i].first);
4277 }
4278 // Ensure right padding
4279 ImGui::SameLine();
4280 ImGui::Dummy({window_padding, 1});
4281 ImGui::Separator();
4282 };
4283
4284 auto max_width = [](const std::vector<std::string>& items, const std::string& title, float extra_size = 0.0f) {
4285 float ret = ImGui::CalcTextSize(title.c_str()).x;
4286 for (const std::string& item : items) {
4287 ret = std::max(ret, extra_size + ImGui::CalcTextSize(item.c_str()).x);
4288 }
4289 return ret;
4290 };
4291
4292 auto calculate_offsets = [max_width, this](const std::vector<std::pair<std::string, std::vector<std::string>>>& title_columns, float extra_size = 0.0f) {
4293 const ImGuiStyle& style = ImGui::GetStyle();
4294 std::vector<float> offsets;
4295 // ORCA increase spacing for more readable format. Using direct number requires much less code change in here. GetTextLineHeight for additional spacing for icon_size
4296 offsets.push_back(max_width(title_columns[0].second, title_columns[0].first, extra_size) + 12.f * m_scale + ImGui::GetTextLineHeight());
4297 for (size_t i = 1; i < title_columns.size() - 1; i++) // ORCA dont add extra spacing after icon / "Display" header
4298 offsets.push_back(offsets.back() + max_width(title_columns[i].second, title_columns[i].first) + ((title_columns[i].first == _u8L("Display") ? 0 : 12.f) * m_scale));
4299 if (title_columns.back().first == _u8L("Display") && title_columns.size() > 2)
4300 offsets[title_columns.size() - 2] -= 3.f; // ORCA reduce spacing after previous header
4301
4302 float average_col_width = ImGui::GetWindowWidth() / static_cast<float>(title_columns.size());
4303 std::vector<float> ret;
4304 ret.push_back(0);
4305 for (size_t i = 1; i < title_columns.size(); i++) {
4306 ret.push_back(std::max(offsets[i - 1], i * average_col_width));
4307 }
4308 return ret;
4309 };
4310
4311 auto color_print_ranges = [this](unsigned char extruder_id, const std::vector<CustomGCode::Item>& custom_gcode_per_print_z) {
4312 std::vector<std::pair<ColorRGBA, std::pair<double, double>>> ret;
4313 ret.reserve(custom_gcode_per_print_z.size());
4314
4315 // Loop invariant, but built lazily: this lambda runs once per extruder on every frame
4316 // and most prints reach neither colour change below, so fetching it up front would cost
4317 // more than the per-item fetch it replaces.
4318 std::vector<float> zs;
4319 bool zs_built = false;
4320
4321 for (const auto& item : custom_gcode_per_print_z) {
4322 if (extruder_id + 1 != static_cast<unsigned char>(item.extruder))
4323 continue;
4324
4325 if (item.type != CustomGCode::ColorChange)
4326 continue;
4327
4328 if (!zs_built) {
4329 zs = m_viewer.get_layers_zs();
4330 zs_built = true;
4331 }
4332 auto lower_b = std::lower_bound(zs.begin(), zs.end(),
4333 static_cast<float>(item.print_z - epsilon()));
4334 if (lower_b == zs.end())
4335 continue;
4336
4337 const double current_z = *lower_b;
4338 const double previous_z = (lower_b == zs.begin()) ? 0.0 : *(--lower_b);
4339
4340 // to avoid duplicate values, check adding values
4341 if (ret.empty() || !(ret.back().second.first == previous_z && ret.back().second.second == current_z))
4342 {
4343 ColorRGBA color;
4344 decode_color(item.color, color);
4345 ret.push_back({ color, { previous_z, current_z } });
4346 }
4347 }
4348
4349 return ret;
4350 };
4351
4352 // Whole sentences: the bare "up to"/"above"/"from"/"to" these used to be glued from gave a
4353 // translator no context, and left the unit and the numbers stuck in English word order.
4354 auto upto_label = [](double z) {
4355 char buf[64];
4356 ::sprintf(buf, "%.2f", z);
4357 return format(_u8L("up to %1% mm"), buf);
4358 };
4359
4360 auto above_label = [](double z) {
4361 char buf[64];
4362 ::sprintf(buf, "%.2f", z);
4363 return format(_u8L("above %1% mm"), buf);
4364 };
4365
4366 auto fromto_label = [](double z1, double z2) {
4367 char buf1[64];
4368 ::sprintf(buf1, "%.2f", z1);
4369 char buf2[64];
4370 ::sprintf(buf2, "%.2f", z2);
4371 return format(_u8L("from %1% to %2% mm"), buf1, buf2);
4372 };
4373
4374 auto role_time_and_percent = [this, total_estimated_time](libvgcode::EGCodeExtrusionRole role) {
4375 const float time = m_viewer.get_extrusion_role_estimated_time(role);
4376 return std::make_pair(time, total_estimated_time > 0.0f ? time / total_estimated_time : 0.0f);
4377 };
4378
4379 auto travel_time_and_percent = [this, total_estimated_time]() {
4380 const float time = m_viewer.get_travels_estimated_time();
4381 return std::make_pair(time, total_estimated_time > 0.0f ? time / total_estimated_time : 0.0f);
4382 };
4383
4384 auto format_distance = [imperial_units](float distance_mm) {
4385 char buffer[64];
4386 if (imperial_units) {
4387 ::sprintf(buffer, "%.2fin", distance_mm / GizmoObjectManipulation::in_to_mm);
4388 } else if (std::fabs(distance_mm) < 1000.0f) {
4389 ::sprintf(buffer, "%.0fmm", distance_mm);
4390 } else {
4391 ::sprintf(buffer, "%.2fm", distance_mm / 1000.0f);
4392 }
4393 return std::string(buffer);
4394 };
4395
4396 auto used_filament_per_role = [this, imperial_units](ExtrusionRole role) {
4397 auto it = m_print_statistics.used_filaments_per_role.find(role);
4398 if (it == m_print_statistics.used_filaments_per_role.end())
4399 return std::make_pair(0.0, 0.0);
4400
4401 double koef = imperial_units ? GizmoObjectManipulation::in_to_mm / 1000.0 : 1.0;
4402 double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1;
4403 return std::make_pair(it->second.first / koef, it->second.second / unit_conver);
4404 };
4405
4406 // get used filament (meters and grams) from used volume in respect to the active extruder
4407 auto get_used_filament_from_volume = [this, imperial_units](double volume, int extruder_id) {
4408 double koef = imperial_units ? 1.0 / GizmoObjectManipulation::in_to_mm : 0.001;
4409 std::pair<double, double> ret = { koef * volume / (PI * sqr(0.5 * m_filament_diameters[extruder_id])),
4410 volume * m_filament_densities[extruder_id] * 0.001 };
4411 return ret;
4412 };
4413
4414 //BBS display Color Scheme
4415 ImGui::Dummy({ window_padding, window_padding });
4416 ImGui::Dummy({ window_padding, window_padding });
4417 ImGui::SameLine(window_padding * 2); // ORCA Ignores item spacing to get perfect window margins since since this part uses dummies for window padding
4418
4419 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
4420 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f));
4421 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f));
4422 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(2.f, 2.f) * m_scale);
4423 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f * m_scale); // ORCA Match button style with combo box
4424
4425 // ORCA use glyph based button for fixing button sizes changing depends on used font size on platform
4426 const wchar_t foldIcon = m_fold ? ImGui::UnfoldButtonIcon : ImGui::FoldButtonIcon;
4427 if (imgui.glyph_button(foldIcon, ImVec2(16.f, 16.f) * m_scale)) {
4428 m_fold = !m_fold;
4429 }
4430
4431 ImGui::SameLine();
4432 const wchar_t gCodeToggle = ImGui::gCodeButtonIcon;
4433 if (imgui.glyph_button(gCodeToggle, ImVec2(16.f, 16.f) * m_scale)) {
4434 wxGetApp().toggle_show_gcode_window();
4435 wxGetApp().plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
4436 }
4437
4438 ImGui::PopStyleColor(3);
4439 ImGui::PopStyleVar(2);
4440
4441 //imgui.bold_text(_u8L("Color Scheme"));
4443
4444 ImGui::SameLine();
4445 const char* view_type_value = view_type_items_str[m_view_type_sel].c_str();
4446 ImGuiComboFlags flags = ImGuiComboFlags_HeightLargest; // ORCA allow to fit all items to prevent scrolling on reaching last elements
4447 if (ImGui::BBLBeginCombo("", view_type_value, flags)) {
4448 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
4449 for (int i = 0; i < view_type_items_str.size(); i++) {
4450 const bool is_selected = (m_view_type_sel == i);
4451 if (ImGui::BBLSelectable(view_type_items_str[i].c_str(), is_selected)) {
4452 m_fold = false;
4453 m_view_type_sel = i;
4456 // ORCA: remember the pick so the "Last used" preview default can restore it
4457 const std::string view_type_name = view_type_to_config_name(view_type_items[m_view_type_sel]);
4458 if (!view_type_name.empty())
4459 wxGetApp().app_config->set("preview_last_view_type", view_type_name);
4461 #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
4462 imgui.set_requires_extra_frame();
4463 #else
4464 wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
4465 wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
4466 #endif
4467 }
4468 if (is_selected) {
4469 ImGui::SetItemDefaultFocus();
4470 }
4471 }
4472 ImGui::PopStyleVar(1);
4473 ImGui::EndCombo();
4474 }
4476 ImGui::SameLine(0, window_padding); // ORCA Without (0,window_padding) it adds unnecessary item spacing after combo box
4477 // ORCA predictable_icon_pos helpful when window size determined by combo box.
4478 float predictable_icon_pos = ImGui::GetCursorPosX() - icon_size - window_padding - ImGui::GetStyle().ItemSpacing.x - 1.f * m_scale; // 1 for border
4479 ImGui::Dummy({ window_padding, window_padding });
4480 ImGui::Dummy({ window_padding, window_padding }); // ORCA Matches top-bottom window paddings
4481 float window_width = ImGui::GetWindowWidth(); // ORCA Store window width
4482
4483 if (m_fold) {
4484 legend_height = ImGui::GetFrameHeight() + window_padding * 4; // ORCA using 4 instead 2 gives correct toolbar margins while its folded
4485 ImGui::SameLine(window_width); // ORCA use stored window width while folded. This prevents annoying position change on fold/expand button
4486 ImGui::Dummy({ 0, 0 });
4487 imgui.end();
4488 ImGui::PopStyleColor(7);
4489 ImGui::PopStyleVar(2);
4490 return;
4491 }
4492
4493 // data used to properly align items in columns when showing time
4494 std::vector<float> offsets;
4495 std::vector<std::string> labels;
4496 std::vector<std::string> times;
4497 std::string travel_time;
4498 std::vector<std::string> percents;
4499 std::vector<std::string> used_filaments_length;
4500 std::vector<std::string> used_filaments_weight;
4501 std::string travel_percent;
4502 std::string travel_distance;
4503 std::string travel_moves;
4504 std::vector<double> model_used_filaments_m;
4505 std::vector<double> model_used_filaments_g;
4506 double total_model_used_filament_m = 0, total_model_used_filament_g = 0;
4507 std::vector<double> flushed_filaments_m;
4508 std::vector<double> flushed_filaments_g;
4509 double total_flushed_filament_m = 0, total_flushed_filament_g = 0;
4510 std::vector<double> wipe_tower_used_filaments_m;
4511 std::vector<double> wipe_tower_used_filaments_g;
4512 double total_wipe_tower_used_filament_m = 0, total_wipe_tower_used_filament_g = 0;
4513 std::vector<double> support_used_filaments_m;
4514 std::vector<double> support_used_filaments_g;
4515 double total_support_used_filament_m = 0, total_support_used_filament_g = 0;
4516 struct ColumnData {
4517 enum {
4518 Model = 1,
4519 Flushed = 2,
4520 WipeTower = 4,
4521 Support = 1 << 3,
4522 };
4523 };
4524 int displayed_columns = 0;
4525 std::map<std::string, float> color_print_offsets;
4526 const PrintStatistics& ps = wxGetApp().plater()->get_partplate_list().get_current_fff_print().print_statistics();
4527 double koef = imperial_units ? GizmoObjectManipulation::in_to_mm : 1000.0;
4528 double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1;
4529 std::vector<double> used_filaments_m;
4530 std::vector<double> used_filaments_g;
4531
4532 // used filament statistics
4533 for (size_t extruder_id : m_viewer.get_used_extruders_ids()) {
4534 if (m_print_statistics.model_volumes_per_extruder.find(extruder_id) == m_print_statistics.model_volumes_per_extruder.end()) {
4535 model_used_filaments_m.push_back(0.0);
4536 model_used_filaments_g.push_back(0.0);
4537 }
4538 else {
4539 double volume = m_print_statistics.model_volumes_per_extruder.at(extruder_id);
4540 auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4541 model_used_filaments_m.push_back(model_used_filament_m);
4542 model_used_filaments_g.push_back(model_used_filament_g);
4543 total_model_used_filament_m += model_used_filament_m;
4544 total_model_used_filament_g += model_used_filament_g;
4545 displayed_columns |= ColumnData::Model;
4546 }
4547 }
4548
4549 for (size_t extruder_id : m_viewer.get_used_extruders_ids()) {
4550 if (m_print_statistics.wipe_tower_volumes_per_extruder.find(extruder_id) == m_print_statistics.wipe_tower_volumes_per_extruder.end()) {
4551 wipe_tower_used_filaments_m.push_back(0.0);
4552 wipe_tower_used_filaments_g.push_back(0.0);
4553 }
4554 else {
4555 double volume = m_print_statistics.wipe_tower_volumes_per_extruder.at(extruder_id);
4556 auto [wipe_tower_used_filament_m, wipe_tower_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4557 wipe_tower_used_filaments_m.push_back(wipe_tower_used_filament_m);
4558 wipe_tower_used_filaments_g.push_back(wipe_tower_used_filament_g);
4559 total_wipe_tower_used_filament_m += wipe_tower_used_filament_m;
4560 total_wipe_tower_used_filament_g += wipe_tower_used_filament_g;
4561 displayed_columns |= ColumnData::WipeTower;
4562 }
4563 }
4564
4565 for (size_t extruder_id : m_viewer.get_used_extruders_ids()) {
4566 if (m_print_statistics.flush_per_filament.find(extruder_id) == m_print_statistics.flush_per_filament.end()) {
4567 flushed_filaments_m.push_back(0.0);
4568 flushed_filaments_g.push_back(0.0);
4569 }
4570 else {
4571 double volume = m_print_statistics.flush_per_filament.at(extruder_id);
4572 auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4573 flushed_filaments_m.push_back(flushed_filament_m);
4574 flushed_filaments_g.push_back(flushed_filament_g);
4575 total_flushed_filament_m += flushed_filament_m;
4576 total_flushed_filament_g += flushed_filament_g;
4577 displayed_columns |= ColumnData::Flushed;
4578 }
4579 }
4580
4581 for (size_t extruder_id : m_viewer.get_used_extruders_ids()) {
4582 if (m_print_statistics.support_volumes_per_extruder.find(extruder_id) == m_print_statistics.support_volumes_per_extruder.end()) {
4583 support_used_filaments_m.push_back(0.0);
4584 support_used_filaments_g.push_back(0.0);
4585 }
4586 else {
4587 double volume = m_print_statistics.support_volumes_per_extruder.at(extruder_id);
4588 auto [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4589 support_used_filaments_m.push_back(used_filament_m);
4590 support_used_filaments_g.push_back(used_filament_g);
4591 total_support_used_filament_m += used_filament_m;
4592 total_support_used_filament_g += used_filament_g;
4593 displayed_columns |= ColumnData::Support;
4594 }
4595 }
4596
4597
4598 // extrusion paths section -> title
4599 ImGui::Dummy({ window_padding, window_padding });
4600 ImGui::SameLine();
4601 switch (curr_view_type)
4602 {
4604 {
4605 // calculate offsets to align time/percentage data
4606 char buffer[64];
4607 const std::vector<libvgcode::EGCodeExtrusionRole>& roles = m_viewer.get_extrusion_roles();
4608 for (libvgcode::EGCodeExtrusionRole role : roles) {
4609 assert(static_cast<size_t>(role) < libvgcode::GCODE_EXTRUSION_ROLES_COUNT);
4610 if (static_cast<size_t>(role) < libvgcode::GCODE_EXTRUSION_ROLES_COUNT) {
4611 labels.push_back(_u8L(ExtrusionEntity::role_to_string(convert(role))));
4612 auto [time, percent] = role_time_and_percent(role);
4613 times.push_back((time > 0.0f) ? short_time(get_time_dhms(time)) : "");
4614 if (percent == 0) // ORCA remove % symbol from rows
4615 ::sprintf(buffer, "0");
4616 else
4617 percent > 0.001 ? ::sprintf(buffer, "%.1f", percent * 100) : ::sprintf(buffer, "<0.1");
4618 percents.push_back(buffer);
4619
4620 auto [model_used_filament_m, model_used_filament_g] = used_filament_per_role(convert(role));
4621 ::sprintf(buffer, imperial_units ? "%.2fin" : "%.2fm", model_used_filament_m); // ORCA dont use spacing between value and unit
4622 used_filaments_length.push_back(buffer);
4623 used_filaments_weight.push_back(format_compact_weight(model_used_filament_g, imperial_units));
4624 }
4625 }
4626
4627 //BBS: get travel time and percent
4628 {
4629 auto [time, percent] = travel_time_and_percent();
4630 travel_time = (time > 0.0f) ? short_time(get_time_dhms(time)) : "";
4631 if (percent == 0) // ORCA remove % symbol from rows
4632 ::sprintf(buffer, "0");
4633 else
4634 percent > 0.001 ? ::sprintf(buffer, "%.1f", percent * 100) : ::sprintf(buffer, "<0.1");
4635 travel_percent = buffer;
4636 percents.push_back(travel_percent);
4637
4638 // Set travel distance and moves for the Travel row Usage columns
4639 travel_distance = format_distance(m_print_statistics.total_travel_distance);
4640 used_filaments_length.push_back(travel_distance);
4641
4642 travel_moves = format_compact_count(m_print_statistics.total_travel_moves);
4643 used_filaments_weight.push_back(travel_moves);
4644 }
4645
4646 // ORCA use % symbol for percentage and use "Usage" for "Used filaments"
4647 offsets = calculate_offsets({ {_u8L("Line Type"), labels}, {_u8L("Time"), times}, {"%", percents}, {"", used_filaments_length}, {"", used_filaments_weight}, {_u8L("Display"), {""}}}, icon_size);
4648 percents.pop_back();
4649 append_headers({{_u8L("Line Type"), offsets[0]}, {_u8L("Time"), offsets[1]}, {"%", offsets[2]}, {_u8L("Usage"), offsets[3]}, {_u8L("Display"), offsets[5]}});
4650 break;
4651 }
4652 case libvgcode::EViewType::Height: { imgui.title(_u8L("Layer height (mm)")); break; }
4653 case libvgcode::EViewType::Width: { imgui.title(_u8L("Line width (mm)")); break; }
4655 {
4656 imgui.title(_u8L("Speed (mm/s)"));
4657 break;
4658 }
4660 {
4661 imgui.title(_u8L("Actual Speed (mm/s)"));
4662 break;
4663 }
4665 {
4666 imgui.title(_u8L("Acceleration (mm/s²)"));
4667 break;
4668 }
4670 {
4671 imgui.title(_u8L("Jerk (mm/s)"));
4672 break;
4673 }
4674 case libvgcode::EViewType::FanSpeed: { imgui.title(_u8L("Fan speed (%)")); break; }
4675 case libvgcode::EViewType::Temperature: { imgui.title(_u8L("Temperature (℃)")); break; }
4676// ORCA: Add Pressure Advance visualization support
4677 case libvgcode::EViewType::PressureAdvance:{ imgui.title(_u8L("Pressure Advance")); break; }
4679 { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; }
4681 { imgui.title(_u8L("Actual volumetric flow rate (mm³/s)")); break; }
4683 { imgui.title(_u8L("Layer Time")); break; }
4685 { imgui.title(_u8L("Layer Time (log)")); break; }
4686
4688 {
4689 // calculate used filaments data
4690 const size_t extruders_count = get_extruders_count();
4691 used_filaments_m = std::vector<double>(extruders_count, 0.0);
4692 used_filaments_g = std::vector<double>(extruders_count, 0.0);
4693 const std::vector<uint8_t>& used_extruders_ids = m_viewer.get_used_extruders_ids();
4694 for (uint8_t extruder_id : used_extruders_ids) {
4695 if (m_print_statistics.model_volumes_per_extruder.find(extruder_id) == m_print_statistics.model_volumes_per_extruder.end())
4696 continue;
4697 double volume = m_print_statistics.model_volumes_per_extruder.at(extruder_id);
4698
4699 auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4700 model_used_filaments_m.push_back(model_used_filament_m);
4701 model_used_filaments_g.push_back(model_used_filament_g);
4702 }
4703
4704 offsets = calculate_offsets({ { "Extruder NNN", {""}}}, icon_size);
4705 append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Usage"), offsets[1]} });
4706 break;
4707 }
4709 {
4710 std::vector<std::string> total_filaments;
4711 char buffer[64];
4712 const std::string total_weight_text = format_compact_weight(ps.total_weight, imperial_units);
4713 ::sprintf(buffer, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", ps.total_used_filament / /*1000*/koef, total_weight_text.c_str());
4714 total_filaments.push_back(buffer);
4715
4716
4717 std::vector<std::pair<std::string, std::vector<std::string>>> title_columns;
4718 if (displayed_columns & ColumnData::Model) {
4719 title_columns.push_back({ _u8L("Filament"), {""} });
4720 title_columns.push_back({ _u8L("Model"), total_filaments });
4721 }
4722 if (displayed_columns & ColumnData::Support) {
4723 title_columns.push_back({ _u8L("Support"), total_filaments });
4724 }
4725 if (displayed_columns & ColumnData::Flushed) {
4726 title_columns.push_back({ _u8L("Flushed"), total_filaments });
4727 }
4728 if (displayed_columns & ColumnData::WipeTower) {
4729 title_columns.push_back({ _u8L("Tower"), total_filaments });
4730 }
4731 if ((displayed_columns & ~ColumnData::Model) > 0) {
4732 title_columns.push_back({ _u8L("Total"), total_filaments });
4733 }
4734 title_columns.push_back({ _u8L("Display"), {""}}); // ORCA Add spacing for eye icon. used as color_print_offsets[_u8L("Display")]
4735 auto offsets_ = calculate_offsets(title_columns, icon_size);
4736 std::vector<std::pair<std::string, float>> title_offsets;
4737 for (int i = 0; i < offsets_.size(); i++) {
4738 title_offsets.push_back({ title_columns[i].first, offsets_[i] });
4739 color_print_offsets[title_columns[i].first] = offsets_[i];
4740 }
4741 append_headers(title_offsets);
4742
4743 break;
4744 }
4745 default: { break; }
4746 }
4747
4748 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) {
4749 const bool full_layout = offsets.size() > 4;
4750 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> {
4751 libvgcode::EMoveType move_type;
4752 bool has_move_type = true;
4753 switch (option_type) {
4754 case libvgcode::EOptionType::Wipes: { move_type = libvgcode::EMoveType::Wipe; break; }
4757 case libvgcode::EOptionType::Seams: { move_type = libvgcode::EMoveType::Seam; break; }
4759 default: { has_move_type = false; break; }
4760 }
4761
4762 if (!has_move_type)
4763 return { "", "", "", "" };
4764
4765 const size_t move_type_idx = static_cast<size_t>(move_type);
4766 float time = m_move_type_times[move_type_idx][current_time_mode];
4767 if (option_type == libvgcode::EOptionType::ToolChanges) {
4768 // Toolchange delays are injected via synchronize() and are not attributed to ToolChange move vertices.
4769 time = m_print_statistics.total_filament_load_time + m_print_statistics.total_filament_unload_time + m_print_statistics.total_tool_change_time;
4770 }
4771 const std::string time_text = full_layout && time > 0.0f ? short_time(get_time_dhms(time)) : "";
4772 const std::string percent_text = full_layout && total_estimated_time > 0.0f ? format_percent(time / total_estimated_time) : "";
4773 const float seam_distance = m_print_statistics.total_seam_gap_distance + m_print_statistics.total_seam_scarf_distance;
4774 const float distance = (option_type == libvgcode::EOptionType::Seams && seam_distance > 0.0f) ? seam_distance : m_move_type_distances[move_type_idx];
4775 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)
4776 ? format_distance(distance)
4777 : "";
4778 const std::string count_text = full_layout ? format_compact_count(m_move_type_counts[move_type_idx]) : "";
4779
4780 return { time_text, percent_text, distance_text, count_text };
4781 };
4782
4783 auto append_option_item_with_type = [this, offsets, append_item, full_layout](libvgcode::EOptionType type, const ColorRGBA& color, const std::string& label, bool visible,
4784 const std::string& time_text, const std::string& percent_text, const std::string& distance_text, const std::string& count_text) {
4785 std::vector<std::pair<std::string, float>> columns_offsets;
4786 columns_offsets.push_back({ label , offsets[0] });
4787 if (full_layout && !time_text.empty())
4788 columns_offsets.push_back({ time_text, offsets[1] });
4789 if (full_layout && !percent_text.empty())
4790 columns_offsets.push_back({ percent_text, offsets[2] });
4791 if (full_layout && !distance_text.empty())
4792 columns_offsets.push_back({ distance_text, offsets[3] });
4793 if (full_layout && !count_text.empty())
4794 columns_offsets.push_back({ count_text, distance_text.empty() ? offsets[3] : offsets[4] });
4795 append_item(EItemType::Rect, color, columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type]() {
4796 m_viewer.toggle_option_visibility(type);
4797 update_moves_slider();
4798 });
4799 };
4800 const bool visible = m_viewer.is_option_visible(type);
4801 if (type == libvgcode::EOptionType::Travels) {
4802 //BBS: only display travel time in FeatureType view
4803 append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), _u8L("Travel"), visible, "", "", "", "");
4804 }
4805 else if (type == libvgcode::EOptionType::Seams) {
4806 const auto option_values = option_stats(type);
4807 append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Seams)), _u8L("Seams"), visible,
4808 option_values[0], option_values[1], option_values[2], option_values[3]);
4809 }
4810 else if (type == libvgcode::EOptionType::Retractions) {
4811 const auto option_values = option_stats(type);
4812 append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Retractions)), _u8L("Retract"), visible,
4813 option_values[0], option_values[1], option_values[2], option_values[3]);
4814 }
4815 else if (type == libvgcode::EOptionType::Unretractions) {
4816 const auto option_values = option_stats(type);
4817 append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Unretractions)), _u8L("Unretract"), visible,
4818 option_values[0], option_values[1], option_values[2], option_values[3]);
4819 }
4820 else if (type == libvgcode::EOptionType::ToolChanges) {
4821 const auto option_values = option_stats(type);
4822 append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::ToolChanges)), _u8L("Filament changes"), visible,
4823 option_values[0], option_values[1], option_values[2], option_values[3]);
4824 }
4825 else if (type == libvgcode::EOptionType::Wipes) {
4826 const auto option_values = option_stats(type);
4827 append_option_item_with_type(type, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Wipes)), _u8L("Wipe"), visible,
4828 option_values[0], option_values[1], option_values[2], option_values[3]);
4829 }
4830 };
4831
4832 const libvgcode::EViewType new_view_type = curr_view_type;
4833
4834 // extrusion paths section -> items
4835 switch (new_view_type)
4836 {
4838 {
4839 auto roles = m_viewer.get_extrusion_roles();
4840 for (size_t i = 0; i < roles.size(); ++i) {
4841 libvgcode::EGCodeExtrusionRole role = roles[i];
4843 continue;
4844 const bool visible = m_viewer.is_extrusion_role_visible(role);
4845 std::vector<std::pair<std::string, float>> columns_offsets;
4846 columns_offsets.push_back({ labels[i], offsets[0] });
4847 columns_offsets.push_back({ times[i], offsets[1] });
4848 columns_offsets.push_back({percents[i], offsets[2]});
4849 columns_offsets.push_back({used_filaments_length[i], offsets[3]});
4850 columns_offsets.push_back({used_filaments_weight[i], offsets[4]});
4851 append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_extrusion_role_color(role)), columns_offsets,
4852 true, offsets.back(), visible, [this, role]() {
4853 m_viewer.toggle_extrusion_role_visibility(role);
4854 update_moves_slider();
4855 });
4856 }
4857
4858 auto options = m_viewer.get_options();
4859 for(auto item : options) {
4860 if (item != libvgcode::EOptionType::Travels) {
4861 append_option_item(item, offsets);
4862 } else {
4863 //BBS: show travel time in FeatureType view
4864 const bool visible = m_viewer.is_option_visible(item);
4865 std::vector<std::pair<std::string, float>> columns_offsets;
4866 columns_offsets.push_back({ _u8L("Travel"), offsets[0] });
4867 columns_offsets.push_back({ travel_time, offsets[1] });
4868 columns_offsets.push_back({ travel_percent, offsets[2] });
4869 columns_offsets.push_back({ travel_distance, offsets[3] }); // Usage column
4870 columns_offsets.push_back({ travel_moves, offsets[4] }); // Usage column
4871 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]() {
4872 m_viewer.toggle_option_visibility(item);
4873 update_moves_slider();
4874 });
4875 }
4876 }
4877 break;
4878 }
4879 case libvgcode::EViewType::Height: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Height), 2); break; }
4880 case libvgcode::EViewType::Width: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Width), 2); break; }
4882 append_range(m_viewer.get_color_range(libvgcode::EViewType::Speed), 0);
4883 ImGui::Spacing();
4884 ImGui::Dummy({ window_padding, window_padding });
4885 ImGui::SameLine();
4886 offsets = calculate_offsets({ { _u8L("Options"), { _u8L("Travel")}}, { _u8L("Display"), {""}} }, icon_size);
4887 append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
4888 const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
4889 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4890 append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
4891 m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
4892 // refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result));
4894 });
4895 ImGui::PopStyleVar(1);
4896 break;
4897 }
4899 append_range(m_viewer.get_color_range(libvgcode::EViewType::ActualSpeed), 0);
4900 ImGui::Spacing();
4901 ImGui::Dummy({ window_padding, window_padding });
4902 ImGui::SameLine();
4903 offsets = calculate_offsets({ { _u8L("Options"), { _u8L("Travel")}}, { _u8L("Display"), {""}} }, icon_size);
4904 append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
4905 const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
4906 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4907 append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
4908 m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
4909 // refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result));
4911 });
4912 ImGui::PopStyleVar(1);
4913 break;
4914 }
4916 append_range(m_viewer.get_color_range(libvgcode::EViewType::Acceleration), 0);
4917 ImGui::Spacing();
4918 ImGui::Dummy({ window_padding, window_padding });
4919 ImGui::SameLine();
4920 offsets = calculate_offsets({ { _u8L("Options"), { _u8L("Travel")}}, { _u8L("Display"), {""}} }, icon_size);
4921 append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
4922 const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
4923 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4924 append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
4925 m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
4927 });
4928 ImGui::PopStyleVar(1);
4929 break;
4930 }
4932 append_range(m_viewer.get_color_range(libvgcode::EViewType::Jerk), 1);
4933 ImGui::Spacing();
4934 ImGui::Dummy({ window_padding, window_padding });
4935 ImGui::SameLine();
4936 offsets = calculate_offsets({ { _u8L("Options"), { _u8L("Travel")}}, { _u8L("Display"), {""}} }, icon_size);
4937 append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
4938 const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
4939 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4940 append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this]() {
4941 m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
4943 });
4944 ImGui::PopStyleVar(1);
4945 break;
4946 }
4947 case libvgcode::EViewType::FanSpeed: { append_range(m_viewer.get_color_range(libvgcode::EViewType::FanSpeed), 0); break; }
4948 case libvgcode::EViewType::Temperature: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Temperature), 0); break; }
4949// ORCA: Add Pressure Advance visualization support
4950 case libvgcode::EViewType::PressureAdvance: { append_range(m_viewer.get_color_range(libvgcode::EViewType::PressureAdvance), 3); break; }
4951 case libvgcode::EViewType::LayerTimeLinear: { append_range(m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLinear), true); break; }
4952 case libvgcode::EViewType::LayerTimeLogarithmic: { append_range(m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLogarithmic), true); break; }
4953 case libvgcode::EViewType::VolumetricFlowRate: { append_range(m_viewer.get_color_range(libvgcode::EViewType::VolumetricFlowRate), 2); break; }
4956 {
4957 // shows only extruders actually used
4958 char buf[64];
4959 size_t i = 0;
4960 const std::vector<uint8_t>& used_extruders_ids = m_viewer.get_used_extruders_ids();
4961 for (uint8_t extruder_id : used_extruders_ids) {
4962 const std::string weight_text = format_compact_weight(model_used_filaments_g[i], imperial_units);
4963 ::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m[i], weight_text.c_str());
4964 append_item(EItemType::Rect, shown_filament_color(libvgcode::convert(m_viewer.get_tool_colors()[extruder_id])), { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} });
4965 // append_item(EItemType::Rect, libvgcode::convert(m_viewer.get_tool_colors()[extruder_id]), _u8L("Extruder") + " " + std::to_string(extruder_id + 1),
4966 // true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]);
4967 i++;
4968 }
4969 break;
4970 }
4972 {
4973 char buf[64];
4974 imgui.text(_u8L("Total") + ":");
4975 ImGui::SameLine();
4976 const std::string total_weight_text = format_compact_weight(ps.total_weight, imperial_units);
4977 ::sprintf(buf, imperial_units ? "%.2f in / %s" : "%.2f m / %s", ps.total_used_filament / koef, total_weight_text.c_str());
4978 imgui.text(buf);
4979
4980 ImGui::Dummy({window_padding, window_padding});
4981 ImGui::SameLine();
4982 imgui.text(_u8L("Cost") + ":");
4983 ImGui::SameLine();
4984 ::sprintf(buf, "%.2f", ps.total_cost);
4985 imgui.text(buf);
4986
4987 ImGui::Dummy({window_padding, window_padding});
4988 ImGui::SameLine();
4989 imgui.text(_u8L("Total time") + ":");
4990 ImGui::SameLine();
4991 imgui.text(short_time(get_time_dhms(time_mode.time)));
4992 break;
4993 }
4995 //BBS: replace model custom gcode with current plate custom gcode
4996 const std::vector<CustomGCode::Item>& custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes : m_custom_gcode_per_print_z;
4997 size_t total_items = 1;
4998 // BBS: no ColorChange type, use ToolChange
4999 //const std::vector<uint8_t>& used_extruders_ids = m_viewer.get_used_extruders_ids();
5000 //for (uint8_t extruder_id : used_extruders_ids) {
5001 // total_items += color_print_ranges(extruder_id, custom_gcode_per_print_z).size();
5002 //}
5003
5004 const bool need_scrollable = static_cast<float>(total_items) * (icon_size + ImGui::GetStyle().ItemSpacing.y) > child_height;
5005
5006 // add scrollable region, if needed
5007 if (need_scrollable)
5008 ImGui::BeginChild("color_prints", { -1.0f, child_height }, false);
5009
5010 // shows only extruders actually used
5011 size_t i = 0;
5012 const std::vector<uint8_t>& used_extruders_ids = m_viewer.get_used_extruders_ids();
5013 auto tool_colors = m_viewer.get_tool_colors();
5014 for (auto extruder_idx : used_extruders_ids) {
5015 if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) {
5016 std::vector<std::pair<std::string, float>> columns_offsets;
5017 columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[_u8L("Filament")]});
5018
5019 char buf[64];
5020 float column_sum_m = 0.0f;
5021 float column_sum_g = 0.0f;
5022 if (displayed_columns & ColumnData::Model) {
5023 const std::string weight_text = format_compact_weight(model_used_filaments_g[i], imperial_units);
5024 if ((displayed_columns & ~ColumnData::Model) > 0)
5025 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", model_used_filaments_m[i], weight_text.c_str());
5026 else
5027 ::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m[i], weight_text.c_str());
5028 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Model")] });
5029 column_sum_m += model_used_filaments_m[i];
5030 column_sum_g += model_used_filaments_g[i];
5031 }
5032 if (displayed_columns & ColumnData::Support) {
5033 const std::string weight_text = format_compact_weight(support_used_filaments_g[i], imperial_units);
5034 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", support_used_filaments_m[i], weight_text.c_str());
5035 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Support")] });
5036 column_sum_m += support_used_filaments_m[i];
5037 column_sum_g += support_used_filaments_g[i];
5038 }
5039 if (displayed_columns & ColumnData::Flushed) {
5040 const std::string weight_text = format_compact_weight(flushed_filaments_g[i], imperial_units);
5041 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", flushed_filaments_m[i], weight_text.c_str());
5042 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Flushed")]});
5043 column_sum_m += flushed_filaments_m[i];
5044 column_sum_g += flushed_filaments_g[i];
5045 }
5046 if (displayed_columns & ColumnData::WipeTower) {
5047 const std::string weight_text = format_compact_weight(wipe_tower_used_filaments_g[i], imperial_units);
5048 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", wipe_tower_used_filaments_m[i], weight_text.c_str());
5049 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Tower")] });
5050 column_sum_m += wipe_tower_used_filaments_m[i];
5051 column_sum_g += wipe_tower_used_filaments_g[i];
5052 }
5053 if ((displayed_columns & ~ColumnData::Model) > 0) {
5054 const std::string weight_text = format_compact_weight(column_sum_g, imperial_units);
5055 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", column_sum_m, weight_text.c_str());
5056 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Total")] });
5057 }
5058
5059 float checkbox_pos = std::max(predictable_icon_pos, color_print_offsets[_u8L("Display")]); // ORCA prefer predictable_icon_pos when header not reacing end
5060 append_item(EItemType::Rect, shown_filament_color(libvgcode::convert(tool_colors[extruder_idx])), columns_offsets, false, checkbox_pos/*ORCA*/, true, []() {});
5061 }
5062 i++;
5063 }
5064
5065 if (need_scrollable)
5066 ImGui::EndChild();
5067
5068 // Sum of all rows
5069 char buf[64];
5070 if (used_extruders_ids.size() > 1) {
5071 // Separator
5072 ImGuiWindow* window = ImGui::GetCurrentWindow();
5073 const ImRect separator(ImVec2(window->Pos.x + window_padding * 3, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x - window_padding * 3, window->DC.CursorPos.y + 1.0f));
5074 ImGui::ItemSize(ImVec2(0.0f, 0.0f));
5075 const bool item_visible = ImGui::ItemAdd(separator, 0);
5076 window->DrawList->AddLine(separator.Min, ImVec2(separator.Max.x, separator.Min.y), ImGui::GetColorU32(ImGuiCol_Separator));
5077
5078 std::vector<std::pair<std::string, float>> columns_offsets;
5079 columns_offsets.push_back({ _u8L("Total"), color_print_offsets[_u8L("Filament")]});
5080 if (displayed_columns & ColumnData::Model) {
5081 const std::string weight_text = format_compact_weight(total_model_used_filament_g, imperial_units);
5082 if ((displayed_columns & ~ColumnData::Model) > 0)
5083 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_model_used_filament_m, weight_text.c_str());
5084 else
5085 ::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", total_model_used_filament_m, weight_text.c_str());
5086 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Model")] });
5087 }
5088 if (displayed_columns & ColumnData::Support) {
5089 const std::string weight_text = format_compact_weight(total_support_used_filament_g, imperial_units);
5090 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_support_used_filament_m, weight_text.c_str());
5091 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Support")] });
5092 }
5093 if (displayed_columns & ColumnData::Flushed) {
5094 const std::string weight_text = format_compact_weight(total_flushed_filament_g, imperial_units);
5095 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_flushed_filament_m, weight_text.c_str());
5096 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Flushed")] });
5097 }
5098 if (displayed_columns & ColumnData::WipeTower) {
5099 const std::string weight_text = format_compact_weight(total_wipe_tower_used_filament_g, imperial_units);
5100 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_wipe_tower_used_filament_m, weight_text.c_str());
5101 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Tower")] });
5102 }
5103 if ((displayed_columns & ~ColumnData::Model) > 0) {
5104 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);
5105 ::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,
5106 weight_text.c_str());
5107 columns_offsets.push_back({ buf, color_print_offsets[_u8L("Total")] });
5108 }
5109 append_item(EItemType::None, libvgcode::convert(tool_colors[0]), columns_offsets);
5110 }
5111
5112 //BBS display filament change times
5113 ImGui::Dummy({window_padding, window_padding});
5114 ImGui::SameLine();
5115 imgui.text(_u8L("Filament change times") + ":");
5116 ImGui::SameLine();
5117 imgui.text(format_compact_count(m_print_statistics.total_filament_changes));
5118
5119 //display tool change times
5120 ImGui::Dummy({window_padding, window_padding});
5121 ImGui::SameLine();
5122 imgui.text(_u8L("Tool changes") + ":");
5123 ImGui::SameLine();
5124 imgui.text(format_compact_count(m_print_statistics.total_extruder_changes));
5125
5126 //BBS display cost
5127 ImGui::Dummy({ window_padding, window_padding });
5128 ImGui::SameLine();
5129 imgui.text(_u8L("Cost")+":");
5130 ImGui::SameLine();
5131 ::sprintf(buf, "%.2f", ps.total_cost);
5132 imgui.text(buf);
5133
5134 break;
5135 }
5136 default: { break; }
5137 }
5138
5139 // partial estimated printing time section
5140 if (new_view_type == libvgcode::EViewType::ColorPrint) {
5141 using Times = std::pair<float, float>;
5142 using TimesList = std::vector<std::pair<CustomGCode::Type, Times>>;
5143
5144 // helper structure containig the data needed to render the time items
5145 struct PartialTime
5146 {
5147 enum class EType : unsigned char
5148 {
5149 Print,
5151 Pause
5152 };
5153 EType type;
5154 int extruder_id;
5155 ColorRGBA color1;
5156 ColorRGBA color2;
5157 Times times;
5158 std::pair<double, double> used_filament {0.0f, 0.0f};
5159 };
5160 using PartialTimes = std::vector<PartialTime>;
5161
5162 auto generate_partial_times = [this, get_used_filament_from_volume](const TimesList& times, const std::vector<double>& used_filaments) {
5163 PartialTimes items;
5164
5165 //BBS: replace model custom gcode with current plate custom gcode
5166 std::vector<CustomGCode::Item> custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes : m_custom_gcode_per_print_z;
5167 const size_t extruders_count = get_extruders_count();
5168 std::vector<ColorRGBA> last_color(extruders_count);
5169 for (size_t i = 0; i < extruders_count; ++i) {
5170 last_color[i] = shown_filament_color(libvgcode::convert(m_viewer.get_tool_colors()[i]));
5171 }
5172 int last_extruder_id = 1;
5173 int color_change_idx = 0;
5174 for (const auto& time_rec : times) {
5175 switch (time_rec.first)
5176 {
5178 auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
5179 if (it != custom_gcode_per_print_z.end()) {
5180 items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], ColorRGBA::BLACK(), time_rec.second });
5181 items.push_back({ PartialTime::EType::Pause, it->extruder, ColorRGBA::BLACK(), ColorRGBA::BLACK(), time_rec.second });
5182 custom_gcode_per_print_z.erase(it);
5183 }
5184 break;
5185 }
5187 auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
5188 if (it != custom_gcode_per_print_z.end()) {
5189 items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], it->extruder - 1) });
5190 ColorRGBA color;
5191 decode_color(it->color, color);
5192 color = shown_filament_color(color);
5193 items.push_back({ PartialTime::EType::ColorChange, it->extruder, last_color[it->extruder - 1], color, time_rec.second });
5194 last_color[it->extruder - 1] = color;
5195 last_extruder_id = it->extruder;
5196 custom_gcode_per_print_z.erase(it);
5197 }
5198 else
5199 items.push_back({ PartialTime::EType::Print, last_extruder_id, last_color[last_extruder_id - 1], ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], last_extruder_id - 1) });
5200
5201 break;
5202 }
5203 default: { break; }
5204 }
5205 }
5206
5207 return items;
5208 };
5209
5210 auto append_color_change = [&imgui](const ColorRGBA& color1, const ColorRGBA& color2, const std::array<float, 4>& offsets, const Times& times) {
5211 imgui.text(_u8L("Color change"));
5212 ImGui::SameLine();
5213
5214 float icon_size = ImGui::GetTextLineHeight();
5215 ImDrawList* draw_list = ImGui::GetWindowDrawList();
5216 ImVec2 pos = ImGui::GetCursorScreenPos();
5217 pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
5218
5219 add_swatch(draw_list, { pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f }, color1);
5220 pos.x += icon_size;
5221 add_swatch(draw_list, { pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f }, color2);
5222
5223 ImGui::SameLine(offsets[0]);
5224 imgui.text(short_time(get_time_dhms(times.second - times.first)));
5225 };
5226
5227 auto append_print = [&imgui, imperial_units](const ColorRGBA& color, const std::array<float, 4>& offsets, const Times& times, std::pair<double, double> used_filament) {
5228 imgui.text(_u8L_CONTEXT("Print", "Noun"));
5229 ImGui::SameLine();
5230
5231 float icon_size = ImGui::GetTextLineHeight();
5232 ImDrawList* draw_list = ImGui::GetWindowDrawList();
5233 ImVec2 pos = ImGui::GetCursorScreenPos();
5234 pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
5235
5236 add_swatch(draw_list, { pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f }, color);
5237
5238 ImGui::SameLine(offsets[0]);
5239 imgui.text(short_time(get_time_dhms(times.second)));
5240 ImGui::SameLine(offsets[1]);
5241 imgui.text(short_time(get_time_dhms(times.first)));
5242 if (used_filament.first > 0.0f) {
5243 char buffer[64];
5244 ImGui::SameLine(offsets[2]);
5245 ::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", used_filament.first);
5246 imgui.text(buffer);
5247
5248 ImGui::SameLine(offsets[3]);
5249 imgui.text(format_compact_weight(used_filament.second, imperial_units));
5250 }
5251 };
5252
5253 PartialTimes partial_times = generate_partial_times(time_mode.custom_gcode_times, m_print_statistics.volumes_per_color_change);
5254 if (!partial_times.empty()) {
5255 labels.clear();
5256 times.clear();
5257
5258 for (const PartialTime& item : partial_times) {
5259 switch (item.type)
5260 {
5261 case PartialTime::EType::Print: { labels.push_back(_u8L_CONTEXT("Print", "Noun")); break; }
5262 case PartialTime::EType::Pause: { labels.push_back(_u8L("Pause")); break; }
5263 case PartialTime::EType::ColorChange: { labels.push_back(_u8L("Color change")); break; }
5264 }
5265 times.push_back(short_time(get_time_dhms(item.times.second)));
5266 }
5267
5268 std::string longest_used_filament_string;
5269 for (const PartialTime& item : partial_times) {
5270 if (item.used_filament.first > 0.0f) {
5271 char buffer[64];
5272 ::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", item.used_filament.first);
5273 if (::strlen(buffer) > longest_used_filament_string.length())
5274 longest_used_filament_string = buffer;
5275 }
5276 }
5277
5278 //offsets = calculate_offsets(labels, times, { _u8L("Event"), _u8L("Remaining time"), _u8L("Duration"), longest_used_filament_string }, 2.0f * icon_size);
5279
5280 //ImGui::Spacing();
5281 //append_headers({ _u8L("Event"), _u8L("Remaining time"), _u8L("Duration"), _u8L("Used filament") }, offsets);
5282 //const bool need_scrollable = static_cast<float>(partial_times.size()) * (icon_size + ImGui::GetStyle().ItemSpacing.y) > child_height;
5283 //if (need_scrollable)
5284 // // add scrollable region
5285 // ImGui::BeginChild("events", { -1.0f, child_height }, false);
5286
5287 //for (const PartialTime& item : partial_times) {
5288 // switch (item.type)
5289 // {
5290 // case PartialTime::EType::Print: {
5291 // append_print(item.color1, offsets, item.times, item.used_filament);
5292 // break;
5293 // }
5294 // case PartialTime::EType::Pause: {
5295 // imgui.text(_u8L("Pause"));
5296 // ImGui::SameLine(offsets[0]);
5297 // imgui.text(short_time(get_time_dhms(item.times.second - item.times.first)));
5298 // break;
5299 // }
5300 // case PartialTime::EType::ColorChange: {
5301 // append_color_change(item.color1, item.color2, offsets, item.times);
5302 // break;
5303 // }
5304 // }
5305 //}
5306
5307 //if (need_scrollable)
5308 // ImGui::EndChild();
5309 }
5310 }
5311
5312 // travel paths section
5313 if (m_viewer.is_option_visible(libvgcode::EOptionType::Travels)) {
5314 switch (m_viewer.get_view_type())
5315 {
5322 break;
5323 }
5324 default: {
5325 // BBS GUI:refactor
5326 // title
5327 //ImGui::Spacing();
5328 //imgui.title(_u8L("Travel"));
5330 //append_item(EItemType::Line, Travel_Colors[0], _u8L("Movement"));
5331 //append_item(EItemType::Line, Travel_Colors[1], _u8L("Extrusion"));
5332 //append_item(EItemType::Line, Travel_Colors[2], _u8L("Retraction"));
5333
5334 break;
5335 }
5336 }
5337 }
5338
5339 // wipe paths section
5340 //if (m_buffers[buffer_id(EMoveType::Wipe)].visible) {
5341 // switch (m_view_type)
5342 // {
5343 // case EViewType::Feedrate:
5344 // case EViewType::Tool:
5345 // case EViewType::ColorPrint: { break; }
5346 // default: {
5347 // // title
5348 // ImGui::Spacing();
5349 // ImGui::Dummy({ window_padding, window_padding });
5350 // ImGui::SameLine();
5351 // imgui.title(_u8L("Wipe"));
5352
5353 // // items
5354 // append_item(EItemType::Line, Wipe_Color, { {_u8L("Wipe"), 0} });
5355
5356 // break;
5357 // }
5358 // }
5359 //}
5360
5361 //auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
5362 // const TBuffer& buffer = m_buffers[buffer_id(move_type)];
5363 // if (buffer.visible && buffer.has_data())
5364 // append_item(EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
5365 //};
5366
5367 /* BBS GUI refactor */
5368 // options section
5369 //if (any_option_available()) {
5370 // // title
5371 // ImGui::Spacing();
5372 // imgui.title(_u8L("Options"));
5373
5374 // // items
5375 // add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions"));
5376 // add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions"));
5377 // add_option(EMoveType::Seam, EOptionsColors::Seams, _u8L("Seams"));
5378 // add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes"));
5379 // add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes"));
5380 // add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses"));
5381 // add_option(EMoveType::Custom_GCode, EOptionsColors::CustomGCodes, _u8L("Custom G-codes"));
5382 //}
5383
5384
5385 // settings section
5386 bool has_settings = false;
5387 has_settings |= !m_settings_ids.print.empty();
5388 has_settings |= !m_settings_ids.printer.empty();
5389 bool has_filament_settings = true;
5390 has_filament_settings &= !m_settings_ids.filament.empty();
5391 for (const std::string& fs : m_settings_ids.filament) {
5392 has_filament_settings &= !fs.empty();
5393 }
5394 has_settings |= has_filament_settings;
5395 //BBS: add only gcode mode
5396 bool show_settings = m_only_gcode_in_preview; //wxGetApp().is_gcode_viewer();
5397 show_settings &= (new_view_type == libvgcode::EViewType::FeatureType || new_view_type == libvgcode::EViewType::Tool);
5398 show_settings &= has_settings;
5399 if (show_settings) {
5400 auto calc_offset = [this]() {
5401 float ret = 0.0f;
5402 if (!m_settings_ids.printer.empty())
5403 ret = std::max(ret, ImGui::CalcTextSize((_u8L("Printer") + std::string(":")).c_str()).x);
5404 if (!m_settings_ids.print.empty())
5405 ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x);
5406 if (!m_settings_ids.filament.empty()) {
5407 for (unsigned char i : m_viewer.get_used_extruders_ids()) {
5408 ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x);
5409 }
5410 }
5411 if (ret > 0.0f)
5412 ret += 2.0f * ImGui::GetStyle().ItemSpacing.x;
5413 return ret;
5414 };
5415
5416 ImGui::Spacing();
5417 imgui.title(_u8L("Settings"));
5418
5419 float offset = calc_offset();
5420
5421 if (!m_settings_ids.printer.empty()) {
5422 imgui.text(_u8L("Printer") + ":");
5423 ImGui::SameLine(offset);
5424 imgui.text(m_settings_ids.printer);
5425 }
5426 if (!m_settings_ids.print.empty()) {
5427 imgui.text(_u8L("Print settings") + ":");
5428 ImGui::SameLine(offset);
5429 imgui.text(m_settings_ids.print);
5430 }
5431 if (!m_settings_ids.filament.empty()) {
5432 for (unsigned char i : m_viewer.get_used_extruders_ids()) {
5433 if (i < static_cast<unsigned char>(m_settings_ids.filament.size()) && !m_settings_ids.filament[i].empty()) {
5434 std::string txt = _u8L("Filament");
5435 txt += (m_viewer.get_used_extruders_count() == 1) ? ":" : " " + std::to_string(i + 1);
5436 imgui.text(txt);
5437 ImGui::SameLine(offset);
5438 imgui.text(m_settings_ids.filament[i]);
5439 }
5440 }
5441 }
5442 }
5443 // Custom G-code overview
5444 std::vector<CustomGCode::Item> custom_gcode_per_print_z = wxGetApp().is_editor() ?
5445 wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes :
5447 if (custom_gcode_per_print_z.size() != 0) {
5448 float max_len = window_padding + 2 * ImGui::GetStyle().ItemSpacing.x;
5449 ImGui::Spacing();
5450 // Title Line
5451 std::string cgcode_title_str = _u8L("Custom G-code");
5452 std::string cgcode_layer_str = _u8L("Layer");
5453 std::string cgcode_time_str = _u8L("Time");
5454 // Types of custom gcode
5455 std::string cgcode_pause_str = _u8L("Pause");
5456 std::string cgcode_template_str= _u8L("Template");
5457 std::string cgcode_toolchange_str = _u8L("Tool Change");
5458 std::string cgcode_custom_str = _u8L("Custom");
5459 std::string cgcode_unknown_str = _u8L("Unknown");
5460
5461 // Get longest String
5462 max_len += std::max(ImGui::CalcTextSize(cgcode_title_str.c_str()).x,
5463 std::max(ImGui::CalcTextSize(cgcode_pause_str.c_str()).x,
5464 std::max(ImGui::CalcTextSize(cgcode_template_str.c_str()).x,
5465 std::max(ImGui::CalcTextSize(cgcode_toolchange_str.c_str()).x,
5466 std::max(ImGui::CalcTextSize(cgcode_custom_str.c_str()).x,
5467 ImGui::CalcTextSize(cgcode_unknown_str.c_str()).x))))
5468
5469 );
5470
5471 ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
5472 ImGui::Dummy({window_padding, window_padding});
5473 ImGui::SameLine();
5474 imgui.title(cgcode_title_str,true);
5475 ImGui::SameLine(max_len);
5476 imgui.title(cgcode_layer_str, true);
5477 ImGui::SameLine(max_len*1.5);
5478 imgui.title(cgcode_time_str, false);
5479
5480 // ORCA: Get layer Zs as doubles
5481 std::vector<double> layer_zs = get_layers_zs();
5482 // loop invariant, same reason as the layer Zs above
5483 const std::vector<float> layer_times = m_viewer.get_layers_estimated_times();
5484
5485 for (Slic3r::CustomGCode::Item custom_gcode : custom_gcode_per_print_z) {
5486 ImGui::Dummy({window_padding, window_padding});
5487 ImGui::SameLine();
5488
5489 switch (custom_gcode.type) {
5490 case CustomGCode::PausePrint: imgui.text(cgcode_pause_str); break;
5491 case CustomGCode::Template: imgui.text(cgcode_template_str); break;
5492 case CustomGCode::ToolChange: imgui.text(cgcode_toolchange_str); break;
5493 case CustomGCode::Custom: imgui.text(cgcode_custom_str); break;
5494 default: imgui.text(cgcode_unknown_str); break;
5495 }
5496 ImGui::SameLine(max_len);
5497 char buf[64];
5498 int layer = find_close_layer_idx(layer_zs, custom_gcode.print_z, epsilon()); // ORCA: find layer index by Z
5499 ::sprintf(buf, "%d", layer + 1); // +1 because layer 0 is the first layer
5500 imgui.text(buf);
5501 ImGui::SameLine(max_len * 1.5);
5502
5503 float custom_gcode_time = 0;
5504 if (layer > 0)
5505 {
5506 for (int i = 0; i < layer; i++) { // sum all previous layers time
5507 custom_gcode_time += layer_times[i];
5508 }
5509 }
5510 imgui.text(short_time(get_time_dhms(custom_gcode_time)));
5511
5512 }
5513 }
5514
5515
5516 // total estimated printing time section
5517 ImGui::Spacing();
5518 std::string time_title = m_viewer.get_view_type() == libvgcode::EViewType::FeatureType ? _u8L("Total estimation") : _u8L("Time Estimation");
5519 auto can_show_mode_button = [this](libvgcode::ETimeMode mode) {
5520 std::vector<std::string> time_strs;
5521 for (size_t i = 0; i < m_print_statistics.modes.size(); ++i) {
5522 if (m_print_statistics.modes[i].time > 0.0f) {
5523 const std::string time_str = short_time(get_time_dhms(m_print_statistics.modes[i].time));
5524 const auto it = std::find(time_strs.begin(), time_strs.end(), time_str);
5525 if (it == time_strs.end())
5526 time_strs.emplace_back(time_str);
5527 }
5528 }
5529 return time_strs.size() > 1;
5530 };
5531
5532 const libvgcode::ETimeMode time_mode_id = m_viewer.get_time_mode();
5533 if (can_show_mode_button(time_mode_id)) {
5534 switch (time_mode_id)
5535 {
5536 case libvgcode::ETimeMode::Normal: { time_title += " [" + _u8L("Normal mode") + "]"; break; }
5537 default: { assert(false); break; }
5538 }
5539 }
5540 ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
5541 ImGui::Dummy({ window_padding, window_padding });
5542 ImGui::SameLine();
5543 imgui.title(time_title);
5544 std::string total_filament_str = _u8L("Total Filament");
5545 std::string model_filament_str = _u8L("Model Filament");
5546 std::string cost_str = _u8L("Cost");
5547 std::string prepare_str = _u8L("Prepare time");
5548 std::string print_str = _u8L("Model printing time");
5549 std::string total_str = _u8L("Total time");
5550 float max_len = window_padding + 2 * ImGui::GetStyle().ItemSpacing.x;
5551 if (m_viewer.get_layers_count() == 0)
5552 max_len += ImGui::CalcTextSize(total_str.c_str()).x;
5553 else {
5554 if (m_viewer.get_view_type() == libvgcode::EViewType::FeatureType)
5555 max_len += std::max(ImGui::CalcTextSize(cost_str.c_str()).x,
5556 std::max(ImGui::CalcTextSize(print_str.c_str()).x,
5557 std::max(std::max(ImGui::CalcTextSize(prepare_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x),
5558 std::max(ImGui::CalcTextSize(total_filament_str.c_str()).x, ImGui::CalcTextSize(model_filament_str.c_str()).x))));
5559 else
5560 max_len += std::max(ImGui::CalcTextSize(print_str.c_str()).x,
5561 (std::max(ImGui::CalcTextSize(prepare_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x)));
5562 }
5563 if (m_viewer.get_view_type() == libvgcode::EViewType::FeatureType) {
5564 //BBS display filament cost
5565 ImGui::Dummy({ window_padding, window_padding });
5566 ImGui::SameLine();
5567 imgui.text(total_filament_str + ":");
5568 ImGui::SameLine(max_len);
5569 //BBS: use current plater's print statistics
5570 bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
5571 char buf[64];
5572 ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / koef);
5573 imgui.text(buf);
5574 ImGui::SameLine();
5575 imgui.text(" " + format_compact_weight(ps.total_weight, imperial_units));
5576 ImGui::Dummy({ window_padding, window_padding });
5577 ImGui::SameLine();
5578 imgui.text(model_filament_str + ":");
5579 ImGui::SameLine(max_len);
5580 auto exlude_m = total_support_used_filament_m + total_flushed_filament_m + total_wipe_tower_used_filament_m;
5581 auto exlude_g = total_support_used_filament_g + total_flushed_filament_g + total_wipe_tower_used_filament_g;
5582 ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / koef - exlude_m);
5583 imgui.text(buf);
5584 ImGui::SameLine();
5585 imgui.text(" " + format_compact_weight(ps.total_weight - exlude_g, imperial_units));
5586 //BBS: display cost of filaments
5587 ImGui::Dummy({ window_padding, window_padding });
5588 ImGui::SameLine();
5589 imgui.text(cost_str + ":");
5590 ImGui::SameLine(max_len);
5591 ::sprintf(buf, "%.2f", ps.total_cost);
5592 imgui.text(buf);
5593 }
5594 //BBS: start gcode is mostly same with prepeare time
5595 if (time_mode.prepare_time != 0.0f) {
5596 ImGui::Dummy({ window_padding, window_padding });
5597 ImGui::SameLine();
5598 imgui.text(prepare_str + ":");
5599 ImGui::SameLine(max_len);
5600 imgui.text(short_time(get_time_dhms(time_mode.prepare_time)));
5601 }
5602 ImGui::Dummy({ window_padding, window_padding });
5603 ImGui::SameLine();
5604 imgui.text(print_str + ":");
5605 ImGui::SameLine(max_len);
5606 imgui.text(short_time(get_time_dhms(time_mode.time - time_mode.prepare_time)));
5607 ImGui::Dummy({ window_padding, window_padding });
5608 ImGui::SameLine();
5609 imgui.text(total_str + ":");
5610 ImGui::SameLine(max_len);
5611 imgui.text(short_time(get_time_dhms(time_mode.time)));
5612
5613 auto show_mode_button = [this, &imgui, can_show_mode_button](const std::string& label, libvgcode::ETimeMode mode) {
5614 if (can_show_mode_button(mode)) {
5615 if (imgui.button(label)) {
5616 m_viewer.set_time_mode(mode);
5617#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
5618 imgui.set_requires_extra_frame();
5619#else
5620 wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
5621 wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
5622#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
5623 }
5624 }
5625 };
5626
5627 switch (time_mode_id) {
5629 show_mode_button(_u8L("Show stealth mode"), libvgcode::ETimeMode::Stealth);
5630 break;
5631 }
5633 show_mode_button(_u8L("Show normal mode"), libvgcode::ETimeMode::Normal);
5634 break;
5635 }
5636 default : { assert(false); break; }
5637 }
5638
5639 if (m_viewer.get_view_type() == libvgcode::EViewType::ColorPrint) {
5640 ImGui::Spacing();
5641 ImGui::Dummy({ window_padding, window_padding });
5642 ImGui::SameLine();
5643 offsets = calculate_offsets({ { _u8L("Options"), { ""}}, { _u8L("Display"), {""}} }, icon_size);
5644 offsets[1] = std::max(predictable_icon_pos, color_print_offsets[_u8L("Display")]); // ORCA prefer predictable_icon_pos when header not reacing end
5645 append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
5646 for (auto item : m_viewer.get_options())
5647 append_option_item(item, offsets);
5648 }
5649 ImGui::Dummy({ window_padding, window_padding });
5650 if (m_nozzle_nums > 1 && (m_viewer.get_view_type() == libvgcode::EViewType::Summary || m_viewer.get_view_type() == libvgcode::EViewType::ColorPrint)) // ORCA show only on summary and filament tab
5651 render_legend_color_arr_recommen(window_padding);
5652
5653
5654 legend_height = ImGui::GetCurrentWindow()->Size.y;
5655 imgui.end();
5656 ImGui::PopStyleColor(7);
5657 ImGui::PopStyleVar(2);
5658}
struct IMGUI_API ImRect
Definition IMSlider.hpp:19
static const ColorRGBA BLACK()
Definition Color.hpp:127
static std::string role_to_string(ExtrusionRole role)
Definition ExtrusionEntity.cpp:673
static std::string view_type_to_config_name(libvgcode::EViewType type)
Definition GCodeViewer.cpp:1236
bool m_fold
Definition GCodeViewer.hpp:238
size_t get_extruders_count()
Definition GCodeViewer.hpp:529
bool is_legend_shown() const
Definition GCodeViewer.hpp:517
std::vector< std::string > view_type_items_str
Definition GCodeViewer.hpp:345
std::vector< libvgcode::EViewType > view_type_items
Definition GCodeViewer.hpp:344
void set_view_type(libvgcode::EViewType type)
Definition GCodeViewer.hpp:479
void update_moves_slider(bool set_to_max=false)
Definition GCodeViewer.cpp:2715
int m_view_type_sel
Definition GCodeViewer.hpp:346
void push_combo_style()
Definition GCodeViewer.cpp:5660
void pop_combo_style()
Definition GCodeViewer.cpp:5674
ColorRGBA shown_filament_color(ColorRGBA color) const
Definition GCodeViewer.cpp:3251
void render_legend_color_arr_recommen(float window_padding)
Definition GCodeViewer.cpp:3796
void reset_visible(libvgcode::EViewType type)
Definition GCodeViewer.hpp:492
std::vector< double > get_layers_zs() const
Definition GCodeViewer.hpp:438
static const double oz_to_g
Definition GizmoObjectManipulation.hpp:33
static ImU32 to_ImU32(const ColorRGBA &color)
Definition ImGuiWrapper.cpp:2239
@ PausePrint
Definition CustomGCode.hpp:20
@ ToolChange
Definition CustomGCode.hpp:21
@ Template
Definition CustomGCode.hpp:22
@ Custom
Definition CustomGCode.hpp:23
@ ColorChange
Definition CustomGCode.hpp:19
static int find_close_layer_idx(const std::vector< double > &zs, double &z, double eps)
Definition GCodeViewer.cpp:208
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:36
std::string into_u8(const wxString &str)
Definition GUI.cpp:549
@ None
Definition DesignOffer.hpp:25
constexpr double epsilon()
Definition IMSlider.hpp:31
static wxColour decode_color(const std::string &color)
Definition SliceInfoPanel.cpp:51
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:19
static CustomGCode::Info custom_gcode_per_print_z
Definition ToolOrdering.cpp:3253
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
auto range(Cont &&cont)
Definition libslic3r.h:405
@ Hexagon
Definition Model.hpp:279
@ Circle
Definition BuildVolume.hpp:25
EMoveType
Definition Types.hpp:121
@ ToolChange
Definition Types.hpp:126
@ Wipe
Definition Types.hpp:131
@ Seam
Definition Types.hpp:125
EGCodeExtrusionRole
Definition Types.hpp:142
@ COUNT
Definition Types.hpp:166
EOptionType
Definition Types.hpp:175
@ ToolChanges
Definition Types.hpp:183
@ Wipes
Definition Types.hpp:179
@ Seams
Definition Types.hpp:182
@ Unretractions
Definition Types.hpp:181
@ Travels
Definition Types.hpp:178
@ Retractions
Definition Types.hpp:180
static constexpr std::size_t GCODE_EXTRUSION_ROLES_COUNT
Definition Types.hpp:169
ETimeMode
Definition Types.hpp:200
@ Stealth
Definition Types.hpp:202
@ Summary
Definition Types.hpp:92
@ Width
Definition Types.hpp:98
@ Acceleration
Definition Types.hpp:108
@ Speed
Definition Types.hpp:95
@ ActualVolumetricFlowRate
Definition Types.hpp:100
@ LayerTimeLogarithmic
Definition Types.hpp:102
@ PressureAdvance
Definition Types.hpp:106
@ ActualSpeed
Definition Types.hpp:96
@ Jerk
Definition Types.hpp:110
@ LayerTimeLinear
Definition Types.hpp:101
@ Tool
Definition Types.hpp:111
@ FanSpeed
Definition Types.hpp:103
@ VolumetricFlowRate
Definition Types.hpp:99
@ Temperature
Definition Types.hpp:104
@ Height
Definition Types.hpp:97
#define _u8L_CONTEXT(s, ctx)
Definition I18N.hpp:16
std::vector< Item > gcodes
Definition CustomGCode.hpp:71

References Slic3r::GUI::add_swatch(), Slic3r::GUI::ImGuiWrapper::begin(), Slic3r::center(), libvgcode::ColorPrint, libvgcode::convert(), Slic3r::PrintEstimatedStatistics::Mode::custom_gcode_times, libvgcode::FeatureType, Slic3r::GUI::Size::get_height(), Slic3r::Hexagon, Slic3r::GUI::into_u8(), is_legend_shown(), libvgcode::LayerTimeLinear, libvgcode::LayerTimeLogarithmic, m_print_statistics, m_scale, m_viewer, Slic3r::GUI::None, Slic3r::range(), Slic3r::GUI::ImGuiWrapper::set_next_window_pos(), Slic3r::GUI::ImGuiWrapper::text(), Slic3r::PrintEstimatedStatistics::Mode::time, and Slic3r::GUI::ImGuiWrapper::to_ImU32().

Referenced by render_overlay().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_legend_color_arr_recommen()

void Slic3r::GUI::GCodeViewer::render_legend_color_arr_recommen ( float window_padding)
private
3797{
3798 ImGuiWrapper &imgui = *wxGetApp().imgui();
3799
3800 auto link_text = [&](const std::string &label) {
3801 ImVec2 wiki_part_size = ImGui::CalcTextSize(label.c_str());
3802
3803 ImColor HyperColor = ImColor(0, 150, 136, 255).Value;
3804 ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
3805 imgui.text(label.c_str());
3806 ImGui::PopStyleColor();
3807
3808 // underline
3809 ImVec2 lineEnd = ImGui::GetItemRectMax();
3810 lineEnd.y -= 2.0f;
3811 ImVec2 lineStart = lineEnd;
3812 lineStart.x = ImGui::GetItemRectMin().x;
3813 ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, HyperColor);
3814 // click behavior
3815 if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) {
3816 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
3817 Plater *plater = wxGetApp().plater();
3818 wxCommandEvent evt(EVT_OPEN_FILAMENT_MAP_SETTINGS_DIALOG);
3819 evt.SetEventObject(plater);
3820 evt.SetInt(1); // 1 means from gcode viewer
3821 wxPostEvent(plater, evt);
3822 }
3823 }
3824 };
3825
3826 auto link_text_set_to_optional = [&](const std::string &label) {
3827 ImVec2 wiki_part_size = ImGui::CalcTextSize(label.c_str());
3828
3829 ImColor HyperColor = ImColor(0, 150, 136, 255).Value;
3830 ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
3831 imgui.text(label.c_str());
3832 ImGui::PopStyleColor();
3833 // underline
3834 ImVec2 lineEnd = ImGui::GetItemRectMax();
3835 lineEnd.y -= 2.0f;
3836 ImVec2 lineStart = lineEnd;
3837 lineStart.x = ImGui::GetItemRectMin().x;
3838 ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, HyperColor);
3839 // click behavior
3840 if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) {
3841 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
3842 MessageDialog msg_dlg(nullptr, _L("Automatically re-slice according to the optimal filament grouping, and the grouping results will be displayed after slicing."), wxEmptyString, wxOK | wxCANCEL);
3843 if (msg_dlg.ShowModal() == wxID_OK) {
3844 PartPlateList &partplate_list = wxGetApp().plater()->get_partplate_list();
3845 PartPlate *plate = partplate_list.get_curr_plate();
3846 plate->set_filament_map_mode(FilamentMapMode::fmmAutoForFlush);
3847 Plater *plater = wxGetApp().plater();
3848 wxPostEvent(plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE));
3849 }
3850 }
3851 }
3852 };
3853
3854 auto draw_dash_line = [&](ImDrawList* draw_list, int dash_length = 5, int gap_length = 3) {
3855 ImVec2 p1 = ImGui::GetCursorScreenPos();
3856 ImVec2 p2 = ImVec2(p1.x + ImGui::GetContentRegionAvail().x, p1.y);
3857 for (float i = p1.x; i < p2.x; i += (dash_length + gap_length)) {
3858 draw_list->AddLine(ImVec2(i, p1.y), ImVec2(i + dash_length, p1.y), ImGui::GetColorU32(ImVec4(1.0f,1.0f,1.0f,0.6f))); // ORCA match color
3859 }
3860 };
3861
3863
3864 auto config = wxGetApp().plater()->get_partplate_list().get_current_fff_print().config();
3865 auto stats_by_extruder = wxGetApp().plater()->get_partplate_list().get_current_fff_print().statistics_by_extruder();
3866
3867 float delta_weight_to_single_ext = stats_by_extruder.stats_by_single_extruder.filament_flush_weight - stats_by_extruder.stats_by_multi_extruder_curr.filament_flush_weight;
3868 float delta_weight_to_best = stats_by_extruder.stats_by_multi_extruder_curr.filament_flush_weight - stats_by_extruder.stats_by_multi_extruder_best.filament_flush_weight;
3869 // The displayed "hand changes" delta uses the per-nozzle flush_filament_change_count.
3870 // For single-nozzle-per-extruder printers it equals the per-extruder filament_change_count,
3871 // so the shown value is unchanged.
3872 int delta_change_to_single_ext = stats_by_extruder.stats_by_single_extruder.flush_filament_change_count - stats_by_extruder.stats_by_multi_extruder_curr.flush_filament_change_count;
3873 int delta_change_to_best = stats_by_extruder.stats_by_multi_extruder_curr.flush_filament_change_count - stats_by_extruder.stats_by_multi_extruder_best.flush_filament_change_count;
3874
3875 bool any_less_to_single_ext = delta_weight_to_single_ext > EPSILON || delta_change_to_single_ext > 0;
3876 bool any_more_to_best = delta_weight_to_best > EPSILON || delta_change_to_best > 0;
3877 bool all_less_to_single_ext = delta_weight_to_single_ext > EPSILON && delta_change_to_single_ext > 0;
3878 bool all_more_to_best = delta_weight_to_best > EPSILON && delta_change_to_best > 0;
3879
3880 auto get_filament_display_type = [](const ExtruderFilament& filament) {
3881 if (filament.is_support_filament && (filament.type == "PLA" || filament.type == "PA" || filament.type == "ABS"))
3882 return "Sup." + filament.type;
3883 return filament.type;
3884 };
3885
3886
3887 // BBS AMS containers
3888 float line_height = ImGui::GetFrameHeight();
3889 float ams_item_height = 0;
3890 float filament_group_item_align_width = 0;
3891 {
3892 float three_words_width = imgui.calc_text_size("ABC"sv).x;
3893 const int line_capacity = 4;
3894
3895 for (const auto& extruder_filaments : {m_left_extruder_filament,m_right_extruder_filament })
3896 {
3897 float container_height = 0.f;
3898 for (size_t idx = 0; idx < extruder_filaments.size(); idx += line_capacity) {
3899 float text_line_height = 0;
3900 for (int j = idx; j < extruder_filaments.size() && j < idx + line_capacity; ++j) {
3901 auto text_info = imgui.calculate_filament_group_text_size(get_filament_display_type(extruder_filaments[j]));
3902 auto text_size = std::get<0>(text_info);
3903 filament_group_item_align_width = std::max(filament_group_item_align_width, text_size.x);
3904 text_line_height = std::max(text_line_height, text_size.y);
3905 }
3906 container_height += (three_words_width * 1.3f + text_line_height );
3907 }
3908 container_height += 2 * line_height;
3909 ams_item_height = std::max(ams_item_height, container_height);
3910 }
3911 }
3912
3913 int tips_count = 8;
3914 if (any_more_to_best) {
3915 tips_count = 8;
3916 if (wxGetApp().app_config->get("language") != "zh_CN")
3917 tips_count += 1;
3918 }
3919 else if (any_less_to_single_ext) {
3920 tips_count = 6;
3921 if (wxGetApp().app_config->get("language") != "zh_CN")
3922 tips_count += 1;
3923 }
3924 else
3925 tips_count = 5;
3926
3927 float AMS_container_height = ams_item_height + line_height * tips_count + line_height + window_padding * 2.f;
3928 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0)); // this shold be 0 since its child of gcodeviewer
3929 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 1, 1, 1));
3930 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(window_padding * 3, 0));
3931
3932 // ImGui::Dummy({window_padding, window_padding});
3933 ImGui::BeginChild("#AMS", ImVec2(0, AMS_container_height), true, ImGuiWindowFlags_AlwaysUseWindowPadding);
3934 {
3935 float available_width = ImGui::GetContentRegionAvail().x;
3936 float half_width = available_width * 0.49f;
3937 float spacing = 18.0f * m_scale;
3938
3939 ImGui::Dummy({window_padding, window_padding});
3940 ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(1.0f,1.0f,1.0f,0.6f));
3941 imgui.bold_text(_u8L("Filament Grouping"));
3942 ImGui::Separator();
3943 ImGui::PopStyleColor();
3944 ImGui::Dummy({window_padding, window_padding});
3945
3946 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1, 1, 1, 0.05f));
3947 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(window_padding * 2, window_padding));
3948
3949 ImDrawList *child_begin_draw_list = ImGui::GetWindowDrawList();
3950 ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
3951 child_begin_draw_list->AddRectFilled(cursor_pos, ImVec2(cursor_pos.x + half_width, cursor_pos.y + line_height), IM_COL32(255, 255, 255, 10));
3952 ImGui::BeginChild("#LeftAMS", ImVec2(half_width, ams_item_height), false, ImGuiWindowFlags_AlwaysUseWindowPadding);
3953 {
3954 imgui.text(_u8L("Left nozzle"));
3955 ImGui::Dummy({window_padding, window_padding});
3956 int index = 1;
3957 for (const auto &extruder_filament : m_left_extruder_filament) {
3958 imgui.filament_group(get_filament_display_type(extruder_filament), extruder_filament.hex_color.c_str(), extruder_filament.filament_id, filament_group_item_align_width);
3959 if (index % 4 != 0) { ImGui::SameLine(0, spacing); }
3960 index++;
3961 }
3962 ImGui::EndChild();
3963 }
3964 ImGui::SameLine();
3965 cursor_pos = ImGui::GetCursorScreenPos();
3966 child_begin_draw_list->AddRectFilled(cursor_pos, ImVec2(cursor_pos.x + half_width, cursor_pos.y + line_height), IM_COL32(255, 255, 255, 10));
3967 ImGui::BeginChild("#RightAMS", ImVec2(half_width, ams_item_height), false, ImGuiWindowFlags_AlwaysUseWindowPadding);
3968 {
3969 imgui.text(_u8L("Right nozzle"));
3970 ImGui::Dummy({window_padding, window_padding});
3971 int index = 1;
3972 for (const auto &extruder_filament : m_right_extruder_filament) {
3973 imgui.filament_group(get_filament_display_type(extruder_filament), extruder_filament.hex_color.c_str(), extruder_filament.filament_id, filament_group_item_align_width);
3974 if (index % 4 != 0) { ImGui::SameLine(0, spacing); }
3975 index++;
3976 }
3977 ImGui::EndChild();
3978 }
3979 ImGui::PopStyleColor(1);
3980 ImGui::PopStyleVar(1);
3981
3982 ImGui::Dummy({window_padding, window_padding});
3983 imgui.text_wrapped(from_u8(_u8L("Please place filaments on the printer based on grouping result.")), ImGui::GetContentRegionAvail().x);
3984 ImGui::Dummy({window_padding, window_padding});
3985
3986 {
3987 ImDrawList* draw_list = ImGui::GetWindowDrawList();
3988 draw_dash_line(draw_list);
3989 }
3990
3991 bool is_optimal_group = true;
3992 float parent_width = ImGui::GetContentRegionAvail().x;
3993 auto number_format = [](float num) {
3994 if (num > 1000) {
3995 std::string number_str = std::to_string(num);
3996 std::string first_three_digits = number_str.substr(0, 3);
3997 return std::stoi(first_three_digits);
3998 }
3999 return static_cast<int>(num);
4000 };
4001
4002 if (any_more_to_best) {
4003 ImGui::Dummy({window_padding, window_padding});
4004 is_optimal_group = false;
4005 ImVec4 orangeColor = ImVec4(1.0f, 0.5f, 0.0f, 1.0f);
4006 ImGui::PushStyleColor(ImGuiCol_Text, orangeColor);
4007 imgui.text(_u8L("Tips:"));
4008 imgui.text(_u8L("Current grouping of slice result is not optimal."));
4009 wxString tip;
4010 if (delta_weight_to_best >= 0 && delta_change_to_best >= 0)
4011 tip = format_wxstr(_L_PLURAL("Increase %1%g filament and %2% change compared to optimal grouping.",
4012 "Increase %1%g filament and %2% changes compared to optimal grouping.", delta_change_to_best),
4013 number_format(delta_weight_to_best), delta_change_to_best);
4014 else if (delta_weight_to_best >= 0 && delta_change_to_best < 0)
4015 tip = format_wxstr(_L_PLURAL("Increase %1%g filament and save %2% change compared to optimal grouping.",
4016 "Increase %1%g filament and save %2% changes compared to optimal grouping.", std::abs(delta_change_to_best)),
4017 number_format(delta_weight_to_best), std::abs(delta_change_to_best));
4018 else if (delta_weight_to_best < 0 && delta_change_to_best >= 0)
4019 tip = format_wxstr(_L_PLURAL("Save %1%g filament and increase %2% change compared to optimal grouping.",
4020 "Save %1%g filament and increase %2% changes compared to optimal grouping.", delta_change_to_best),
4021 number_format(std::abs(delta_weight_to_best)), delta_change_to_best);
4022
4023 imgui.text_wrapped(tip, parent_width);
4024 ImGui::PopStyleColor(1);
4025 }
4026 else if (any_less_to_single_ext) {
4027 ImGui::Dummy({window_padding, window_padding});
4028 wxString tip;
4029 if (delta_weight_to_single_ext >= 0 && delta_change_to_single_ext >= 0)
4030 tip = format_wxstr(_L_PLURAL("Save %1%g filament and %2% change compared to a printer with one nozzle.",
4031 "Save %1%g filament and %2% changes compared to a printer with one nozzle.", delta_change_to_single_ext),
4032 number_format(delta_weight_to_single_ext), delta_change_to_single_ext);
4033 else if (delta_weight_to_single_ext >= 0 && delta_change_to_single_ext < 0)
4034 tip = format_wxstr(_L_PLURAL("Save %1%g filament and increase %2% change compared to a printer with one nozzle.",
4035 "Save %1%g filament and increase %2% changes compared to a printer with one nozzle.", std::abs(delta_change_to_single_ext)),
4036 number_format(delta_weight_to_single_ext), std::abs(delta_change_to_single_ext));
4037 else if (delta_weight_to_single_ext < 0 && delta_change_to_single_ext >= 0)
4038 tip = format_wxstr(_L_PLURAL("Increase %1%g filament and save %2% change compared to a printer with one nozzle.",
4039 "Increase %1%g filament and save %2% changes compared to a printer with one nozzle.", delta_change_to_single_ext),
4040 number_format(std::abs(delta_weight_to_single_ext)), delta_change_to_single_ext);
4041
4042 imgui.text_wrapped(tip, parent_width);
4043 }
4044
4045 ImGui::Dummy({window_padding, window_padding});
4046 GLGizmoUtils::render_wiki_guide_button(*wxGetApp().plater()->get_current_canvas3D(), m_scale,"https://e.bambulab.com/t?c=mOkvsXkJ9pldGYp9");
4047 ImGui::SameLine();
4048
4049 if (!is_optimal_group) {
4050 link_text_set_to_optional(_u8L("Set to Optimal"));
4051 ImGui::SameLine();
4052 ImGui::Dummy({window_padding, window_padding});
4053 ImGui::SameLine();
4054 }
4055 link_text(_u8L("Regroup filament"));
4056
4057 ImGui::Dummy({window_padding, window_padding});
4058
4059 ImGui::EndChild();
4060 }
4061 ImGui::PopStyleColor(2);
4062 ImGui::PopStyleVar(1);
4063}
#define EPSILON
Definition ColorUtils.cpp:64
Definition GCodeViewer.hpp:184
bool render_wiki_guide_button(const GLCanvas3D &canvas, float scale, const char *url)
Definition GLGizmoUtils.cpp:79
wxString format_wxstr(const char *fmt, TArgs &&... args)
Definition format.hpp:22
@ Plater
Definition Shortcuts.hpp:21
wxString from_u8(const std::string &str)
Definition GUI.cpp:544
@ fmmAutoForFlush
Definition PrintConfig.hpp:633
#define _L_PLURAL(s, plural, n)
Definition I18N.hpp:96

References _L, _L_PLURAL, _u8L, Slic3r::GUI::ImGuiWrapper::bold_text(), Slic3r::GUI::ImGuiWrapper::calc_text_size(), Slic3r::GUI::ImGuiWrapper::calculate_filament_group_text_size(), EPSILON, Slic3r::GUI::ImGuiWrapper::filament_group(), Slic3r::fmmAutoForFlush, Slic3r::GUI::format_wxstr(), Slic3r::GUI::from_u8(), Slic3r::GUI::PartPlateList::get_curr_plate(), m_left_extruder_filament, m_right_extruder_filament, m_scale, Slic3r::GUI::plater(), Slic3r::GUI::GLGizmoUtils::render_wiki_guide_button(), Slic3r::GUI::PartPlate::set_filament_map_mode(), Slic3r::GUI::DPIAware< P >::ShowModal(), Slic3r::GUI::ImGuiWrapper::text(), and Slic3r::GUI::ImGuiWrapper::text_wrapped().

Here is the call graph for this function:

◆ render_markers()

void Slic3r::GUI::GCodeViewer::render_markers ( int canvas_width,
int canvas_height )
private
2227{
2228 auto current = m_viewer.get_view_visible_range();
2229 auto endpoints = m_viewer.get_view_full_range();
2230 m_sequential_view.m_show_marker = m_sequential_view.m_show_marker || (current.back() != endpoints.back() && !m_no_render_path);
2231 const libvgcode::PathVertex& curr_vertex = m_viewer.get_current_vertex();
2232 m_sequential_view.marker.set_world_position(libvgcode::convert(curr_vertex.position));
2233 m_sequential_view.marker.set_z_offset(m_z_offset + 0.5f);
2234
2235 // IDEX/IQEX: compute all carriage positions; update secondary nozzle markers;
2236 // carriage_box_draws is populated for toolhead footprint rendering after render_marker().
2237 // Okabe-Ito colorblind-safe palette — excludes orange (#E69F00) and sky blue (#56B4E9)
2238 // which are used by the bed zone fills, ensuring the markers contrast against the background.
2239 // It identifies the carriages in the views that colour by anything but filament; in Filament
2240 // view a carriage takes its own head's filament colour instead, so a marker, the ghost of
2241 // what it prints and the toolpaths under it all agree on what is loaded there.
2242 static const std::array<ColorRGBA, 4> s_carriage_colors = {{
2243 { 1.000f, 1.000f, 1.000f, 0.65f }, // primary — white
2244 { 0.941f, 0.894f, 0.259f, 0.65f }, // secondary 1 — yellow (#F0E442)
2245 { 0.835f, 0.369f, 0.000f, 0.65f }, // secondary 2 — vermilion (#D55E00)
2246 { 0.800f, 0.475f, 0.655f, 0.65f }, // secondary 3 — reddish purple (#CC79A7)
2247 }};
2248 struct CarriageDraw { Vec3f pos; ColorRGBA color; float box_offset_x = 0.0f; float box_offset_y = 0.0f; };
2249 std::vector<CarriageDraw> carriage_box_draws;
2250 float imex_box_wx = 0.0f, imex_box_wy = 0.0f;
2251 {
2252 PresetBundle* preset_bundle = wxGetApp().preset_bundle;
2253 bool imex_active = false;
2254 if (preset_bundle && m_sequential_view.m_show_marker) {
2255 const DynamicPrintConfig& printer_cfg = preset_bundle->printers.get_edited_preset().config;
2256 auto* is_imex_opt = printer_cfg.opt<ConfigOptionBool>("is_imex");
2257 if (is_imex_opt && is_imex_opt->value) {
2258 const DynamicPrintConfig& process_cfg = preset_bundle->prints.get_edited_preset().config;
2259 auto* mode_opt = process_cfg.opt<ConfigOptionString>("imex_parallel_mode");
2260 std::string mode = mode_opt ? mode_opt->value : kImexPrimaryMode;
2261 // Per-plate mode overrides the process preset.
2262 PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
2263 PartPlate* curr_plate = plate_list.get_curr_plate();
2264 if (curr_plate) {
2265 // Same resolution the plate itself uses, rather than a fourth copy of it.
2266 const std::string plate_mode = curr_plate->get_effective_imex_mode();
2267 if (plate_mode != kImexPrimaryMode)
2268 mode = plate_mode;
2269 }
2270
2271 // Bed X and Y bounds — read from the current plate's shape, which is
2272 // in world/GL coordinates (same space as curr_vertex.position), and is
2273 // the exact same source PartPlate::calc_imex_zones() hands to the library.
2274 BoundingBoxf bed_extents;
2275 {
2276 const Pointfs& plate_shape = curr_plate ? curr_plate->get_shape() : Pointfs{};
2277 if (!plate_shape.empty()) {
2278 bed_extents = get_extents(plate_shape);
2279 } else {
2280 // Fallback: use toolpath bounding box extent
2281 bed_extents = BoundingBoxf(Vec2d(m_paths_bounding_box.min.x(), m_paths_bounding_box.min.y()),
2283 }
2284 }
2285
2286 // Cache guard. The marker plan below is resolved from preset/plate state only,
2287 // so it is rebuilt when that state moves and reused otherwise — the sequential
2288 // slider is sticky, and re-resolving the zone layout on every frame of the rest
2289 // of the session showed up as a measurable per-frame cost. The comparison is
2290 // deliberately made against the live config rather than against a freshly built
2291 // key, so an unchanged frame allocates nothing at all.
2292 static const std::vector<std::string> s_no_strings;
2293 auto* names_opt = printer_cfg.opt<ConfigOptionStrings>("imex_mode_names");
2294 auto* tools_opt = printer_cfg.opt<ConfigOptionStrings>("imex_mode_active_tools");
2295 const std::vector<std::string>& mode_names = names_opt ? names_opt->values : s_no_strings;
2296 const std::vector<std::string>& active_tools = tools_opt ? tools_opt->values : s_no_strings;
2297
2299 key.plate_index = plate_list.get_curr_plate_index();
2300 // Same accessor the plan is built from: a key holding a different fallback than
2301 // the value actually laid out would compare equal across a real change.
2302 key.gantry_count = imex_cfg_int(printer_cfg, "imex_gantry_count");
2303 key.tools_per_gantry = imex_cfg_int(printer_cfg, "imex_tools_per_gantry");
2304 key.tool_layout = (int)imex_cfg_enum<ImexToolLayout>(printer_cfg, "imex_tool_layout");
2305 key.clearance_x = imex_cfg_float(printer_cfg, "imex_nozzle_clearance_x");
2306 key.clearance_y = imex_cfg_float(printer_cfg, "imex_nozzle_clearance_y");
2307 key.firmware_managed = imex_cfg_bool(printer_cfg, "imex_firmware_managed_zones");
2308 key.bed_min_x = bed_extents.min.x();
2309 key.bed_min_y = bed_extents.min.y();
2310 key.bed_max_x = bed_extents.max.x();
2311 key.bed_max_y = bed_extents.max.y();
2312
2313 if (!(m_imex_marker_key.s == key) || m_imex_marker_key.mode != mode ||
2314 m_imex_marker_key.mode_names != mode_names ||
2315 m_imex_marker_key.mode_active_tools != active_tools) {
2316 m_imex_marker_key = ImexMarkerKey{ key, mode, mode_names, active_tools };
2317 m_imex_marker_plan = resolve_imex_marker_plan(printer_cfg, mode, bed_extents);
2318 // The carriage roster — and with it the marker count — can change with any
2319 // of those inputs, so drop the markers and let the lazy init below rebuild
2320 // them. Their colours are restamped every frame regardless.
2321 m_sequential_view.m_imex_secondary_markers.clear();
2322 }
2323
2324 const ImexMarkerPlan& plan = m_imex_marker_plan;
2325 const int sec_count = (int)plan.carriages.size();
2326
2327 // Filament view colours the toolpaths by the filament printing them, so a
2328 // carriage takes its own head's filament colour there and the palette
2329 // everywhere else. get_imex_head_filament_color() answers UNPRINTABLE_COLOR
2330 // for a head it cannot resolve, which is alpha 0.5 where a filament colour
2331 // decodes opaque - that difference, not the black, is what distinguishes it,
2332 // and a head with no filament keeps the palette rather than borrowing a
2333 // colour that would read as a real assignment - the one point where a marker
2334 // and the ghost of what it prints differ, the ghost having no palette to fall
2335 // back to.
2336 //
2337 // The map and the pem are hoisted and each head resolved once, as
2338 // PartPlate::update_imex_ghost_colors() does for the ghosts: both the marker
2339 // and the toolhead box of a carriage want the same answer, and rebuilding it
2340 // per draw parses the plate's map string and rebuilds the pem vector.
2341 const bool color_by_filament = m_viewer.get_view_type() == libvgcode::EViewType::ColorPrint;
2342 std::vector<ColorRGBA> carriage_colors(sec_count + 1);
2343 if (sec_count > 0) {
2344 const ConfigOptionInts pem = effective_physical_extruder_map(*preset_bundle);
2345 const auto plate_map = curr_plate ? curr_plate->get_imex_head_filament_map()
2346 : std::map<int, int>{};
2347 std::map<int, ColorRGBA> head_colors;
2348 auto color_for = [&](int phys_head, size_t palette_index) {
2349 const ColorRGBA fallback = s_carriage_colors[palette_index % s_carriage_colors.size()];
2350 if (!color_by_filament || curr_plate == nullptr || phys_head < 0)
2351 return fallback;
2352 auto hc = head_colors.find(phys_head);
2353 if (hc == head_colors.end())
2354 hc = head_colors.emplace(phys_head,
2355 curr_plate->get_imex_head_filament_color(phys_head, pem, plate_map)).first;
2356 if (hc->second == GLVolume::UNPRINTABLE_COLOR)
2357 return fallback;
2358 ColorRGBA c = hc->second;
2359 c.a(fallback.a()); // as translucent as the palette makes them
2360 return c;
2361 };
2362 carriage_colors[0] = color_for(plan.pri_head, 0);
2363 for (int i = 0; i < sec_count; ++i)
2364 carriage_colors[i + 1] = color_for(plan.carriages[i].phys_head, i + 1);
2365 }
2366 if (sec_count > 0) {
2367 imex_active = true;
2368 imex_box_wx = plan.box_wx;
2369 imex_box_wy = plan.box_wy;
2370
2371 // Lazy init secondary nozzle markers
2372 if ((int)m_sequential_view.m_imex_secondary_markers.size() != sec_count) {
2373 m_sequential_view.m_imex_secondary_markers.resize(sec_count);
2374 for (int i = 0; i < sec_count; ++i) {
2375 m_sequential_view.m_imex_secondary_markers[i].init(m_marker_filename);
2376 }
2377 }
2378 // Set every frame, not once at init: the view type and the filament palette
2379 // both change without the marker list being rebuilt. The primary marker is
2380 // one of the carriages here, so it is coloured alongside them - and restored
2381 // below when no mode is active, since it is the same marker every non-IMEX
2382 // preview draws.
2383 m_sequential_view.marker.set_color(carriage_colors[0]);
2384 for (int i = 0; i < sec_count; ++i)
2385 m_sequential_view.m_imex_secondary_markers[i].set_color(carriage_colors[i + 1]);
2386
2387 const Vec3f prim_pos = libvgcode::convert(curr_vertex.position);
2388 carriage_box_draws.push_back({ prim_pos, carriage_colors[0],
2389 plan.pri_box_offset_x, plan.pri_box_offset_y });
2390
2391 for (int i = 0; i < sec_count; ++i) {
2392 const ImexMarkerPlan::Carriage& carriage = plan.carriages[i];
2393 // Tracking an axis translates the primary by the gap between the two
2394 // zone centres; mirroring reflects it about the midpoint of those
2395 // centres — the zones being equal-sized, that midpoint is the boundary
2396 // between them, so the carriage still lands inside its own zone. Which
2397 // axis does which, and both terms, come from resolve_imex_marker_plan().
2398 const Vec3f sec_pos{ carriage.mirror_x ? carriage.x_term - prim_pos.x()
2399 : prim_pos.x() + carriage.x_term,
2400 carriage.mirror_y ? carriage.y_term - prim_pos.y()
2401 : prim_pos.y() + carriage.y_term,
2402 prim_pos.z() };
2403 m_sequential_view.m_imex_secondary_markers[i].set_world_position(sec_pos);
2404 m_sequential_view.m_imex_secondary_markers[i].set_z_offset(m_z_offset + 0.5f);
2405 carriage_box_draws.push_back({
2406 sec_pos, carriage_colors[i + 1],
2407 carriage.box_offset_x, carriage.box_offset_y });
2408 }
2409 }
2410 }
2411 }
2412 if (!imex_active) {
2413 m_sequential_view.m_imex_secondary_markers.clear();
2414 // The primary marker is the one every preview draws, so the carriage colour it may
2415 // have been given has to come back off when no parallel mode is active.
2417 }
2418 }
2419 m_sequential_view.render_marker(!m_no_render_path, canvas_width, sequential_view_height(canvas_height), m_viewer.get_view_type());
2420
2421 // IDEX/IQEX: render toolhead footprint boxes for each active carriage.
2422 // Each box is imex_nozzle_clearance_x × imex_nozzle_clearance_y, sitting above the nozzle tip.
2423 // Hidden when the user toggles off "Show IDEX/IQEX Toolhead Boxes" in the View menu — gives
2424 // an unobstructed view of the toolpaths during sequential playback. Default-on; the absence
2425 // of an app_config entry is also treated as on.
2426 const bool show_toolhead_boxes = wxGetApp().app_config->get("show_imex_toolhead_boxes") != "false";
2427 if (show_toolhead_boxes && !carriage_box_draws.empty() && imex_box_wx > 0.0f && imex_box_wy > 0.0f) {
2428 // The mesh depends only on the two clearance dimensions, which a config edit can
2429 // change without a G-code reload — so rebuild it when they move (or when it has not
2430 // been built yet) rather than on every frame.
2431 // Mesh origin: nozzle at x=0, centered in Y, Z starts at nozzle tip level.
2432 // Per-carriage box_offset_x shifts the mesh left or right so the nozzle lands
2433 // at the correct (collision-side) edge.
2434 if (!m_imex_toolhead_box.is_initialized() ||
2435 m_imex_box_mesh_wx != imex_box_wx || m_imex_box_mesh_wy != imex_box_wy) {
2436 const float box_h = std::max(imex_box_wx, imex_box_wy);
2437 indexed_triangle_set its = its_make_cube((double)imex_box_wx, (double)imex_box_wy, (double)box_h);
2438 // No vertex pre-shifting — box_offset_x/y in the per-carriage transform
2439 // positions the nozzle at the correct collision-side edge.
2440 m_imex_toolhead_box.reset();
2441 m_imex_toolhead_box.init_from(its);
2442 m_imex_box_mesh_wx = imex_box_wx;
2443 m_imex_box_mesh_wy = imex_box_wy;
2444 }
2445
2446 GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
2447 if (shader) {
2450 shader->start_using();
2451 shader->set_uniform("emission_factor", 0.0f);
2452 const Camera& camera = wxGetApp().plater()->get_camera();
2453 shader->set_uniform("projection_matrix", camera.get_projection_matrix());
2454 const Transform3d& view_matrix = camera.get_view_matrix();
2455 for (const auto& draw : carriage_box_draws) {
2456 const Transform3d model_matrix = Geometry::translation_transform(
2457 (draw.pos + Vec3f(draw.box_offset_x, draw.box_offset_y, m_z_offset)).cast<double>());
2458 shader->set_uniform("view_model_matrix", view_matrix * model_matrix);
2459 const Matrix3d view_normal_matrix =
2460 view_matrix.matrix().block(0, 0, 3, 3) *
2461 model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
2462 shader->set_uniform("view_normal_matrix", view_normal_matrix);
2463 m_imex_toolhead_box.set_color(draw.color);
2464 m_imex_toolhead_box.render();
2465 }
2466 shader->stop_using();
2468 }
2469 }
2470}
#define glsafe(cmd)
Definition OpenGLUtils.hpp:25
static ColorRGBA UNPRINTABLE_COLOR
Definition 3DScene.hpp:98
static ColorRGBA default_color()
Definition GCodeViewer.hpp:124
GLModel m_imex_toolhead_box
Definition GCodeViewer.hpp:325
ImexMarkerPlan m_imex_marker_plan
Definition GCodeViewer.hpp:320
static ImexMarkerPlan resolve_imex_marker_plan(const DynamicPrintConfig &printer_cfg, const std::string &mode, const BoundingBoxf &bed_extents)
Definition GCodeViewer.cpp:2003
ImexMarkerKey m_imex_marker_key
Definition GCodeViewer.hpp:319
int sequential_view_height(int canvas_height) const
Definition GCodeViewer.cpp:2584
float m_imex_box_mesh_wx
Definition GCodeViewer.hpp:326
float m_imex_box_mesh_wy
Definition GCodeViewer.hpp:327
bool m_no_render_path
Definition GCodeViewer.hpp:366
Definition GCodeViewer.hpp:248
Definition GCodeViewer.hpp:288
#define glEnable
Definition gl.h:3667
#define GL_SRC_ALPHA
Definition gl.h:1621
#define GL_BLEND
Definition gl.h:275
#define GL_ONE_MINUS_SRC_ALPHA
Definition gl.h:1239
#define glDisable
Definition gl.h:3607
#define glBlendFunc
Definition gl.h:3325
@ Camera
Definition Shortcuts.hpp:72
void draw(const IconManager::Icon &icon, const ImVec2 &size, const ImVec4 &tint_col, const ImVec4 &border_col)
Draw imgui image with icon.
Definition IconManager.cpp:373
void translation_transform(Transform3d &transform, const Vec3d &translation)
Definition Geometry.cpp:346
T imex_cfg_enum(const ConfigBase &cfg, const std::string &key)
Definition IMEXHelpers.hpp:386
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:65
bool imex_cfg_bool(const ConfigBase &cfg, const std::string &key)
Definition IMEXHelpers.cpp:282
ConfigOptionInts effective_physical_extruder_map(const ConfigOptionInts *explicit_pem, int nozzle_count)
Definition IMEXHelpers.cpp:52
ConfigOptionIntsTempl< false > ConfigOptionInts
Definition Config.hpp:1154
constexpr const char * kImexPrimaryMode
Definition IMEXHelpers.hpp:27
double imex_cfg_float(const ConfigBase &cfg, const std::string &key)
Definition IMEXHelpers.cpp:295
indexed_triangle_set its_make_cube(double xd, double yd, double zd)
Definition TriangleMesh.cpp:902
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
int imex_cfg_int(const ConfigBase &cfg, const std::string &key)
Definition IMEXHelpers.cpp:269
Eigen::Matrix< double, 3, 3, Eigen::DontAlign > Matrix3d
Definition Point.hpp:86
int plate_index
Definition GCodeViewer.hpp:293

References Slic3r::ColorRGBA::a(), Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::bed_max_x, Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::bed_max_y, Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::bed_min_x, Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::bed_min_y, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::box_offset_x, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::box_offset_y, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::box_wx, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::box_wy, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::carriages, Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::clearance_x, Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::clearance_y, libvgcode::ColorPrint, Slic3r::Preset::config, libvgcode::convert(), Slic3r::GUI::GCodeViewer::SequentialView::Marker::default_color(), Slic3r::GUI::draw(), Slic3r::effective_physical_extruder_map(), Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::firmware_managed, Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::gantry_count, Slic3r::GUI::PartPlateList::get_curr_plate(), Slic3r::GUI::PartPlateList::get_curr_plate_index(), Slic3r::PresetCollection::get_edited_preset(), Slic3r::GUI::PartPlate::get_effective_imex_mode(), Slic3r::get_extents(), Slic3r::GUI::PartPlate::get_imex_head_filament_color(), Slic3r::GUI::PartPlate::get_imex_head_filament_map(), Slic3r::GUI::Camera::get_projection_matrix(), Slic3r::GUI::PartPlate::get_shape(), Slic3r::GUI::Camera::get_view_matrix(), GL_BLEND, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, glBlendFunc, glDisable, glEnable, glsafe, Slic3r::imex_cfg_bool(), Slic3r::imex_cfg_enum(), Slic3r::imex_cfg_float(), Slic3r::imex_cfg_int(), Slic3r::its_make_cube(), Slic3r::kImexPrimaryMode, m_imex_box_mesh_wx, m_imex_box_mesh_wy, m_imex_marker_key, m_imex_marker_plan, m_imex_toolhead_box, m_marker_filename, m_no_render_path, m_paths_bounding_box, m_sequential_view, m_viewer, m_z_offset, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::mirror_x, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::mirror_y, Slic3r::DynamicConfig::opt(), Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::plate_index, libvgcode::PathVertex::position, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::pri_box_offset_x, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::pri_box_offset_y, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::pri_head, Slic3r::PresetBundle::printers, Slic3r::PresetBundle::prints, resolve_imex_marker_plan(), sequential_view_height(), Slic3r::GLShaderProgram::set_uniform(), Slic3r::GLShaderProgram::start_using(), Slic3r::GLShaderProgram::stop_using(), Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::tool_layout, Slic3r::GUI::GCodeViewer::ImexMarkerKey::Scalars::tools_per_gantry, Slic3r::Geometry::translation_transform(), Slic3r::GLVolume::UNPRINTABLE_COLOR, Slic3r::ConfigOptionSingle< T >::value, Slic3r::ConfigOptionVector< T >::values, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::x_term, and Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::y_term.

Referenced by render_scene(), and render_translucent_toolpaths().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_overlay()

void Slic3r::GUI::GCodeViewer::render_overlay ( int canvas_width,
int canvas_height,
int right_margin )
2531{
2532 if (m_viewer.get_extrusion_roles().empty())
2533 return;
2534
2535 float legend_height = 0.0f;
2536 render_legend(legend_height, canvas_width, canvas_height, right_margin);
2537
2538 if (m_user_mode != wxGetApp().get_mode()) {
2539 update_by_mode(wxGetApp().get_mode());
2540 m_user_mode = wxGetApp().get_mode();
2541 }
2542
2543 m_sequential_view.render_overlay(!m_no_render_path, legend_height, &m_viewer, m_viewer.get_current_vertex().gcode_id, canvas_width, sequential_view_height(canvas_height), right_margin * m_scale, m_viewer.get_view_type());
2544
2545#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
2546 if (is_legend_shown()) {
2547 ImGuiWrapper& imgui = *Slic3r::GUI::wxGetApp().imgui();
2548 const Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
2549 ImGuiPureWrap::set_next_window_pos(static_cast<float>(cnv_size.get_width()), static_cast<float>(cnv_size.get_height()), ImGuiCond_Always, 1.0f, 1.0f);
2550 ImGuiPureWrap::begin(std::string("LibVGCode Viewer Controller"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
2551
2552 ImGuiPureWrap::checkbox("Cog marker fixed screen size", m_cog_marker_fixed_screen_size);
2553 if (ImGui::BeginTable("Cog", 2)) {
2554
2555 ImGui::TableNextRow();
2556 ImGui::TableSetColumnIndex(0);
2557 ImGuiPureWrap::text_colored(ImGuiPureWrap::COL_ORANGE_LIGHT, "Cog marker size");
2558 ImGui::TableSetColumnIndex(1);
2559 imgui.slider_float("##CogSize", &m_cog_marker_size, 1.0f, 5.0f);
2560
2561 ImGui::EndTable();
2562 }
2563
2564 ImGuiPureWrap::checkbox("Tool marker fixed screen size", m_tool_marker_fixed_screen_size);
2565 if (ImGui::BeginTable("Tool", 2)) {
2566
2567 ImGui::TableNextRow();
2568 ImGui::TableSetColumnIndex(0);
2569 ImGuiPureWrap::text_colored(ImGuiPureWrap::COL_ORANGE_LIGHT, "Tool marker size");
2570 ImGui::TableSetColumnIndex(1);
2571 imgui.slider_float("##ToolSize", &m_tool_marker_size, 1.0f, 5.0f);
2572
2573 ImGui::EndTable();
2574 }
2575
2576 ImGuiPureWrap::end();
2577 }
2578#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
2579
2580 //BBS render slider
2581 render_slider(canvas_width, canvas_height);
2582}
void render_legend(float &legend_height, int canvas_width, int canvas_height, int right_margin)
Definition GCodeViewer.cpp:4065
void render_slider(int canvas_width, int canvas_height)
Definition GCodeViewer.cpp:5680

References Slic3r::GUI::Size::get_height(), Slic3r::GUI::Size::get_width(), is_legend_shown(), m_no_render_path, m_scale, m_sequential_view, m_user_mode, m_viewer, render_legend(), render_slider(), sequential_view_height(), Slic3r::GUI::ImGuiWrapper::slider_float(), and update_by_mode().

Here is the call graph for this function:

◆ render_scene()

void Slic3r::GUI::GCodeViewer::render_scene ( int canvas_width,
int canvas_height )
2213{
2215 render_shells(canvas_width, canvas_height);
2216
2217 if (m_viewer.get_extrusion_roles_count() == 0)
2218 return;
2219
2221 // ORCA: the markers write depth, which would hide the translucent toolpaths behind them
2222 if (!m_viewer.has_translucent_toolpaths())
2223 render_markers(canvas_width, canvas_height);
2224}
void render_toolpaths()
Definition GCodeViewer.cpp:3270
void render_shells(int canvas_width, int canvas_height)
Definition GCodeViewer.cpp:3452
void render_markers(int canvas_width, int canvas_height)
Definition GCodeViewer.cpp:2226
#define GL_DEPTH_TEST
Definition gl.h:574

References GL_DEPTH_TEST, glEnable, glsafe, m_viewer, render_markers(), render_shells(), and render_toolpaths().

Here is the call graph for this function:

◆ render_shadow_casters()

void Slic3r::GUI::GCodeViewer::render_shadow_casters ( const Transform3d & light_view_matrix,
const Transform3d & light_projection_matrix,
const Vec3d & light_position )
2493{
2494 if (!has_data())
2495 return;
2496
2497 m_viewer.render_shadow_casters(
2498 libvgcode::convert(static_cast<Matrix4f>(light_view_matrix.matrix().cast<float>())),
2499 libvgcode::convert(static_cast<Matrix4f>(light_projection_matrix.matrix().cast<float>())),
2500 libvgcode::convert(static_cast<Vec3f>(light_position.cast<float>())));
2501}
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > Matrix4f
Definition Point.hpp:87

References libvgcode::convert(), has_data(), and m_viewer.

Here is the call graph for this function:

◆ render_shells()

void Slic3r::GUI::GCodeViewer::render_shells ( int canvas_width,
int canvas_height )
private
3453{
3454 //BBS: add shell previewing logic
3455 if ((!m_shells.previewing && !m_shells.visible) || m_shells.volumes.empty())
3456 //if (!m_shells.visible || m_shells.volumes.empty())
3457 return;
3458
3459 GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
3460 if (shader == nullptr)
3461 return;
3462
3464
3465 shader->start_using();
3466 shader->set_uniform("emission_factor", 0.1f);
3467 const Camera& camera = wxGetApp().plater()->get_camera();
3468 shader->set_uniform("z_far", camera.get_far_z());
3469 shader->set_uniform("z_near", camera.get_near_z());
3470 m_shells.volumes.render(GLVolumeCollection::ERenderType::Transparent, false, camera.get_view_matrix(), camera.get_projection_matrix(), {canvas_width, canvas_height});
3471 shader->set_uniform("emission_factor", 0.0f);
3472 shader->stop_using();
3473
3475}
@ Transparent
Definition 3DScene.hpp:422
#define GL_TRUE
Definition gl.h:1892
#define glDepthMask
Definition gl.h:3595
#define GL_FALSE
Definition gl.h:648

References Slic3r::GUI::Camera::get_far_z(), Slic3r::GUI::Camera::get_near_z(), Slic3r::GUI::Camera::get_projection_matrix(), Slic3r::GUI::Camera::get_view_matrix(), GL_FALSE, GL_TRUE, glDepthMask, glsafe, m_shells, Slic3r::GLShaderProgram::set_uniform(), Slic3r::GLShaderProgram::start_using(), Slic3r::GLShaderProgram::stop_using(), and Slic3r::GLVolumeCollection::Transparent.

Referenced by render_scene().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_slider()

void Slic3r::GUI::GCodeViewer::render_slider ( int canvas_width,
int canvas_height )
private
5680 {
5681 m_moves_slider->render(canvas_width, canvas_height);
5682 m_layers_slider->render(canvas_width, canvas_height);
5683}

References m_layers_slider, and m_moves_slider.

Referenced by render_overlay().

Here is the caller graph for this function:

◆ render_toolpaths()

void Slic3r::GUI::GCodeViewer::render_toolpaths ( )
private
3271{
3272 const Camera& camera = wxGetApp().plater()->get_camera();
3273 Matrix4f view = camera.get_view_matrix().matrix().cast<float>();
3274 // Belt "designed" (upright) view is produced by back-transforming the toolpath
3275 // GEOMETRY into model space at load time (see load_as_gcode ->
3276 // compute_belt_back_transform -> libvgcode::convert). The camera is left untouched
3277 // here; transforming the view as well would double-apply the inverse. Baking the
3278 // transform into the geometry (not the camera) also keeps the bed and toolpaths in
3279 // the same frame so they stay aligned.
3280 const libvgcode::Mat4x4 converted_view_matrix = libvgcode::convert(view);
3281 const libvgcode::Mat4x4 converted_projetion_matrix = libvgcode::convert(static_cast<Matrix4f>(camera.get_projection_matrix().matrix().cast<float>()));
3282#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
3283 m_viewer.set_cog_marker_scale_factor(m_cog_marker_fixed_screen_size ? 10.0f * m_cog_marker_size * camera.get_inv_zoom() : m_cog_marker_size);
3284 m_viewer.set_tool_marker_scale_factor(m_tool_marker_fixed_screen_size ? 10.0f * m_tool_marker_size * camera.get_inv_zoom() : m_tool_marker_size);
3285#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
3286 m_viewer.render(converted_view_matrix, converted_projetion_matrix);
3287
3288#if ENABLE_NEW_GCODE_VIEWER_DEBUG
3289 if (is_legend_shown()) {
3290 ImGuiWrapper& imgui = *wxGetApp().imgui();
3291 const Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
3292 imgui.set_next_window_pos(static_cast<float>(cnv_size.get_width()), 0.0f, ImGuiCond_Always, 1.0f, 0.0f);
3293 imgui.begin(std::string("LibVGCode Viewer Debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
3294
3295 if (ImGui::BeginTable("Data", 2)) {
3296 ImGui::TableNextRow();
3297 ImGui::TableSetColumnIndex(0);
3299 ImGui::TableSetColumnIndex(1);
3300 ImGuiWrapper::text(std::to_string(m_viewer.get_vertices_count()));
3301
3302 ImGui::Separator();
3303
3304 ImGui::TableNextRow();
3305 ImGui::TableSetColumnIndex(0);
3307 ImGui::TableSetColumnIndex(1);
3308 ImGuiWrapper::text(format_memsize(m_viewer.get_used_cpu_memory()));
3309
3310 ImGui::TableNextRow();
3311 ImGui::TableSetColumnIndex(0);
3313 ImGui::TableSetColumnIndex(1);
3314 ImGuiWrapper::text(format_memsize(m_viewer.get_used_gpu_memory()));
3315
3316 ImGui::Separator();
3317
3318 ImGui::TableNextRow();
3319 ImGui::TableSetColumnIndex(0);
3321 ImGui::TableSetColumnIndex(1);
3322 const libvgcode::Interval& layers_range = m_viewer.get_layers_view_range();
3323 ImGuiWrapper::text(std::to_string(layers_range[0]) + " - " + std::to_string(layers_range[1]));
3324
3326
3327 ImGui::TableNextRow();
3328 ImGui::TableSetColumnIndex(0);
3330 ImGui::TableSetColumnIndex(1);
3331 const libvgcode::Interval& enabled_view_range = m_viewer.get_view_enabled_range();
3332 ImGuiWrapper::text(std::to_string(enabled_view_range[0]) + " - " + std::to_string(enabled_view_range[1]) + " | " +
3333 std::to_string(m_viewer.get_vertex_at(enabled_view_range[0]).gcode_id) + " - " +
3334 std::to_string(m_viewer.get_vertex_at(enabled_view_range[1]).gcode_id));
3335
3336 ImGui::TableNextRow();
3337 ImGui::TableSetColumnIndex(0);
3339 ImGui::TableSetColumnIndex(1);
3340 const libvgcode::Interval& visible_view_range = m_viewer.get_view_visible_range();
3341 ImGuiWrapper::text(std::to_string(visible_view_range[0]) + " - " + std::to_string(visible_view_range[1]) + " | " +
3342 std::to_string(m_viewer.get_vertex_at(visible_view_range[0]).gcode_id) + " - " +
3343 std::to_string(m_viewer.get_vertex_at(visible_view_range[1]).gcode_id));
3344
3345 auto add_range_property_row = [&imgui](const std::string& label, const std::array<float, 2>& range) {
3346 ImGui::TableNextRow();
3347 ImGui::TableSetColumnIndex(0);
3349 ImGui::TableSetColumnIndex(1);
3350 char buf[128];
3351 sprintf(buf, "%.3f - %.3f", range[0], range[1]);
3352 ImGuiWrapper::text(buf);
3353 };
3354
3355 add_range_property_row("height range", m_viewer.get_color_range(libvgcode::EViewType::Height).get_range());
3356 add_range_property_row("width range", m_viewer.get_color_range(libvgcode::EViewType::Width).get_range());
3357 add_range_property_row("speed range", m_viewer.get_color_range(libvgcode::EViewType::Speed).get_range());
3358 add_range_property_row("acceleration range", m_viewer.get_color_range(libvgcode::EViewType::Acceleration).get_range());
3359 add_range_property_row("jerk range", m_viewer.get_color_range(libvgcode::EViewType::Jerk).get_range());
3360 add_range_property_row("fan speed range", m_viewer.get_color_range(libvgcode::EViewType::FanSpeed).get_range());
3361 add_range_property_row("temperature range", m_viewer.get_color_range(libvgcode::EViewType::Temperature).get_range());
3362// ORCA: Add Pressure Advance visualization support
3363 add_range_property_row("pressure advance range", m_viewer.get_color_range(libvgcode::EViewType::PressureAdvance).get_range());
3364 add_range_property_row("volumetric rate range", m_viewer.get_color_range(libvgcode::EViewType::VolumetricFlowRate).get_range());
3365 add_range_property_row("layer time linear range", m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLinear).get_range());
3366 add_range_property_row("layer time logarithmic range", m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLogarithmic).get_range());
3367
3368 ImGui::EndTable();
3369 }
3370
3371#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
3372 ImGui::Separator();
3373
3374 if (ImGui::BeginTable("Cog", 2)) {
3375 ImGui::TableNextRow();
3376 ImGui::TableSetColumnIndex(0);
3377 ImGuiPureWrap::text_colored(ImGuiPureWrap::COL_ORANGE_LIGHT, "Cog marker scale factor");
3378 ImGui::TableSetColumnIndex(1);
3379 ImGuiPureWrap::text(std::to_string(get_cog_marker_scale_factor()));
3380
3381 ImGui::EndTable();
3382 }
3383
3384 ImGui::Separator();
3385
3386 if (ImGui::BeginTable("Tool", 2)) {
3387 ImGui::TableNextRow();
3388 ImGui::TableSetColumnIndex(0);
3389 ImGuiPureWrap::text_colored(ImGuiPureWrap::COL_ORANGE_LIGHT, "Tool marker scale factor");
3390 ImGui::TableSetColumnIndex(1);
3391 ImGuiPureWrap::text(std::to_string(m_viewer.get_tool_marker_scale_factor()));
3392
3393 ImGui::TableNextRow();
3394 ImGui::TableSetColumnIndex(0);
3395 ImGuiPureWrap::text_colored(ImGuiPureWrap::COL_ORANGE_LIGHT, "Tool marker z offset");
3396 ImGui::TableSetColumnIndex(1);
3397 float tool_z_offset = m_viewer.get_tool_marker_offset_z();
3398 if (imgui.slider_float("##ToolZOffset", &tool_z_offset, 0.0f, 1.0f))
3399 m_viewer.set_tool_marker_offset_z(tool_z_offset);
3400
3401 ImGui::TableNextRow();
3402 ImGui::TableSetColumnIndex(0);
3403 ImGuiPureWrap::text_colored(ImGuiPureWrap::COL_ORANGE_LIGHT, "Tool marker color");
3404 ImGui::TableSetColumnIndex(1);
3405 const libvgcode::Color& color = m_viewer.get_tool_marker_color();
3406 std::array<float, 3> c = { static_cast<float>(color[0]) / 255.0f, static_cast<float>(color[1]) / 255.0f, static_cast<float>(color[2]) / 255.0f };
3407 if (ImGui::ColorPicker3("##ToolColor", c.data())) {
3408 m_viewer.set_tool_marker_color({ static_cast<uint8_t>(c[0] * 255.0f),
3409 static_cast<uint8_t>(c[1] * 255.0f),
3410 static_cast<uint8_t>(c[2] * 255.0f) });
3411 }
3412 ImGui::TableNextRow();
3413 ImGui::TableSetColumnIndex(0);
3414 ImGuiPureWrap::text_colored(ImGuiPureWrap::COL_ORANGE_LIGHT, "Tool marker alpha");
3415 ImGui::TableSetColumnIndex(1);
3416 float tool_alpha = m_viewer.get_tool_marker_alpha();
3417 if (imgui.slider_float("##ToolAlpha", &tool_alpha, 0.25f, 0.75f))
3418 m_viewer.set_tool_marker_alpha(tool_alpha);
3419
3420 ImGui::EndTable();
3421 }
3422#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
3423
3424 ImGui::Separator();
3425 if (ImGui::BeginTable("Radii", 2)) {
3426
3427 ImGui::TableNextRow();
3428 ImGui::TableSetColumnIndex(0);
3430 ImGui::TableSetColumnIndex(1);
3431 float travels_radius = m_viewer.get_travels_radius();
3432 ImGui::SetNextItemWidth(200.0f);
3433 if (imgui.slider_float("##TravelRadius", &travels_radius, 0.05f, 0.5f))
3434 m_viewer.set_travels_radius(travels_radius);
3435
3436 ImGui::TableNextRow();
3437 ImGui::TableSetColumnIndex(0);
3439 ImGui::TableSetColumnIndex(1);
3440 float wipes_radius = m_viewer.get_wipes_radius();
3441 ImGui::SetNextItemWidth(200.0f);
3442 if (imgui.slider_float("##WipesRadius", &wipes_radius, 0.05f, 0.5f))
3443 m_viewer.set_wipes_radius(wipes_radius);
3444
3445 ImGui::EndTable();
3446 }
3447 imgui.end();
3448 }
3449#endif // ENABLE_NEW_GCODE_VIEWER_DEBUG
3450}
static void text_colored(const ImVec4 &color, const char *label)
Definition ImGuiWrapper.cpp:1157
static const ImVec4 COL_ORANGE_LIGHT
Definition ImGuiWrapper.hpp:387
static void text(const char *label)
Definition ImGuiWrapper.cpp:1128
#define glBindBuffer
Definition gl.h:3267
#define GL_ELEMENT_ARRAY_BUFFER
Definition gl.h:636
std::string format_memsize(size_t bytes, unsigned int decimals)
Definition utils.cpp:1703
std::array< float, 16 > Mat4x4
Definition Types.hpp:51
std::array< uint8_t, 3 > Color
Definition Types.hpp:59

References libvgcode::Acceleration, Slic3r::GUI::ImGuiWrapper::begin(), Slic3r::GUI::ImGuiWrapper::COL_ORANGE_LIGHT, libvgcode::convert(), Slic3r::GUI::ImGuiWrapper::end(), libvgcode::FanSpeed, Slic3r::format_memsize(), Slic3r::GUI::Camera::get_inv_zoom(), Slic3r::GUI::Camera::get_projection_matrix(), Slic3r::GUI::Camera::get_view_matrix(), Slic3r::GUI::Size::get_width(), GL_ELEMENT_ARRAY_BUFFER, glBindBuffer, glsafe, libvgcode::Height, is_legend_shown(), libvgcode::Jerk, libvgcode::LayerTimeLinear, libvgcode::LayerTimeLogarithmic, m_viewer, libvgcode::PressureAdvance, Slic3r::range(), Slic3r::GUI::ImGuiWrapper::set_next_window_pos(), Slic3r::GUI::ImGuiWrapper::slider_float(), libvgcode::Speed, libvgcode::Temperature, Slic3r::GUI::ImGuiWrapper::text(), Slic3r::GUI::ImGuiWrapper::text_colored(), libvgcode::VolumetricFlowRate, and libvgcode::Width.

Referenced by render_scene().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_translucent_toolpaths()

void Slic3r::GUI::GCodeViewer::render_translucent_toolpaths ( int canvas_width,
int canvas_height )
3259{
3260 if (!m_viewer.has_translucent_toolpaths())
3261 return;
3262
3263 const Camera& camera = wxGetApp().plater()->get_camera();
3264 m_viewer.render_translucent(libvgcode::convert(static_cast<Matrix4f>(camera.get_view_matrix().matrix().cast<float>())),
3265 libvgcode::convert(static_cast<Matrix4f>(camera.get_projection_matrix().matrix().cast<float>())));
3267 render_markers(canvas_width, canvas_height);
3268}

References libvgcode::convert(), Slic3r::GUI::Camera::get_projection_matrix(), Slic3r::GUI::Camera::get_view_matrix(), GL_DEPTH_TEST, glEnable, glsafe, m_viewer, and render_markers().

Here is the call graph for this function:

◆ reset()

void Slic3r::GUI::GCodeViewer::reset ( )
1960{
1961 //BBS: should also reset the result id
1962 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": current result id %1% ")%m_last_result_id;
1963 m_last_result_id = -1;
1964 m_belt_layer_zs.clear();
1965 //BBS: add only gcode mode
1967
1968 m_viewer.reset();
1969
1970 m_paths_bounding_box = BoundingBoxf3();
1971 m_max_bounding_box = BoundingBoxf3();
1972 m_max_print_height = 0.0f;
1974 m_z_offset = 0.0f;
1976 m_filament_diameters = std::vector<float>();
1977 m_filament_densities = std::vector<float>();
1978 m_move_type_counts.fill(0);
1979 for (auto& move_type_times : m_move_type_times)
1980 move_type_times.fill(0.0f);
1981 m_move_type_distances.fill(0.0f);
1982 m_print_statistics.reset();
1983 m_custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
1984 m_plate_mass = {};
1985 m_object_masses.clear();
1986 m_body_masses.clear();
1987 m_support_masses.clear();
1990 m_sequential_view.gcode_window.reset();
1991 m_contained_in_bed = true;
1992}

References m_belt_layer_zs, m_body_masses, m_contained_in_bed, m_custom_gcode_per_print_z, m_extruders_count, m_filament_densities, m_filament_diameters, m_last_result_id, m_left_extruder_filament, m_machine_frame_transform_active, m_max_bounding_box, m_max_print_height, m_move_type_counts, m_move_type_distances, m_move_type_times, m_object_masses, m_only_gcode_in_preview, m_paths_bounding_box, m_plate_mass, m_print_statistics, m_right_extruder_filament, m_sequential_view, m_support_masses, m_viewer, and m_z_offset.

Referenced by ~GCodeViewer(), load_as_gcode(), and Slic3r::GUI::GCodeViewer::SequentialView::GCodeWindow::load_gcode().

Here is the caller graph for this function:

◆ reset_shell()

void Slic3r::GUI::GCodeViewer::reset_shell ( )
1953{
1954 m_shells.volumes.clear();
1955 m_shells.print_id = -1;
1956 m_shell_bounding_box = BoundingBoxf3();
1957}

References m_shell_bounding_box, and m_shells.

Referenced by load_shells().

Here is the caller graph for this function:

◆ reset_visible()

void Slic3r::GUI::GCodeViewer::reset_visible ( libvgcode::EViewType type)
inline
492 {
494 auto roles = m_viewer.get_extrusion_roles();
495 for (size_t i = 0; i < roles.size(); ++i) {
496 auto role = roles[i];
497 if (!m_viewer.is_extrusion_role_visible(role)) {
498 m_viewer.toggle_extrusion_role_visibility(role);
499 }
500 }
501 }
502 }

References libvgcode::FeatureType, and m_viewer.

◆ resolve_imex_marker_plan()

GCodeViewer::ImexMarkerPlan Slic3r::GUI::GCodeViewer::resolve_imex_marker_plan ( const DynamicPrintConfig & printer_cfg,
const std::string & mode,
const BoundingBoxf & bed_extents )
staticprivate
2006{
2007 ImexMarkerPlan plan;
2008
2009 // Firmware-managed-zones centers the slice at bed origin, so prim_pos
2010 // and the preview toolpaths sit in a shifted frame relative to the
2011 // plate-local bed bounds the zone math uses. Computing secondaries here
2012 // would place them off-bed. The firmware physically fans the centered
2013 // toolpath out into the zones, so the centered preview with no
2014 // secondaries is the honest representation.
2015 if (imex_cfg_bool(printer_cfg, "imex_firmware_managed_zones"))
2016 return plan;
2017 if (mode.empty() || mode == kImexPrimaryMode)
2018 return plan;
2019
2020 // Only the gantry grouping and the mirror axis are decided here; the zone grid itself comes
2021 // from compute_imex_zone_layout() below, which reads the same keys through the same accessor.
2022 const int tools_per_gantry = std::max(1, imex_cfg_int(printer_cfg, "imex_tools_per_gantry"));
2023 plan.box_wx = (float)imex_cfg_float(printer_cfg, "imex_nozzle_clearance_x");
2024 plan.box_wy = (float)imex_cfg_float(printer_cfg, "imex_nozzle_clearance_y");
2025
2026 // Parse "idx:P/C/M" via shared helpers — matches PartPlate::calc_imex_zones.
2027 // The role travels as an ImexRole all the way to the marker placement
2028 // below; there is no int encoding in between, so a role added to the enum
2029 // cannot silently fall into the "not Mirror, therefore Copy" branch.
2030 int pri_tool = -1;
2031 std::vector<int> sec_tool_ids;
2032 std::map<int, ImexRole> sec_tool_roles; // tool_id -> Copy or Mirror
2033 std::set<int> sec_aggregated; // representatives standing in for a whole gantry
2034 {
2035 // Same lookup rule as PartPlate's zones and ghosts, and as the slicer:
2036 // an unresolved mode, and a mode the tools array is too short to cover,
2037 // both come back empty and leave the marker roster empty.
2038 const std::string entry = find_imex_mode(printer_cfg, mode).active_tools;
2039 pri_tool = imex_primary_tool_for_mode(entry);
2040 // Aggregate per gantry via the same source of truth as PartPlate's
2041 // zone/ghost aggregation: in Span modes only one tool prints per
2042 // zone at a time, so a non-primary gantry collapses to one
2043 // representative marker. Non-Span gantries keep per-tool markers.
2044 const ImexGantryGrouping grouping =
2045 group_imex_active_tools_by_gantry(entry, tools_per_gantry);
2046 auto add_tool = [&](int phys_idx, ImexRole role, bool aggregated) {
2047 if (phys_idx < 0 || phys_idx == pri_tool) return;
2048 // Only Copy and Mirror print in a zone of their own, so only they
2049 // get a marker. Exhaustive with no default so -Wswitch makes a new
2050 // role answer "does this carriage get its own marker?" rather than
2051 // defaulting into a Copy-shaped one.
2052 switch (role) {
2053 case ImexRole::Copy:
2054 case ImexRole::Mirror:
2055 break;
2056 case ImexRole::Primary: // not a secondary carriage
2057 case ImexRole::Span: // rides in the primary's zone
2058 return;
2059 }
2060 sec_tool_roles[phys_idx] = role;
2061 sec_tool_ids.push_back(phys_idx);
2062 if (aggregated) sec_aggregated.insert(phys_idx);
2063 };
2064 // Out-of-grid tool indices (a stale mode string carried over from a
2065 // printer with more tools) are handled inconsistently by the code we
2066 // must agree with: compute_imex_zone_layout drops them, so they own no
2067 // zone, while calc_imex_ghosts still bakes a ghost for them. No single
2068 // policy matches both, so the marker roster is left exactly as it was
2069 // and such a tool simply falls back to the first zone below. Clamping
2070 // pri_tool instead is a trap: the -1 sentinel truncates to gantry 0 in
2071 // imex_mirror_axis_for and flips the marker to the opposite mirror
2072 // axis from the ghost. It is also why the layout's own `primary_head`
2073 // cannot stand in for `pri_tool` here — the layout reports -1 for an
2074 // off-grid primary, this roster has to keep the authored index.
2075 for (const auto& grp : grouping.groups) {
2076 // Markers: an aggregated non-primary gantry shows only its rep.
2077 if (grp.aggregate && grp.gantry_index != grouping.primary_gantry)
2078 add_tool(grp.representative_phys, grp.representative_role, true);
2079 else
2080 for (const auto& [phys_idx, role] : grp.tools)
2081 add_tool(phys_idx, role, false);
2082 }
2083 }
2084 const int sec_count = (int)sec_tool_ids.size();
2085 if (sec_count == 0)
2086 return plan;
2087
2088 // The zone grid is not re-derived here: this is the same call
2089 // PartPlate::calc_imex_zones() makes, with the same printer config and the
2090 // same bed extents, so the preview and the plate cannot place a tool
2091 // differently for the same mode. The T0-corner flips, the active
2092 // column/row sets and the zone pitch all live inside the library; the
2093 // markers need nothing from it but `head_zone_centers`.
2094 // `mode` is already resolved (per-plate mode beats the process preset),
2095 // so it goes in as the plate mode with no process fallback.
2096 const ImexZoneLayout zone_layout =
2097 compute_imex_zone_layout(printer_cfg, mode, std::string(), bed_extents);
2098
2099 // Centre of zone (0,0), the fallback for any head the layout gave no zone —
2100 // a mode string naming a tool outside this printer's grid. Zone indices are
2101 // dense, so the lowest centre on each axis IS zone 0's. An empty layout
2102 // means one undivided zone, whose centre is the bed's.
2103 Vec2d zone0_center = bed_extents.center();
2104 if (!zone_layout.head_zone_centers.empty()) {
2105 zone0_center = zone_layout.head_zone_centers.begin()->second;
2106 for (const auto& head_center : zone_layout.head_zone_centers) {
2107 zone0_center.x() = std::min(zone0_center.x(), head_center.second.x());
2108 zone0_center.y() = std::min(zone0_center.y(), head_center.second.y());
2109 }
2110 }
2111 auto zone_center_of = [&](int tid) -> Vec2d {
2112 auto it = zone_layout.head_zone_centers.find(tid);
2113 return (it == zone_layout.head_zone_centers.end()) ? zone0_center : it->second;
2114 };
2115 const Vec2d pri_center = zone_center_of(pri_tool);
2116
2117 // An aggregated gantry's zone is a full-X row strip with no column of its
2118 // own, so its marker tracks primary's X. calc_imex_ghosts() reaches the same
2119 // zero X offset by putting both frames on the bed centreline; for a single
2120 // marker, pinning the centre says it directly.
2121 auto sec_center_of = [&](int tid) -> Vec2d {
2122 Vec2d c = zone_center_of(tid);
2123 if (sec_aggregated.count(tid))
2124 c.x() = pri_center.x();
2125 return c;
2126 };
2127
2128 // Primary carriage box: seeded from whether primary holds the leftmost zone
2129 // column, then turned by any secondary sitting to one side of it.
2130 plan.pri_box_offset_x = (pri_center.x() <= zone0_center.x()) ? 0.0f : -plan.box_wx;
2131 plan.pri_box_offset_y = -plan.box_wy;
2132 for (int i = 0; i < sec_count; ++i) {
2133 const Vec2d sc = sec_center_of(sec_tool_ids[i]);
2134 if (sc.x() > pri_center.x()) { plan.pri_box_offset_x = 0.0f; }
2135 else if (sc.x() < pri_center.x()) { plan.pri_box_offset_x = -plan.box_wx; }
2136 if (sc.y() > pri_center.y()) { plan.pri_box_offset_y = 0.0f; }
2137 else if (sc.y() < pri_center.y()) { plan.pri_box_offset_y = -plan.box_wy; }
2138 }
2139
2140 plan.pri_head = pri_tool;
2141 plan.carriages.reserve(sec_count);
2142 for (int i = 0; i < sec_count; ++i) {
2143 const int sec_tool = sec_tool_ids[i];
2144 const Vec2d sec_center = sec_center_of(sec_tool);
2145 const ImexRole sec_role = sec_tool_roles[sec_tool];
2146
2147 // A carriage stays inside its own zone; a Mirror reflects its
2148 // zone-relative offset about that zone's centerline, on the axis of the
2149 // boundary it shares with primary — the same rule the ghosts use:
2150 // Copy → tracks primary on both axes.
2151 // Mirror, same gantry → reflect X (zones sit side by side).
2152 // Mirror, other gantry → reflect Y (zones sit front-to-back); X
2153 // tracks primary, since the part off that
2154 // gantry is a Y-reflection of the tool
2155 // directly behind it.
2156 // The axis comes from the shared helper, so the markers can never drift
2157 // out of step with the plate ghosts.
2158 const bool is_mirror = (sec_role == ImexRole::Mirror);
2159 const bool cross_gantry = imex_mirror_axis_for(pri_tool, sec_tool,
2160 tools_per_gantry) == ImexMirrorAxis::Y;
2161
2162 // Tracking an axis translates by the gap between the two zone centres.
2163 // Mirroring it reflects primary about the midpoint of those centres —
2164 // the zones being equal-sized, that midpoint is the boundary between
2165 // them, so the carriage still lands inside its own zone. Both are a
2166 // single term applied to the live primary position each frame:
2167 // `term - pos` when mirrored, `pos + term` when tracked.
2168 ImexMarkerPlan::Carriage carriage;
2169 carriage.phys_head = sec_tool;
2170 carriage.mirror_x = is_mirror && !cross_gantry;
2171 carriage.mirror_y = is_mirror && cross_gantry;
2172 carriage.x_term = carriage.mirror_x ? (float)(sec_center.x() + pri_center.x())
2173 : (float)(sec_center.x() - pri_center.x());
2174 carriage.y_term = carriage.mirror_y ? (float)(sec_center.y() + pri_center.y())
2175 : (float)(sec_center.y() - pri_center.y());
2176
2177 // The box shows the side a toolhead could COLLIDE from, not merely which
2178 // way its body hangs. Tools sharing a gantry share an X rail and can
2179 // actually run into each other, and only in a same-gantry (X-axis) mirror
2180 // do they converge — so that is the one case where the secondary's box
2181 // flips to face the primary. Tools on different gantries cannot collide
2182 // in X at all, so a cross-gantry mirror keeps the primary's facing, the
2183 // same as a Copy. Do not "fix" this to follow carriage geometry: a box on
2184 // the far side would point away from the only tool it can hit.
2185 if (is_mirror && !cross_gantry) {
2186 if (sec_center.x() > pri_center.x()) carriage.box_offset_x = -plan.box_wx;
2187 else if (sec_center.x() < pri_center.x()) carriage.box_offset_x = 0.0f;
2188 else carriage.box_offset_x = plan.pri_box_offset_x;
2189 } else {
2190 carriage.box_offset_x = plan.pri_box_offset_x;
2191 }
2192 // Y follows the same collision rule: face the gantry you could hit. A tool
2193 // on ANOTHER row faces the primary's row; a tool on the primary's OWN row
2194 // shares its gantry and can only hit the same other gantry, so it faces
2195 // wherever the primary faces. The old `else` hardcoded -imex_box_wy, which
2196 // happens to equal pri_box_offset_y on the rear-* layouts (primary's row
2197 // sits above the others, so the loop above settles on -box_wy anyway)
2198 // — hence a no-op there. On the front-* layouts the primary flips to 0.0f
2199 // and the hardcoded value pointed the same-gantry secondary away from the
2200 // only tools it could run into.
2201 if (sec_center.y() > pri_center.y()) carriage.box_offset_y = -plan.box_wy;
2202 else if (sec_center.y() < pri_center.y()) carriage.box_offset_y = 0.0f;
2203 else carriage.box_offset_y = plan.pri_box_offset_y;
2204
2205 plan.carriages.push_back(carriage);
2206 }
2207
2208 return plan;
2209}
int phys_head
Definition GCodeViewer.hpp:255
ImexRole
Definition IMEXHelpers.hpp:345
@ Primary
Definition IMEXHelpers.hpp:345
@ Mirror
Definition IMEXHelpers.hpp:345
@ Copy
Definition IMEXHelpers.hpp:345
@ Span
Definition IMEXHelpers.hpp:345
ImexMode find_imex_mode(const ConfigBase &cfg, const std::string &name)
Definition IMEXHelpers.cpp:665
ImexGantryGrouping group_imex_active_tools_by_gantry(const std::string &active_tools_for_mode, int tools_per_gantry)
Definition IMEXHelpers.cpp:365
int imex_primary_tool_for_mode(const std::string &active_tools_for_mode)
Definition IMEXHelpers.cpp:422
ImexZoneLayout compute_imex_zone_layout(const DynamicPrintConfig &printer_cfg, const std::string &plate_mode, const std::string &process_mode, const BoundingBoxf &bed_extents)
Definition IMEXZones.cpp:17
ImexMirrorAxis imex_mirror_axis_for(int primary_phys, int target_phys, int tools_per_gantry)
Definition IMEXHelpers.cpp:578
@ Y
Definition IMEXHelpers.hpp:557
std::string active_tools
Definition IMEXHelpers.hpp:70

References Slic3r::ImexMode::active_tools, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::box_offset_x, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::box_offset_y, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::box_wx, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::box_wy, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::carriages, Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::compute_imex_zone_layout(), Slic3r::Copy, Slic3r::find_imex_mode(), Slic3r::group_imex_active_tools_by_gantry(), Slic3r::ImexGantryGrouping::groups, Slic3r::ImexZoneLayout::head_zone_centers, Slic3r::imex_cfg_bool(), Slic3r::imex_cfg_float(), Slic3r::imex_cfg_int(), Slic3r::imex_mirror_axis_for(), Slic3r::imex_primary_tool_for_mode(), Slic3r::kImexPrimaryMode, Slic3r::Mirror, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::mirror_x, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::mirror_y, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::phys_head, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::pri_box_offset_x, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::pri_box_offset_y, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::pri_head, Slic3r::Primary, Slic3r::ImexGantryGrouping::primary_gantry, Slic3r::Span, Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::x_term, Slic3r::Y, and Slic3r::GUI::GCodeViewer::ImexMarkerPlan::Carriage::y_term.

Referenced by render_markers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_view_type()

void Slic3r::GUI::GCodeViewer::select_view_type ( libvgcode::EViewType type)
1268{
1269 auto it = std::find(view_type_items.begin(), view_type_items.end(), type);
1270 m_view_type_sel = (it != view_type_items.end()) ? static_cast<int>(std::distance(view_type_items.begin(), it)) : 0;
1271 set_view_type(type);
1272}

References m_view_type_sel, set_view_type(), and view_type_items.

Referenced by apply_default_view_type().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sequential_view_height()

int Slic3r::GUI::GCodeViewer::sequential_view_height ( int canvas_height) const
private
2585{
2586 //BBS fixed bottom_margin for space to render horiz slider
2587 const int bottom_margin = SLIDER_BOTTOM_MARGIN * GCODE_VIEWER_SLIDER_SCALE;
2588 // BBS fixed buttom margin. m_moves_slider.pos_y
2589 return canvas_height - bottom_margin * m_scale;
2590}
static const float GCODE_VIEWER_SLIDER_SCALE
Definition GCodeViewer.hpp:49
static const float SLIDER_BOTTOM_MARGIN
Definition GCodeViewer.hpp:54

References Slic3r::GUI::GCODE_VIEWER_SLIDER_SCALE, m_scale, and Slic3r::GUI::SLIDER_BOTTOM_MARGIN.

Referenced by render_markers(), and render_overlay().

Here is the caller graph for this function:

◆ set_belt_printer()

void Slic3r::GUI::GCodeViewer::set_belt_printer ( bool enabled,
float angle_deg )
inline
524{ m_belt_view_enabled = enabled; m_belt_angle_deg = angle_deg; }

References m_belt_angle_deg, and m_belt_view_enabled.

◆ set_clipping_plane()

void Slic3r::GUI::GCodeViewer::set_clipping_plane ( const ClippingPlane & plane)
2521{
2522 // Flipped to match ClippingPlane::distance().
2523 const Vec3f normal = -plane.get_normal().cast<float>();
2524 m_clipping_plane = plane.is_active() ?
2525 std::array<float, 4>{ normal.x(), normal.y(), normal.z(), float(plane.get_offset()) } :
2526 std::array<float, 4>{ 0.0f, 0.0f, 0.0f, 1.0f };
2527 m_viewer.set_clipping_plane(m_clipping_plane);
2528}
std::array< float, 4 > m_clipping_plane
Definition GCodeViewer.hpp:376
Point normal(Point pt, double scale)
Definition TreeSupport.cpp:112

References Slic3r::GUI::ClippingPlane::get_normal(), Slic3r::GUI::ClippingPlane::get_offset(), Slic3r::GUI::ClippingPlane::is_active(), m_clipping_plane, m_viewer, and Slic3r::normal().

Here is the call graph for this function:

◆ set_dim_previous_layers()

void Slic3r::GUI::GCodeViewer::set_dim_previous_layers ( bool value)
inline
507{ m_viewer.set_dim_previous_layers(value); }

References m_viewer.

◆ set_dim_previous_layers_brightness()

void Slic3r::GUI::GCodeViewer::set_dim_previous_layers_brightness ( float value)
inline
510{ m_viewer.set_dim_previous_layers_brightness(value); }

References m_viewer.

◆ set_gloss()

void Slic3r::GUI::GCodeViewer::set_gloss ( bool gloss)
inline
423{ m_viewer.set_gloss(gloss); }

References m_viewer.

◆ set_layers_z_range()

void Slic3r::GUI::GCodeViewer::set_layers_z_range ( const std::array< unsigned int, 2 > & layers_z_range)
2815{
2816 m_viewer.set_layers_view_range(static_cast<uint32_t>(layers_z_range[0]), static_cast<uint32_t>(layers_z_range[1]));
2817 update_moves_slider(true);
2818}

References m_viewer, and update_moves_slider().

Here is the call graph for this function:

◆ set_light_top_dir()

void Slic3r::GUI::GCodeViewer::set_light_top_dir ( const Vec3d & direction)
2511{
2512 m_viewer.set_light_top_dir(libvgcode::convert(static_cast<Vec3f>(direction.cast<float>())));
2513}

References libvgcode::convert(), and m_viewer.

Here is the call graph for this function:

◆ set_scale()

void Slic3r::GUI::GCodeViewer::set_scale ( float scale = 1.0)
1226{
1227 if(m_scale != scale)m_scale = scale;
1228 if (m_sequential_view.m_scale != scale) {
1229 m_sequential_view.m_scale = scale;
1230 m_sequential_view.marker.m_scale = scale;
1231 m_sequential_view.gcode_window.m_scale = scale; // ORCA
1232 }
1233}
int scale(const int val)
Definition WipeTowerDialog.cpp:58

References m_scale, m_sequential_view, and scale().

Here is the call graph for this function:

◆ set_shadow_map()

void Slic3r::GUI::GCodeViewer::set_shadow_map ( int texture_unit,
const Transform3d & light_view_projection,
float intensity,
float texel_size )
2504{
2505 m_viewer.set_shadow_map(texture_unit,
2506 libvgcode::convert(static_cast<Matrix4f>(light_view_projection.matrix().cast<float>())),
2507 intensity, texel_size);
2508}

References libvgcode::convert(), and m_viewer.

Here is the call graph for this function:

◆ set_shell_transparency()

void Slic3r::GUI::GCodeViewer::set_shell_transparency ( float alpha = 0.15f)
1949{ m_shells.volumes.set_transparency(alpha); }

References m_shells.

◆ set_shells_on_preview()

void Slic3r::GUI::GCodeViewer::set_shells_on_preview ( bool is_previewing)
inline
402{ m_shells.previewing = is_previewing; }

References m_shells.

◆ set_tone()

void Slic3r::GUI::GCodeViewer::set_tone ( float exposure,
float saturation )
2516{
2517 m_viewer.set_tone(exposure, saturation);
2518}

References m_viewer.

◆ set_translucent_filaments()

void Slic3r::GUI::GCodeViewer::set_translucent_filaments ( bool value)
inline
513{ m_viewer.set_translucent_filaments(value); }

References m_viewer.

◆ set_view_type()

void Slic3r::GUI::GCodeViewer::set_view_type ( libvgcode::EViewType type)
inline
479 {
480 m_viewer.set_view_type(type);
481 }

References m_viewer.

Referenced by select_view_type().

Here is the caller graph for this function:

◆ shadow_casters_signature()

size_t Slic3r::GUI::GCodeViewer::shadow_casters_signature ( ) const
2473{
2474 size_t hash = m_viewer.get_vertices_count();
2475 const libvgcode::Interval& visible = m_viewer.get_view_visible_range();
2476 const libvgcode::Interval& layers = m_viewer.get_layers_view_range();
2477 for (size_t value : { size_t(visible[0]), size_t(visible[1]), size_t(layers[0]), size_t(layers[1]) })
2478 boost::hash_combine(hash, value);
2479 for (double value : { m_paths_bounding_box.min.x(), m_paths_bounding_box.min.y(), m_paths_bounding_box.min.z(),
2481 boost::hash_combine(hash, value);
2482 boost::hash_combine(hash, m_viewer.is_top_layer_only_view_range());
2483 for (size_t i = 0; i < libvgcode::GCODE_EXTRUSION_ROLES_COUNT; ++i)
2484 boost::hash_combine(hash, m_viewer.is_extrusion_role_visible(libvgcode::EGCodeExtrusionRole(i)));
2485 boost::hash_combine(hash, m_viewer.is_option_visible(libvgcode::EOptionType::Travels));
2486 boost::hash_combine(hash, m_viewer.is_option_visible(libvgcode::EOptionType::Wipes));
2487 for (float value : m_clipping_plane)
2488 boost::hash_combine(hash, value);
2489 return hash;
2490}

References libvgcode::GCODE_EXTRUSION_ROLES_COUNT, m_clipping_plane, m_paths_bounding_box, m_viewer, libvgcode::Travels, and libvgcode::Wipes.

◆ show_legend()

void Slic3r::GUI::GCodeViewer::show_legend ( bool show)
inline
518{ m_legend_visible = show; }

References m_legend_visible.

◆ shown_filament_color()

ColorRGBA Slic3r::GUI::GCodeViewer::shown_filament_color ( ColorRGBA color) const
private
3252{
3253 if (!m_viewer.is_translucent_filaments())
3254 color.a(1.0f);
3255 return color;
3256}

References Slic3r::ColorRGBA::a(), and m_viewer.

Here is the call graph for this function:

◆ toggle_belt_show_designed()

void Slic3r::GUI::GCodeViewer::toggle_belt_show_designed ( )
inline

◆ update_by_mode()

void Slic3r::GUI::GCodeViewer::update_by_mode ( ConfigOptionMode mode)
1303{
1304 view_type_items.clear();
1305 view_type_items_str.clear();
1306 options_items.clear();
1307
1308 // BBS initialzed view_type items
1324// ORCA: Add Pressure Advance visualization support
1326 //if (mode == ConfigOptionMode::comDevelop) {
1327 // view_type_items.push_back(EViewType::Tool);
1328 //}
1329
1330 for (int i = 0; i < view_type_items.size(); i++) {
1332 }
1333
1334 // BBS for first layer inspection
1336
1340 options_items.push_back(EMoveType::Wipe);
1341 //if (mode == ConfigOptionMode::comDevelop) {
1342 // options_items.push_back(EMoveType::Tool_change);
1343 //}
1344 //BBS: seam is not real move and extrusion, put at last line
1345 options_items.push_back(EMoveType::Seam);
1346}
std::vector< EMoveType > options_items
Definition GCodeViewer.hpp:349
@ Travel
Definition GCodeProcessor.hpp:62
@ Wipe
Definition GCodeProcessor.hpp:63
@ Seam
Definition GCodeProcessor.hpp:57

References libvgcode::Acceleration, libvgcode::ActualSpeed, libvgcode::ActualVolumetricFlowRate, libvgcode::ColorPrint, libvgcode::FanSpeed, libvgcode::FeatureType, Slic3r::GUI::get_view_type_string(), libvgcode::Height, libvgcode::Jerk, libvgcode::LayerTimeLinear, libvgcode::LayerTimeLogarithmic, options_items, libvgcode::PressureAdvance, Slic3r::Retract, Slic3r::Seam, libvgcode::Speed, libvgcode::Summary, libvgcode::Temperature, libvgcode::Tool, Slic3r::Travel, Slic3r::Unretract, view_type_items, view_type_items_str, libvgcode::VolumetricFlowRate, libvgcode::Width, and Slic3r::Wipe.

Referenced by init(), and render_overlay().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_layers_slider_mode()

void Slic3r::GUI::GCodeViewer::update_layers_slider_mode ( )
2774{
2775 // true -> single-extruder printer profile OR
2776 // multi-extruder printer profile , but whole model is printed by only one extruder
2777 // false -> multi-extruder printer profile , and model is printed by several extruders
2778 bool one_extruder_printed_model = true;
2779
2780 // extruder used for whole model for multi-extruder printer profile
2781 int only_extruder = -1;
2782
2783 // BBS
2784 if (wxGetApp().filaments_cnt() > 1) {
2785 const ModelObjectPtrs &objects = wxGetApp().plater()->model().objects;
2786
2787 // check if whole model uses just only one extruder
2788 if (!objects.empty()) {
2789 const int extruder = objects[0]->config.has("extruder") ? objects[0]->config.option("extruder")->getInt() : 0;
2790
2791 auto is_one_extruder_printed_model = [objects, extruder]() {
2792 for (ModelObject *object : objects) {
2793 if (object->config.has("extruder") && object->config.option("extruder")->getInt() != extruder) return false;
2794
2795 for (ModelVolume *volume : object->volumes)
2796 if ((volume->config.has("extruder") && volume->config.option("extruder")->getInt() != extruder) || !volume->mmu_segmentation_facets.empty()) return false;
2797
2798 for (const auto &range : object->layer_config_ranges)
2799 if (range.second.has("extruder") && range.second.option("extruder")->getInt() != extruder) return false;
2800 }
2801 return true;
2802 };
2803
2804 if (is_one_extruder_printed_model())
2805 only_extruder = extruder;
2806 else
2807 one_extruder_printed_model = false;
2808 }
2809 }
2810
2811 // TODO m_layers_slider->SetModeAndOnlyExtruder(one_extruder_printed_model, only_extruder);
2812}

References Slic3r::ModelVolume::config, Slic3r::FacetsAnnotation::empty(), Slic3r::ConfigOption::getInt(), Slic3r::ModelConfig::has(), Slic3r::ModelVolume::mmu_segmentation_facets, Slic3r::ModelConfig::option(), and Slic3r::range().

Here is the call graph for this function:

◆ update_moves_slider()

void Slic3r::GUI::GCodeViewer::update_moves_slider ( bool set_to_max = false)
2716{
2717 if (m_gcode_result->moves.empty())
2718 return;
2719
2720 const libvgcode::Interval& range = m_viewer.get_view_enabled_range();
2721 const libvgcode::Interval& visible_range = m_viewer.get_view_visible_range();
2722 uint32_t last_gcode_id = get_gcode_vertex_at(range[0]).gcode_id;
2723 uint32_t gcode_id_min = get_gcode_vertex_at(visible_range[0]).gcode_id;
2724 uint32_t gcode_id_max = get_gcode_vertex_at(visible_range[1]).gcode_id;
2725
2726 const size_t range_size = range[1] - range[0] + 1;
2727 std::vector<double> values;
2728 values.reserve(range_size);
2729 std::vector<double> alternate_values;
2730 alternate_values.reserve(range_size);
2731
2732 std::optional<uint32_t> visible_range_min_id;
2733 std::optional<uint32_t> visible_range_max_id;
2734 uint32_t counter = 0;
2735
2736 for (size_t i = range[0]; i <= range[1]; ++i) {
2737 const uint32_t gcode_id = get_gcode_vertex_at(i).gcode_id;
2738 bool skip = false;
2739 if (i > range[0]) {
2740 // skip consecutive moves with same gcode id (resulting from processing G2 and G3 lines)
2741 if (last_gcode_id == gcode_id) {
2742 values.back() = i + 1;
2743 skip = true;
2744 }
2745 else
2746 last_gcode_id = gcode_id;
2747 }
2748
2749 if (!skip) {
2750 values.emplace_back(i + 1);
2751 alternate_values.emplace_back(gcode_id);
2752 if (alternate_values.back() == gcode_id_min)
2753 visible_range_min_id = counter;
2754 else if (alternate_values.back() == gcode_id_max)
2755 visible_range_max_id = counter;
2756 ++counter;
2757 }
2758 }
2759
2760 const int span_min_id = visible_range_min_id.has_value() ? *visible_range_min_id : 0;
2761 const int span_max_id = visible_range_max_id.has_value() ? *visible_range_max_id : static_cast<int>(values.size()) - 1;
2762
2763 bool keep_min = m_moves_slider->GetActiveValue() == m_moves_slider->GetMinValue();
2764
2765 m_moves_slider->SetSliderValues(values);
2766 m_moves_slider->SetSliderAlternateValues(alternate_values);
2767 m_moves_slider->SetMaxValue(static_cast<int>(values.size()) - 1);
2768 m_moves_slider->SetSelectionSpan(span_min_id, span_max_id);
2769 if (set_to_max)
2770 m_moves_slider->SetHigherValue(keep_min ? m_moves_slider->GetMinValue() : m_moves_slider->GetMaxValue());
2771}
const libvgcode::PathVertex & get_gcode_vertex_at(size_t id) const
Definition GCodeViewer.hpp:473
uint32_t gcode_id
Definition PathVertex.hpp:70

References libvgcode::PathVertex::gcode_id, get_gcode_vertex_at(), m_gcode_result, m_moves_slider, m_viewer, and Slic3r::range().

Referenced by set_layers_z_range().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_sequential_view_current()

void Slic3r::GUI::GCodeViewer::update_sequential_view_current ( unsigned int first,
unsigned int last )
2626{
2627 m_viewer.set_view_visible_range(static_cast<uint32_t>(first), static_cast<uint32_t>(last));
2628 const libvgcode::Interval& enabled_range = m_viewer.get_view_enabled_range();
2629 enable_moves_slider(enabled_range[1] > enabled_range[0]);
2630
2631#if ENABLE_ACTUAL_SPEED_DEBUG
2632 if (enabled_range[1] != m_viewer.get_view_visible_range()[1]) {
2633 const libvgcode::PathVertex& curr_vertex = m_viewer.get_current_vertex();
2634 if (curr_vertex.is_extrusion() || curr_vertex.is_travel() || curr_vertex.is_wipe() ||
2635 curr_vertex.type == libvgcode::EMoveType::Seam) {
2636 const libvgcode::ColorRange& color_range = m_viewer.get_color_range(libvgcode::EViewType::ActualSpeed);
2637 const std::array<float, 2>& interval = color_range.get_range();
2638 const size_t vertices_count = m_viewer.get_vertices_count();
2639 std::vector<SequentialView::ActualSpeedImguiWidget::Item> actual_speed_data;
2640 // collect vertices sharing the same gcode_id
2641 const size_t curr_id = m_viewer.get_current_vertex_id();
2642 size_t start_id = curr_id;
2643 while (start_id > 0) {
2644 --start_id;
2645 if (curr_vertex.gcode_id != m_viewer.get_vertex_at(start_id).gcode_id)
2646 break;
2647 }
2648 size_t end_id = curr_id;
2649 while (end_id < vertices_count - 1) {
2650 ++end_id;
2651 if (curr_vertex.gcode_id != m_viewer.get_vertex_at(end_id).gcode_id)
2652 break;
2653 }
2654
2655 if (m_viewer.get_vertex_at(end_id - 1).type == libvgcode::convert(EMoveType::Seam))
2656 --end_id;
2657
2658 assert(end_id - start_id >= 2);
2659
2660 float total_len = 0.0f;
2661 for (size_t i = start_id; i < end_id; ++i) {
2662 const libvgcode::PathVertex& v = m_viewer.get_vertex_at(i);
2663 const float len = (i > start_id) ?
2664 (libvgcode::convert(v.position) - libvgcode::convert(m_viewer.get_vertex_at(i - 1).position)).norm() : 0.0f;
2665 total_len += len;
2666 if (i == start_id || len > EPSILON)
2667 actual_speed_data.push_back({ total_len, v.actual_feedrate, v.times[0] == 0.0f });
2668 }
2669
2670 std::vector<std::pair<float, ColorRGBA>> levels;
2671 const std::vector<float> values = color_range.get_values();
2672 for (float value : values) {
2673 levels.push_back(std::make_pair(value, libvgcode::convert(color_range.get_color_at(value))));
2674 levels.back().second.a(0.5f);
2675 }
2676
2677 // ORCA Compress consecutive duplicate speeds with 0.1 precision
2678 auto sameSpeed = [](float a, float b) {
2679 return static_cast<int>(std::roundf(a * 10.0f)) == static_cast<int>(std::roundf(b * 10.0f));
2680 };
2681 std::vector<SequentialView::ActualSpeedImguiWidget::Item> compressed;
2682 if (!actual_speed_data.empty()) {
2683 compressed.push_back(actual_speed_data[0]);
2684 for (int i = 1; i < (int)actual_speed_data.size(); ++i) {
2685 const bool same_as_prev = sameSpeed(actual_speed_data[i].speed, actual_speed_data[i - 1].speed);
2686 const bool same_as_next = (i + 1 < (int)actual_speed_data.size()) && sameSpeed(actual_speed_data[i].speed, actual_speed_data[i + 1].speed);
2687 if (!same_as_prev) {
2688 if (!sameSpeed(compressed.back().speed, actual_speed_data[i - 1].speed))
2689 compressed.push_back(actual_speed_data[i - 1]);
2690 compressed.push_back(actual_speed_data[i]);
2691 } else if (!same_as_next)
2692 compressed.push_back(actual_speed_data[i]);
2693 }
2694 if (compressed.back().pos != actual_speed_data.back().pos)
2695 compressed.push_back(actual_speed_data.back());
2696 }
2697
2698 m_sequential_view.marker.set_actual_speed_data(compressed);
2699 m_sequential_view.marker.set_actual_speed_y_range(std::make_pair(interval[0], interval[1]));
2700 m_sequential_view.marker.set_actual_speed_levels(levels);
2701 }
2702 }
2703#endif // ENABLE_ACTUAL_SPEED_DEBUG
2704}
void enable_moves_slider(bool enable) const
Definition GCodeViewer.cpp:2706
std::vector< float > get_values() const
Definition ColorRange.cpp:92
const std::array< float, 2 > & get_range() const
Definition ColorRange.cpp:87
Color get_color_at(float value) const
Definition ColorRange.cpp:62
bool is_extrusion() const
Definition PathVertex.cpp:12
float actual_feedrate
Definition PathVertex.hpp:40
bool is_wipe() const
Definition PathVertex.cpp:22
bool is_travel() const
Definition PathVertex.cpp:17

References libvgcode::PathVertex::actual_feedrate, libvgcode::ActualSpeed, libvgcode::convert(), enable_moves_slider(), EPSILON, libvgcode::PathVertex::gcode_id, libvgcode::ColorRange::get_color_at(), libvgcode::ColorRange::get_range(), libvgcode::ColorRange::get_values(), libvgcode::PathVertex::is_extrusion(), libvgcode::PathVertex::is_travel(), libvgcode::PathVertex::is_wipe(), m_sequential_view, m_viewer, libvgcode::PathVertex::position, libvgcode::Seam, Slic3r::Seam, libvgcode::PathVertex::times, and libvgcode::PathVertex::type.

Here is the call graph for this function:

◆ update_shells_color_by_extruder()

void Slic3r::GUI::GCodeViewer::update_shells_color_by_extruder ( const DynamicPrintConfig * config)
1944{
1945 if (config != nullptr)
1946 m_shells.volumes.update_colors_by_extruder(config, false);
1947}

References m_shells.

◆ view_type_from_config_name()

bool Slic3r::GUI::GCodeViewer::view_type_from_config_name ( const std::string & name,
libvgcode::EViewType & type )
static
1246{
1247 for (const auto& [config_name, value] : view_type_config_map()) {
1248 if (config_name == name) {
1249 type = value;
1250 return true;
1251 }
1252 }
1253 return false;
1254}

References Slic3r::GUI::view_type_config_map().

Referenced by apply_default_view_type().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ view_type_to_config_name()

std::string Slic3r::GUI::GCodeViewer::view_type_to_config_name ( libvgcode::EViewType type)
static
1237{
1238 for (const auto& [name, value] : view_type_config_map()) {
1239 if (value == type)
1240 return name;
1241 }
1242 return std::string();
1243}

References Slic3r::GUI::view_type_config_map().

Here is the call graph for this function:

Member Data Documentation

◆ filament_printable_reuslt

FilamentPrintableResult Slic3r::GUI::GCodeViewer::filament_printable_reuslt

Referenced by load_as_gcode().

◆ m_applied_default_view_type_key

std::string Slic3r::GUI::GCodeViewer::m_applied_default_view_type_key
private

Referenced by apply_default_view_type().

◆ m_belt_angle_deg

float Slic3r::GUI::GCodeViewer::m_belt_angle_deg = 0.f
private

◆ m_belt_layer_zs

std::vector<double> Slic3r::GUI::GCodeViewer::m_belt_layer_zs
private

Referenced by get_layers_zs(), load_as_gcode(), and reset().

◆ m_belt_show_designed

bool Slic3r::GUI::GCodeViewer::m_belt_show_designed = true
private

◆ m_belt_view_enabled

bool Slic3r::GUI::GCodeViewer::m_belt_view_enabled = false
private

◆ m_body_masses

std::vector<GCodeProcessorResult::ObjectMass> Slic3r::GUI::GCodeViewer::m_body_masses
private

◆ m_clipping_plane

std::array<float, 4> Slic3r::GUI::GCodeViewer::m_clipping_plane { 0.0f, 0.0f, 0.0f, 1.0f }
private
376{ 0.0f, 0.0f, 0.0f, 1.0f };

Referenced by set_clipping_plane(), and shadow_casters_signature().

◆ m_conflict_result

ConflictResultOpt Slic3r::GUI::GCodeViewer::m_conflict_result

Referenced by load_as_gcode().

◆ m_contained_in_bed

bool Slic3r::GUI::GCodeViewer::m_contained_in_bed { true }
private
365{ true };

Referenced by is_contained_in_bed(), load_as_gcode(), load_as_preview(), and reset().

◆ m_custom_gcode_per_print_z

std::vector<CustomGCode::Item> Slic3r::GUI::GCodeViewer::m_custom_gcode_per_print_z
private

Referenced by load_as_gcode(), and reset().

◆ m_detected_point_sizes

std::array<float, 2> Slic3r::GUI::GCodeViewer::m_detected_point_sizes = { 0.0f, 0.0f }
private
356{ 0.0f, 0.0f };

Referenced by init().

◆ m_extruders_count

size_t Slic3r::GUI::GCodeViewer::m_extruders_count
private

◆ m_filament_densities

std::vector<float> Slic3r::GUI::GCodeViewer::m_filament_densities
private

Referenced by load_as_gcode(), and reset().

◆ m_filament_diameters

std::vector<float> Slic3r::GUI::GCodeViewer::m_filament_diameters
private

Referenced by load_as_gcode(), and reset().

◆ m_fold

bool Slic3r::GUI::GCodeViewer::m_fold = {false}
private
238{false};

◆ m_gcode_check_result

GCodeCheckResult Slic3r::GUI::GCodeViewer::m_gcode_check_result

Referenced by load_as_gcode().

◆ m_gcode_result

const GCodeProcessorResult* Slic3r::GUI::GCodeViewer::m_gcode_result
private

◆ m_gl_data_initialized

bool Slic3r::GUI::GCodeViewer::m_gl_data_initialized { false }
private
208{ false };

Referenced by init().

◆ m_imex_box_mesh_wx

float Slic3r::GUI::GCodeViewer::m_imex_box_mesh_wx { 0.0f }
private
326{ 0.0f }; // clearance dimensions m_imex_toolhead_box was built for

Referenced by render_markers().

◆ m_imex_box_mesh_wy

float Slic3r::GUI::GCodeViewer::m_imex_box_mesh_wy { 0.0f }
private
327{ 0.0f };

Referenced by render_markers().

◆ m_imex_marker_key

ImexMarkerKey Slic3r::GUI::GCodeViewer::m_imex_marker_key
private

Referenced by render_markers().

◆ m_imex_marker_plan

ImexMarkerPlan Slic3r::GUI::GCodeViewer::m_imex_marker_plan
private

Referenced by render_markers().

◆ m_imex_toolhead_box

GLModel Slic3r::GUI::GCodeViewer::m_imex_toolhead_box
private

Referenced by render_markers().

◆ m_is_dark

bool Slic3r::GUI::GCodeViewer::m_is_dark = false
private

Referenced by on_change_color_mode().

◆ m_last_belt_show_designed

bool Slic3r::GUI::GCodeViewer::m_last_belt_show_designed { true }
private
211{ true };

Referenced by load_as_gcode().

◆ m_last_result_id

unsigned int Slic3r::GUI::GCodeViewer::m_last_result_id { 0 }
private
209{ 0 };

Referenced by load_as_gcode(), and reset().

◆ m_layers_slider

IMSlider* Slic3r::GUI::GCodeViewer::m_layers_slider
private

◆ m_left_extruder_filament

std::vector<ExtruderFilament> Slic3r::GUI::GCodeViewer::m_left_extruder_filament
private

◆ m_legend_enabled

bool Slic3r::GUI::GCodeViewer::m_legend_enabled { true }
private
352{ true };

Referenced by enable_legend(), and is_legend_shown().

◆ m_legend_height

float Slic3r::GUI::GCodeViewer::m_legend_height
private

Referenced by get_legend_height().

◆ m_legend_visible

bool Slic3r::GUI::GCodeViewer::m_legend_visible { true }
private
351{ true };

Referenced by is_legend_shown(), and show_legend().

◆ m_loaded_as_preview

bool Slic3r::GUI::GCodeViewer::m_loaded_as_preview { false }
private
377{ false };

Referenced by load_as_gcode(), and load_as_preview().

◆ m_machine_frame_transform_active

bool Slic3r::GUI::GCodeViewer::m_machine_frame_transform_active { false }
private
234{ false };

Referenced by is_machine_frame_transform_active(), load_as_gcode(), and reset().

◆ m_marker_filename

std::string Slic3r::GUI::GCodeViewer::m_marker_filename
private

Referenced by init(), and render_markers().

◆ m_max_bounding_box

BoundingBoxf3 Slic3r::GUI::GCodeViewer::m_max_bounding_box
private

◆ m_max_print_height

float Slic3r::GUI::GCodeViewer::m_max_print_height { 0.0f }
private
233{ 0.0f };

Referenced by get_max_print_height(), load_as_gcode(), and reset().

◆ m_move_type_counts

std::array<unsigned int, static_cast<size_t>(EMoveType::Count)> Slic3r::GUI::GCodeViewer::m_move_type_counts {}
private
216{};

Referenced by load_as_gcode(), load_as_preview(), and reset().

◆ m_move_type_distances

std::array<float, static_cast<size_t>(EMoveType::Count)> Slic3r::GUI::GCodeViewer::m_move_type_distances {}
private
218{};

Referenced by load_as_gcode(), load_as_preview(), and reset().

◆ m_move_type_times

std::array<std::array<float, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)>, static_cast<size_t>(EMoveType::Count)> Slic3r::GUI::GCodeViewer::m_move_type_times {}
private
217{};

Referenced by load_as_gcode(), load_as_preview(), and reset().

◆ m_moves_slider

IMSlider* Slic3r::GUI::GCodeViewer::m_moves_slider
private

◆ m_no_render_path

bool Slic3r::GUI::GCodeViewer::m_no_render_path { false }
mutableprivate
366{ false };

Referenced by render_markers(), and render_overlay().

◆ m_nozzle_nums

size_t Slic3r::GUI::GCodeViewer::m_nozzle_nums
private

Referenced by init(), and load_as_gcode().

◆ m_object_masses

std::vector<GCodeProcessorResult::ObjectMass> Slic3r::GUI::GCodeViewer::m_object_masses
private

◆ m_only_gcode_in_preview

bool Slic3r::GUI::GCodeViewer::m_only_gcode_in_preview {false}
private
220{false};

Referenced by is_only_gcode_in_preview(), load_as_gcode(), and reset().

◆ m_paths_bounding_box

BoundingBoxf3 Slic3r::GUI::GCodeViewer::m_paths_bounding_box
private

◆ m_plate_mass

GCodeProcessorResult::ObjectMass Slic3r::GUI::GCodeViewer::m_plate_mass
private

◆ m_plater_extruder

std::vector<int> Slic3r::GUI::GCodeViewer::m_plater_extruder
private

Referenced by get_plater_extruder().

◆ m_print_statistics

PrintEstimatedStatistics Slic3r::GUI::GCodeViewer::m_print_statistics
private

Referenced by load_as_gcode(), render_legend(), and reset().

◆ m_right_extruder_filament

std::vector<ExtruderFilament> Slic3r::GUI::GCodeViewer::m_right_extruder_filament
private

◆ m_scale

◆ m_sequential_view

◆ m_settings_ids

GCodeProcessorResult::SettingsIds Slic3r::GUI::GCodeViewer::m_settings_ids
private

Referenced by load_as_gcode().

◆ m_shell_bounding_box

BoundingBoxf3 Slic3r::GUI::GCodeViewer::m_shell_bounding_box
private

◆ m_shells

◆ m_support_masses

std::vector<GCodeProcessorResult::ObjectMass> Slic3r::GUI::GCodeViewer::m_support_masses
private

◆ m_user_mode

ConfigOptionMode Slic3r::GUI::GCodeViewer::m_user_mode
private

Referenced by init(), and render_overlay().

◆ m_view_type_sel

int Slic3r::GUI::GCodeViewer::m_view_type_sel = 0
private

Referenced by select_view_type().

◆ m_viewer

◆ m_z_offset

float Slic3r::GUI::GCodeViewer::m_z_offset { 0.0f }
private
235{ 0.0f };

Referenced by load_as_gcode(), render_markers(), and reset().

◆ options_items

std::vector<EMoveType> Slic3r::GUI::GCodeViewer::options_items
private

Referenced by update_by_mode().

◆ view_type_items

std::vector<libvgcode::EViewType> Slic3r::GUI::GCodeViewer::view_type_items
private

Referenced by select_view_type(), and update_by_mode().

◆ view_type_items_str

std::vector<std::string> Slic3r::GUI::GCodeViewer::view_type_items_str
private

Referenced by update_by_mode().


The documentation for this class was generated from the following files: