Merge remote-tracking branch 'remote/master' into SoftFever

# Conflicts:
#	resources/profiles/BBL/filament/Bambu PC @BBL X1C.json
#	resources/profiles/BBL/filament/Bambu TPU 95A @BBL X1C.json
This commit is contained in:
SoftFever 2022-07-23 20:29:33 +08:00
commit b806df7710
269 changed files with 10330 additions and 32230 deletions

View file

@ -1220,7 +1220,7 @@ int CLI::run(int argc, char **argv)
for (int i = 0; i < plate_data_list.size(); i++) {
PlateData *plate_data = plate_data_list[i];
for (auto it = plate_data->slice_flaments_info.begin(); it != plate_data->slice_flaments_info.end(); it++) {
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) {
it->type = filament_types?filament_types->get_at(it->id):"PLA";
it->color = filament_color?filament_color->get_at(it->id):"#FFFFFF";
//it->filament_id = filament_id?filament_id->get_at(it->id):"unknown";
@ -1729,7 +1729,7 @@ extern "C" {
argv_ptrs[i] = argv_narrow[i].data();
//BBS: register default exception handler
#if BBL_RELEASE_TO_PUBLIC
#if 1
SET_DEFULTER_HANDLER();
#else
AddVectoredExceptionHandler(1, CBaseException::UnhandledExceptionFilter);

View file

@ -164,9 +164,8 @@ namespace ImGui
const wchar_t HeightRangeIcon = 0x0813;
const wchar_t FoldButtonIcon = 0x0814;
const wchar_t UnfoldButtonIcon = 0x0815;
const wchar_t GcodePauseIcon = 0x0816;
const wchar_t SphereButtonIcon = 0x0817;
const wchar_t FragmentFilterIcon = 0x0818;
const wchar_t SphereButtonIcon = 0x0816;
const wchar_t FragmentFilterIcon = 0x0817;
// void MyFunction(const char* name, const MyMatrix44& v);
}

View file

@ -4117,7 +4117,7 @@ bool ImGui::BBLInputScalar(const char *label, ImGuiDataType data_type, void *p_d
if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt;
char buf[16];
char buf[8];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
bool value_changed = false;
@ -6235,7 +6235,11 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
if (g.Style.FrameBorderSize > 0.0f)
RenderFrameBorder(bb.Min, bb.Max, rounding);
else
#ifdef __APPLE__
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding,NULL,2.0f); // Color button are often in need of some sort of border
#else
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
#endif
}
// Drag and Drop Source

View file

@ -256,9 +256,15 @@ void AppConfig::set_defaults()
set("backup_interval", "10");
}
#if BBL_RELEASE_TO_PUBLIC
if (get("iot_environment").empty()) {
set("iot_environment", "3");
}
#else
if (get("iot_environment").empty()) {
set("iot_environment", "1");
}
#endif
// Remove legacy window positions/sizes
erase("app", "main_frame_maximized");
@ -1003,12 +1009,7 @@ std::string AppConfig::get_region()
std::string AppConfig::get_country_code()
{
std::string region = get_region();
/* fix PRE environment when release to public */
#if 0
this->set("iot_environment", "2");
return "ENV_CN_PRE";
#else
//if (is_engineering_region()) { return region; }
if (is_engineering_region()) { return region; }
if (region == "CHN" || region == "China")
return "CN";
else if (region == "USA")
@ -1022,7 +1023,7 @@ std::string AppConfig::get_country_code()
else
return "Others";
return "";
#endif
}
bool AppConfig::is_engineering_region(){

View file

@ -762,40 +762,7 @@ bool compSecondMoment(const ExPolygons& expolys, double& smExpolysX, double& smE
return true;
}
// BBS: thermal length is calculated according to the material of a volume
double getThermalLength(const ModelVolume* modelVolumePtr) {
double thermalLength = 200.;
auto aa = modelVolumePtr->extruder_id();
if (Model::extruderParamsMap.find(aa) != Model::extruderParamsMap.end()) {
if (Model::extruderParamsMap.at(aa).materialName == "ABS" ||
Model::extruderParamsMap.at(aa).materialName == "PA-CF" ||
Model::extruderParamsMap.at(aa).materialName == "PET-CF") {
thermalLength = 100;
}
if (Model::extruderParamsMap.at(aa).materialName == "PC") {
thermalLength = 40;
}
if (Model::extruderParamsMap.at(aa).materialName == "TPU") {
thermalLength = 1000;
}
}
return thermalLength;
}
// BBS: thermal length calculation for a group of volumes
double getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs)
{
double thermalLength = 1250.;
for (const auto& modelVolumePtr : modelVolumePtrs) {
if (modelVolumePtr != nullptr) {
// the thermal length of a group is decided by the volume with shortest thermal length
thermalLength = std::min(thermalLength, getThermalLength(modelVolumePtr));
}
}
return thermalLength;
}
//BBS: config brimwidth by volumes
double configBrimWidthByVolumes(double deltaT, double adhension, double maxSpeed, const ModelVolume* modelVolumePtr, const ExPolygons& expolys)
@ -825,7 +792,7 @@ double configBrimWidthByVolumes(double deltaT, double adhension, double maxSpeed
const double& bboxX = bbox2.size()(0);
const double& bboxY = bbox2.size()(1);
double thermalLength = sqrt(bboxX * bboxX + bboxY * bboxY) * SCALING_FACTOR;
double thermalLengthRef = getThermalLength(modelVolumePtr);
double thermalLengthRef = Model::getThermalLength(modelVolumePtr);
double height_to_area = std::max(height / Ixx * (bbox2.size()(1) * SCALING_FACTOR), height / Iyy * (bbox2.size()(0) * SCALING_FACTOR));
double brim_width = adhension * std::min(std::min(std::max(height_to_area * maxSpeed / 24, thermalLength * 8. / thermalLengthRef * std::min(height, 30.) / 30.), 18.), 1.5 * thermalLength);
@ -846,8 +813,12 @@ double configBrimWidthByVolumeGroups(double adhension, double maxSpeed, const st
BoundingBoxf3 mergedBbx;
for (const auto& modelVolumePtr : modelVolumePtrs) {
if (modelVolumePtr->is_model_part()) {
auto rawBoundingbox = modelVolumePtr->mesh().transformed_bounding_box(modelVolumePtr->get_matrix());
auto bbox = modelVolumePtr->get_object()->instances.front()->transform_bounding_box(rawBoundingbox);
Slic3r::Transform3d t;
if (modelVolumePtr->get_object()->instances.size() > 0)
t = modelVolumePtr->get_object()->instances.front()->get_matrix() * modelVolumePtr->get_matrix();
else
t = modelVolumePtr->get_matrix();
auto bbox = modelVolumePtr->mesh().transformed_bounding_box(t);
mergedBbx.merge(bbox);
}
}
@ -870,7 +841,7 @@ double configBrimWidthByVolumeGroups(double adhension, double maxSpeed, const st
const double& bboxX = bbox2.size()(0);
const double& bboxY = bbox2.size()(1);
double thermalLength = sqrt(bboxX * bboxX + bboxY * bboxY) * SCALING_FACTOR;
double thermalLengthRef = getThermalLength(modelVolumePtrs);
double thermalLengthRef = Model::getThermalLength(modelVolumePtrs);
double height_to_area = std::max(height / Ixx * (bbox2.size()(1) * SCALING_FACTOR), height / Iyy * (bbox2.size()(0) * SCALING_FACTOR));
double brim_width = adhension * std::min(std::min(std::max(height_to_area * maxSpeed / 24, thermalLength * 8. / thermalLengthRef * std::min(height, 30.) / 30.), 18.), 1.5 * thermalLength);
@ -884,26 +855,13 @@ double configBrimWidthByVolumeGroups(double adhension, double maxSpeed, const st
}
//BBS: create all brims
static ExPolygons outer_inner_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
static ExPolygons outer_inner_brim_area(const Print& print,
const float no_brim_offset, std::map<ObjectID, ExPolygons>& brimAreaMap,
std::map<ObjectID, ExPolygons>& supportBrimAreaMap,
std::vector<std::pair<ObjectID, unsigned int>>& objPrintVec,
std::vector<unsigned int>& printExtruders)
{
std::unordered_set<size_t> top_level_objects_idx;
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
for (const PrintObject* object : top_level_objects_with_brim)
top_level_objects_idx.insert(object->id().id);
unsigned int support_material_extruder = printExtruders.front() + 1;
auto allExtruders = print.extruders();
if (print.has_support_material()) {
assert(top_level_objects_with_brim.front()->config().support_filament >= 0);
if (top_level_objects_with_brim.front()->config().support_filament > 0)
support_material_extruder = top_level_objects_with_brim.front()->config().support_filament;
allExtruders.push_back(support_material_extruder - 1);
sort_remove_duplicates(allExtruders);
}
ExPolygons brim_area;
ExPolygons no_brim_area;
@ -927,7 +885,6 @@ static ExPolygons outer_inner_brim_area(const Print& print, const ConstPrintObje
float brim_offset = scale_(object->config().brim_object_gap.value);
double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR;
float brim_width = scale_(floor(object->config().brim_width.value / flowWidth / 2) * flowWidth * 2);
const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
const float scaled_flow_width = print.brim_flow().scaled_spacing();
const float scaled_additional_brim_width = scale_(floor(5 / flowWidth / 2) * flowWidth * 2);
const float scaled_half_min_adh_length = scale_(1.1);
@ -1017,8 +974,13 @@ static ExPolygons outer_inner_brim_area(const Print& print, const ConstPrintObje
if (brimAreaMap.find(object->id()) != brimAreaMap.end())
expolygons_append(brim_area, brimAreaMap[object->id()]);
}
if ((print.config().print_sequence == PrintSequence::ByObject) && top_level_objects_with_brim.front()->config().support_filament == 0)
support_material_extruder = objectWithExtruder.second;
support_material_extruder = object->config().support_filament;
if (support_material_extruder == 0 && object->has_support_material()) {
if (print.config().print_sequence == PrintSequence::ByObject)
support_material_extruder = objectWithExtruder.second;
else
support_material_extruder = printExtruders.front() + 1;
}
if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) {
if (!object->support_layers().empty()) {
for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) {
@ -1658,10 +1620,7 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
std::map<ObjectID, ExPolygons> supportBrimAreaMap;
Flow flow = print.brim_flow();
const auto scaled_resolution = scaled<double>(print.config().resolution.value);
std::vector<ExPolygons> bottom_layers_expolygons = get_print_bottom_layers_expolygons(print);
ConstPrintObjectPtrs top_level_objects_with_brim = get_top_level_objects_with_brim(print, bottom_layers_expolygons);
Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim, scaled_resolution);
ExPolygons islands_area_ex = outer_inner_brim_area(print, top_level_objects_with_brim,
ExPolygons islands_area_ex = outer_inner_brim_area(print,
float(flow.scaled_spacing()), brimAreaMap, supportBrimAreaMap, objPrintVec, printExtruders);
// BBS: Find boundingbox of the first layer

View file

@ -122,8 +122,6 @@ set(lisbslic3r_sources
GCode/SpiralVase.hpp
GCode/SeamPlacer.cpp
GCode/SeamPlacer.hpp
GCode/SpeedGenerator.cpp
GCode/SpeedGenerator.hpp
GCode/ToolOrdering.cpp
GCode/ToolOrdering.hpp
GCode/WipeTower.cpp
@ -317,6 +315,12 @@ set(lisbslic3r_sources
SLA/ReprojectPointsOnMesh.hpp
)
if (APPLE)
list(APPEND lisbslic3r_sources
MacUtils.mm
)
endif ()
add_library(libslic3r STATIC ${lisbslic3r_sources}
"${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h"
${OpenVDBUtils_SOURCES})

View file

@ -4,6 +4,9 @@
#include <cassert>
#include "Geometry.hpp"
//BBS: Refer to ArcWelderLib for the arc fitting functions
namespace Slic3r {
//BBS: threshold used to judge collineation

View file

@ -127,6 +127,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
std::vector<std::vector<const SurfaceFillParams*>> region_to_surface_params(layer.regions().size(), std::vector<const SurfaceFillParams*>());
SurfaceFillParams params;
bool has_internal_voids = false;
const PrintObjectConfig& object_config = layer.object()->config();
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
const LayerRegion &layerm = *layer.regions()[region_id];
region_to_surface_params[region_id].assign(layerm.fill_surfaces.size(), nullptr);
@ -163,7 +164,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
params.flow = params.bridge ?
//BBS: always enable thick bridge for internal bridge
layerm.bridging_flow(extrusion_role, (surface.is_bridge() && !surface.is_external()) || g_config_thick_bridges) :
layerm.bridging_flow(extrusion_role, (surface.is_bridge() && !surface.is_external()) || object_config.thick_bridges) :
layerm.flow(extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness);
// Calculate flow spacing for infill pattern generation.

View file

@ -80,9 +80,8 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface* surface, cons
ThickPolylines polylines;
for (ExPolygon& ex : gaps_ex_sorted) {
//BBS: medial axis algorithm can't handle duplicated points in expolygon.
//Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION);
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION * 0.1);
ex.medial_axis(max, min, &polylines);
}
@ -114,9 +113,8 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface* surface, cons
ThickPolylines polylines;
for (ExPolygon& ex : external_gaps_collapsed) {
//BBS: medial axis algorithm can't handle duplicated points in expolygon.
//Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION);
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION * 0.1);
ex.medial_axis(max, min, &polylines);
}

View file

@ -3156,7 +3156,7 @@ void FillMonotonicLineWGapFill::fill_surface_extrusion(const Surface* surface, c
ThickPolylines polylines;
for (ExPolygon& ex : gaps_ex_sorted) {
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION);
ex.douglas_peucker(SCALED_RESOLUTION * 0.1);
ex.medial_axis(max, min, &polylines);
}

View file

@ -232,6 +232,7 @@ static constexpr const char* LOCK_ATTR = "locked";
static constexpr const char* GCODE_FILE_ATTR = "gcode_file";
static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file";
static constexpr const char* PATTERN_FILE_ATTR = "pattern_file";
static constexpr const char* PATTERN_BBOX_FILE_ATTR = "pattern_bbox_file";
static constexpr const char* OBJECT_ID_ATTR = "object_id";
static constexpr const char* INSTANCEID_ATTR = "instance_id";
static constexpr const char* PLATERID_ATTR = "plater_id";
@ -451,7 +452,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
info.id = it->first;
info.used_m = used_filament_m;
info.used_g = used_filament_g;
slice_flaments_info.push_back(info);
slice_filaments_info.push_back(info);
}
}
@ -1464,9 +1465,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
plate_data_list[it->first-1]->gcode_prediction = it->second->gcode_prediction;
plate_data_list[it->first-1]->gcode_weight = it->second->gcode_weight;
plate_data_list[it->first-1]->toolpath_outside = it->second->toolpath_outside;
plate_data_list[it->first-1]->slice_flaments_info = it->second->slice_flaments_info;
plate_data_list[it->first-1]->slice_filaments_info = it->second->slice_filaments_info;
plate_data_list[it->first-1]->thumbnail_file = (m_load_restore || it->second->thumbnail_file.empty()) ? it->second->thumbnail_file : m_backup_path + "/" + it->second->thumbnail_file;
plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file;
plate_data_list[it->first-1]->pattern_bbox_file = (m_load_restore || it->second->pattern_bbox_file.empty()) ? it->second->pattern_bbox_file : m_backup_path + "/" + it->second->pattern_bbox_file;
it++;
}
@ -3039,6 +3041,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
{
m_curr_plater->pattern_file = value;
}
else if (key == PATTERN_BBOX_FILE_ATTR)
{
m_curr_plater->pattern_bbox_file = value;
}
else if (key == INSTANCEID_ATTR)
{
m_curr_instance.instance_id = atoi(value.c_str());
@ -3110,7 +3116,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
filament_info.color = color;
filament_info.used_m = atof(used_m.c_str());
filament_info.used_g = atof(used_g.c_str());
m_curr_plater->slice_flaments_info.push_back(filament_info);
m_curr_plater->slice_filaments_info.push_back(filament_info);
}
return true;
}
@ -5327,10 +5333,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n";
}
if (plate_data->pattern_thumbnail.is_valid()) {
if (!plate_data->pattern_file.empty()) {
std::string pattern_file_in_3mf = (boost::format(PATTERN_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_file_in_3mf << "\"/>\n";
}
if (!plate_data->pattern_bbox_file.empty()) {
std::string pattern_bbox_file_in_3mf = (boost::format(PATTERN_CONFIG_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_BBOX_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_bbox_file_in_3mf << "\"/>\n";
}
if (instance_size > 0)
{
@ -5430,7 +5440,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_WEIGHT_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_weight_str() << "\"/>\n";
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OUTSIDE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->toolpath_outside << "\"/>\n";
for (auto it = plate_data->slice_flaments_info.begin(); it != plate_data->slice_flaments_info.end(); it++)
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++)
{
stream << " <" << FILAMENT_TAG << " " << FILAMENT_ID_TAG << "=\"" << std::to_string(it->id + 1) << "\" "
<< FILAMENT_TYPE_TAG << "=\"" << it->type << "\" "
@ -5903,7 +5913,8 @@ private:
break;
case AddObject: {
{
_BBS_3MF_Exporter e;
CNumericLocalesSetter locales_setter;
_BBS_3MF_Exporter e;
e.save_object_mesh(t.path, *t.object, (int) t.id);
// response to delete cloned object
}

View file

@ -30,7 +30,7 @@ public:
std::string _3mf_thumbnail;
std::string _3mf_printer_thumbnail_middle;
std::string _3mf_printer_thumbnail_small;
PackingTemporaryData() {}
};
@ -63,9 +63,10 @@ struct PlateData
ThumbnailData plate_thumbnail;
ThumbnailData pattern_thumbnail;
std::string pattern_file;
std::string pattern_bbox_file;
std::string gcode_prediction;
std::string gcode_weight;
std::vector<FilamentInfo> slice_flaments_info;
std::vector<FilamentInfo> slice_filaments_info;
bool is_sliced_valid = false;
bool toolpath_outside {false};
@ -114,7 +115,7 @@ enum class LoadStrategy
{
Default = 0,
AddDefaultInstances = 1,
CheckVersion = 2,
CheckVersion = 2,
LoadModel = 4,
LoadConfig = 8,
LoadAuxiliary = 16,
@ -223,7 +224,7 @@ extern bool store_bbs_3mf(StoreParams& store_params);
extern void release_PlateData_list(PlateDataPtrs& plate_data_list);
// backup & restore project
// backup & restore project
extern void save_object_mesh(ModelObject& object);

View file

@ -2542,6 +2542,24 @@ GCode::LayerResult GCode::process_layer(
// Shall the support interface be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
bool interface_dontcare = object.config().support_interface_filament.value == 0;
// BBS: apply wiping overridden extruders
WipingExtrusions& wiping_extrusions = const_cast<LayerTools&>(layer_tools).wiping_extrusions();
if (support_dontcare) {
int extruder_override = wiping_extrusions.get_support_extruder_overrides(&object);
if (extruder_override >= 0) {
support_extruder = extruder_override;
support_dontcare = false;
}
}
if (interface_dontcare) {
int extruder_override = wiping_extrusions.get_support_interface_extruder_overrides(&object);
if (extruder_override >= 0) {
interface_extruder = extruder_override;
interface_dontcare = false;
}
}
// BBS: try to print support base with a filament other than interface filament
if (support_dontcare && !interface_dontcare) {
unsigned int dontcare_extruder = first_extruder_id;
@ -2609,7 +2627,16 @@ GCode::LayerResult GCode::process_layer(
// Shall the support interface be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
bool interface_dontcare = object.config().support_interface_filament.value == 0;
// BBS: apply wiping overridden extruders
WipingExtrusions& wiping_extrusions = const_cast<LayerTools&>(layer_tools).wiping_extrusions();
if (support_dontcare) {
int extruder_override = wiping_extrusions.get_support_extruder_overrides(&object);
if (extruder_override >= 0) {
support_extruder = extruder_override;
support_dontcare = false;
}
}
if (support_dontcare || interface_dontcare) {
// Some support will be printed with "don't care" material, preferably non-soluble.
// Is the current extruder assigned a soluble filament?
@ -2897,8 +2924,12 @@ GCode::LayerResult GCode::process_layer(
// BBS
WipingExtrusions& wiping_extrusions = const_cast<LayerTools&>(layer_tools).wiping_extrusions();
bool support_overridden = wiping_extrusions.is_support_overridden(layer.object());
bool support_intf_overridden = wiping_extrusions.is_support_interface_overridden(layer.object());
ExtrusionRole support_extrusion_role = instance_to_print.object_by_extruder.support_extrusion_role;
if (print_wipe_extrusions == 0)
bool is_overridden = support_extrusion_role == erSupportMaterialInterface ? support_intf_overridden : support_overridden;
if (is_overridden == (print_wipe_extrusions != 0))
support_eec.entities = filter_by_extrusion_role(instance_to_print.object_by_extruder.support->entities, instance_to_print.object_by_extruder.support_extrusion_role);
for (auto& ptr : support_eec.entities)

View file

@ -1,50 +0,0 @@
#include "SpeedGenerator.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/Utils.hpp"
#define BOOST_SPIRIT_THREADSAFE
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/date_time.hpp>
#include <boost/foreach.hpp>
namespace Slic3r {
SpeedGenerator::SpeedGenerator() {
// default is 100 speed
for (int i = 0; i < 6; i++) {
speed_table[i] = 100;
}
std::string config_file = resources_dir() + "/PerimeterSpeedConfig.json";
std::string encoded_path = encode_path(config_file.c_str());
boost::property_tree::read_json<boost::property_tree::ptree>(encoded_path, root);
if (root.count("speed_table")) {
int i = 0;
auto array6 = root.get_child("speed_table");
for (auto pos = array6.begin(); pos != array6.end() && i < 6; pos++, i++)
speed_table[i] = pos->second.get_value<int>();
}
}
double SpeedGenerator::calculate_speed(const ExtrusionPath& path, double max_speed, double min_speed) {
// limit the speed in case of F0 generated in gcode when user set 0 speed in UI
// which cause printer stopped. 1mm/s is slow enough and can make printer not really stopped.
max_speed = max_speed < 1 ? 1 : max_speed;
min_speed = min_speed < 1 ? 1 : min_speed;
// switch min and max speed if user set the max speed to be slower than min_speed
if (max_speed < min_speed) {
double temp = max_speed;
max_speed = min_speed;
min_speed = temp;
}
speed_table[0] = max_speed;
int overhang_degree = path.get_overhang_degree();
assert(overhang_degree >= 0 && overhang_degree <= 6);
double speed = (double)speed_table[overhang_degree];
speed = std::max(speed, min_speed);
speed = std::min(speed, max_speed);
return speed;
}
}

View file

@ -1,22 +0,0 @@
#ifndef libslic3r_SpeedGenerator_hpp_
#define libslic3r_SpeedGenerator_hpp_
#include <string>
namespace Slic3r {
class ExtrusionPath;
class SpeedGenerator {
public:
SpeedGenerator();
double calculate_speed(const ExtrusionPath& path, double max_speed, double min_speed);
private:
boost::property_tree::ptree root;
int speed_table[6];
};
}
#endif // libslic3r_SpeedGenerator_hpp_

View file

@ -304,6 +304,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
layer_tools.extruders.push_back(extruder_interface);
if (has_support || has_interface) {
layer_tools.has_support = true;
layer_tools.wiping_extrusions().is_support_overriddable_and_mark(role, object);
}
}
@ -321,6 +322,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
layer_tools.extruders.push_back(extruder_interface);
if (has_support || has_interface) {
layer_tools.has_support = true;
layer_tools.wiping_extrusions().is_support_overriddable_and_mark(role, object);
}
}
@ -797,6 +799,19 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, size
copies_vector[copy_id] = extruder;
}
// BBS
void WipingExtrusions::set_support_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies)
{
something_overridden = true;
support_map.emplace(object, extruder);
}
void WipingExtrusions::set_support_interface_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies)
{
something_overridden = true;
support_intf_map.emplace(object, extruder);
}
// Finds first non-soluble extruder on the layer
int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const
{
@ -834,6 +849,25 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con
return true;
}
// BBS
bool WipingExtrusions::is_support_overriddable(const ExtrusionRole role, const PrintObject& object) const
{
if (!object.config().flush_into_support)
return false;
if (role == erMixed) {
return object.config().support_filament == 0 || object.config().support_interface_filament == 0;
}
else if (role == erSupportMaterial || role == erSupportTransition) {
return object.config().support_filament == 0;
}
else if (role == erSupportMaterialInterface) {
return object.config().support_interface_filament == 0;
}
return false;
}
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
// and returns volume that is left to be wiped on the wipe tower.
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe)
@ -844,6 +878,10 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
if (! this->something_overridable || volume_to_wipe <= 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder))
return std::max(0.f, volume_to_wipe); // Soluble filament cannot be wiped in a random infill, neither the filament after it
// BBS
if (print.config().filament_is_support.get_at(old_extruder))
return std::max(0.f, volume_to_wipe); // Support filament cannot be used to print support, infill, wipe_tower, etc.
// we will sort objects so that dedicated for wiping are at the beginning:
ConstPrintObjectPtrs object_list = print.objects().vector();
std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config().flush_into_objects; });
@ -876,7 +914,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
for (const LayerRegion *layerm : this_layer->regions()) {
const auto &region = layerm->region();
if (!object->config().flush_into_infill && !object->config().flush_into_objects)
if (!object->config().flush_into_infill && !object->config().flush_into_objects && !object->config().flush_into_support)
continue;
bool wipe_into_infill_only = !object->config().flush_into_objects && object->config().flush_into_infill;
bool is_infill_first = print.config().wall_infill_order == WallInfillOrder::InfillInnerOuter ||
@ -918,6 +956,46 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
}
}
}
// BBS
if (object->config().flush_into_support) {
auto& object_config = object->config();
const SupportLayer* this_support_layer = object->get_support_layer_at_printz(lt.print_z, EPSILON);
const TreeSupportLayer* this_tree_support_layer = object->get_tree_support_layer_at_printz(lt.print_z, EPSILON);
do {
if (this_support_layer == nullptr && this_tree_support_layer == nullptr)
break;
bool support_overriddable = object_config.support_filament == 0;
bool support_intf_overriddable = object_config.support_interface_filament == 0;
if (!support_overriddable && !support_intf_overriddable)
break;
auto& entities = this_support_layer != nullptr ? this_support_layer->support_fills.entities : this_tree_support_layer->support_fills.entities;
if (support_overriddable && !is_support_overridden(object)) {
set_support_extruder_override(object, copy, new_extruder, num_of_copies);
for (const ExtrusionEntity* ee : entities) {
if (ee->role() == erSupportMaterial || ee->role() == erSupportTransition)
volume_to_wipe -= ee->total_volume();
if (volume_to_wipe <= 0.f)
return 0.f;
}
}
if (support_intf_overriddable && !is_support_interface_overridden(object)) {
set_support_interface_extruder_override(object, copy, new_extruder, num_of_copies);
for (const ExtrusionEntity* ee : entities) {
if (ee->role() == erSupportMaterialInterface)
volume_to_wipe -= ee->total_volume();
if (volume_to_wipe <= 0.f)
return 0.f;
}
}
} while (0);
}
}
}
// Some purge remains to be done on the Wipe Tower.
@ -1010,4 +1088,24 @@ const WipingExtrusions::ExtruderPerCopy* WipingExtrusions::get_extruder_override
return overrides;
}
// BBS
int WipingExtrusions::get_support_extruder_overrides(const PrintObject* object)
{
auto iter = support_map.find(object);
if (iter != support_map.end())
return iter->second;
return -1;
}
int WipingExtrusions::get_support_interface_extruder_overrides(const PrintObject* object)
{
auto iter = support_intf_map.find(object);
if (iter != support_intf_map.end())
return iter->second;
return -1;
}
} // namespace Slic3r

View file

@ -32,6 +32,8 @@ public:
// This is called from GCode::process_layer - see implementation for further comments:
const ExtruderPerCopy* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies);
int get_support_extruder_overrides(const PrintObject* object);
int get_support_interface_extruder_overrides(const PrintObject* object);
// This function goes through all infill entities, decides which ones will be used for wiping and
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
@ -46,6 +48,22 @@ public:
return out;
}
// BBS
bool is_support_overriddable(const ExtrusionRole role, const PrintObject& object) const;
bool is_support_overriddable_and_mark(const ExtrusionRole role, const PrintObject& object) {
bool out = this->is_support_overriddable(role, object);
this->something_overridable |= out;
return out;
}
bool is_support_overridden(const PrintObject* object) const {
return support_map.find(object) != support_map.end();
}
bool is_support_interface_overridden(const PrintObject* object) const {
return support_intf_map.find(object) != support_intf_map.end();
}
void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; }
private:
@ -54,6 +72,9 @@ private:
// This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
void set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies);
// BBS
void set_support_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies);
void set_support_interface_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies);
// Returns true in case that entity is not printed with its usual extruder for a given copy:
bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const {
@ -62,6 +83,9 @@ private:
}
std::map<const ExtrusionEntity*, ExtruderPerCopy> entity_map; // to keep track of who prints what
// BBS
std::map<const PrintObject*, int> support_map;
std::map<const PrintObject*, int> support_intf_map;
bool something_overridable = false;
bool something_overridden = false;
const LayerTools* m_layer_tools = nullptr; // so we know which LayerTools object this belongs to

View file

@ -251,6 +251,12 @@ public:
};
std::vector<std::pair<ExPolygon *, int>> area_groups;
enum OverhangType {
Detected=0,
Enforced
};
std::map<const ExPolygon *, OverhangType> overhang_types;
virtual bool has_extrusions() const { return !support_fills.empty(); }
void simplify_support_extrusion_path() { this->simplify_support_entity_collection(&support_fills);}

View file

@ -70,6 +70,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
const PrintConfig &print_config = this->layer()->object()->print()->config();
const PrintRegionConfig &region_config = this->region().config();
const PrintObjectConfig& object_config = this->layer()->object()->config();
// This needs to be in sync with PrintObject::_slice() slicing_mode_normal_below_layer!
bool spiral_mode = print_config.spiral_mode &&
//FIXME account for raft layers.
@ -100,7 +101,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
g.layer_id = (int)this->layer()->id();
g.ext_perimeter_flow = this->flow(frExternalPerimeter);
g.overhang_flow = this->bridging_flow(frPerimeter, g_config_thick_bridges);
g.overhang_flow = this->bridging_flow(frPerimeter, object_config.thick_bridges);
g.solid_infill_flow = this->flow(frSolidInfill);
g.process();
@ -118,6 +119,9 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
const bool has_infill = this->region().config().sparse_infill_density.value > 0.;
const float margin = float(scale_(EXTERNAL_INFILL_MARGIN));
// BBS
const PrintObjectConfig& object_config = this->layer()->object()->config();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-initial");
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
@ -285,7 +289,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// would get merged into a single one while they need different directions
// also, supply the original expolygon instead of the grown one, because in case
// of very thin (but still working) anchors, the grown expolygon would go beyond them
BridgeDetector bd(initial, lower_layer->lslices, this->bridging_flow(frInfill, g_config_thick_bridges).scaled_width());
BridgeDetector bd(initial, lower_layer->lslices, this->bridging_flow(frInfill, object_config.thick_bridges).scaled_width());
#ifdef SLIC3R_DEBUG
printf("Processing bridge at layer %zu:\n", this->layer()->id());
#endif

View file

@ -0,0 +1,10 @@
#ifndef __MAC_UTILS_H
#define __MAC_UTILS_H
namespace Slic3r {
bool is_macos_support_boost_add_file_log();
}
#endif

15
src/libslic3r/MacUtils.mm Normal file
View file

@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
#import "MacUtils.hpp"
namespace Slic3r {
bool is_macos_support_boost_add_file_log()
{
if (@available(macOS 12.0, *)) {
return true;
} else {
return false;
}
}
}; // namespace Slic3r

View file

@ -2754,6 +2754,41 @@ double Model::findMaxSpeed(const ModelObject* object) {
if (objMaxSpeed <= 0) objMaxSpeed = 250.;
return objMaxSpeed;
}
// BBS: thermal length is calculated according to the material of a volume
double Model::getThermalLength(const ModelVolume* modelVolumePtr) {
double thermalLength = 200.;
auto aa = modelVolumePtr->extruder_id();
if (Model::extruderParamsMap.find(aa) != Model::extruderParamsMap.end()) {
if (Model::extruderParamsMap.at(aa).materialName == "ABS" ||
Model::extruderParamsMap.at(aa).materialName == "PA-CF" ||
Model::extruderParamsMap.at(aa).materialName == "PET-CF") {
thermalLength = 100;
}
if (Model::extruderParamsMap.at(aa).materialName == "PC") {
thermalLength = 40;
}
if (Model::extruderParamsMap.at(aa).materialName == "TPU") {
thermalLength = 1000;
}
}
return thermalLength;
}
// BBS: thermal length calculation for a group of volumes
double Model::getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs)
{
double thermalLength = 1250.;
for (const auto& modelVolumePtr : modelVolumePtrs) {
if (modelVolumePtr != nullptr) {
// the thermal length of a group is decided by the volume with shortest thermal length
thermalLength = std::min(thermalLength, getThermalLength(modelVolumePtr));
}
}
return thermalLength;
}
// max printing speed, difference in bed temperature and envirument temperature and bed adhension coefficients are considered
double ModelInstance::get_auto_brim_width(double deltaT, double adhension) const
{
@ -2763,9 +2798,10 @@ double ModelInstance::get_auto_brim_width(double deltaT, double adhension) const
auto bbox_size = transform_bounding_box(raw_bbox).size();
double height_to_area = std::max(bbox_size(2) / (bbox_size(0) * bbox_size(0) * bbox_size(1)),
bbox_size(2) / (bbox_size(1) * bbox_size(1) * bbox_size(0)));
double thermalLength = std::max(bbox_size(0), bbox_size(1));
double thermalLength = sqrt(bbox_size(0)* bbox_size(0) + bbox_size(1)* bbox_size(1));
double thermalLengthRef = Model::getThermalLength(object->volumes);
double brim_width = adhension * std::min(std::min(std::max(height_to_area * 200 * maxSpeed/200, (deltaT-30)/75 * thermalLength * 0.15), 20.), 1.5 * thermalLength);
double brim_width = adhension * std::min(std::min(std::max(height_to_area * 200 * maxSpeed/200, thermalLength * 8. / thermalLengthRef * std::min(bbox_size(2), 30.) / 30.), 20.), 1.5 * thermalLength);
// small brims are omitted
if (brim_width < 5 && brim_width < 1.5 * thermalLength)
brim_width = 0;

View file

@ -1274,6 +1274,9 @@ public:
ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr);
// BBS
static double findMaxSpeed(const ModelObject* object);
static double getThermalLength(const ModelVolume* modelVolumePtr);
static double getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs);
// BBS: backup
static Model read_from_archive(
const std::string& input_file,

View file

@ -553,58 +553,33 @@ void PerimeterGenerator::process()
offset_top_surface = 0;
//don't takes into account too thin areas
double min_width_top_surface = std::max(double(ext_perimeter_spacing / 2 + 10), 1.0 * (double(perimeter_width)));
//make thin upper surfaces disapear with -+offset_top_surface
ExPolygons grown_upper_slices;
//do offset2 per island, to avoid big blob merging
//remove polygon too thin (but don't mess with holes)
for (const ExPolygon& expoly_to_grow : *this->upper_slices) {
//only offset the contour, as it can merge holes
Polygons contour = offset2({ ExPolygon(expoly_to_grow.contour) }, -offset_top_surface, offset_top_surface + min_width_top_surface);
if (!contour.empty()) {
if (expoly_to_grow.holes.empty()) {
for (Polygon& p : contour)
grown_upper_slices.push_back(ExPolygon{ p });
}
else {
Polygons holes = expoly_to_grow.holes;
for (Polygon& h : holes)
h.reverse();
holes = offset(holes, -min_width_top_surface);
for (ExPolygon p : diff_ex(contour, holes))
grown_upper_slices.push_back(p);
}
}
}
grown_upper_slices = union_ex(grown_upper_slices);
ExPolygons grown_upper_slices = offset_ex(*this->upper_slices, min_width_top_surface);
//set the clip to a virtual "second perimeter"
fill_clip = offset_ex(last, -double(ext_perimeter_spacing));
auto fill_clip_old = fill_clip;
// get the real top surface
const ExPolygons top_grown_polygons = diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes);
ExPolygons top_polygons = diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes);
//get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the min_width_top_surface we removed a bit before)
//also remove the ext_perimeter_spacing/2 width because we are faking the external periemter, and we will remove ext_perimeter_spacing2
const ExPolygons inner_polygons = diff_ex(last,
offset_ex(top_grown_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)),
ApplySafetyOffset::Yes);
ExPolygons inner_polygons = diff_ex(last,
offset_ex(top_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)),
ApplySafetyOffset::Yes);
// get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly the polygons to fill.
const ExPolygons top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes);
top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes);
// increase by half peri the inner space to fill the frontier between last and stored.
top_fills = union_ex(top_fills, top_polygons);
//set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap.
double infill_spacing_unscaled = this->config->sparse_infill_line_width.value;
//if (infill_spacing_unscaled == 0) infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, nozzle_diameter);
fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2));
last = intersection_ex(inner_polygons, last);
//{
// std::stringstream stri;
// stri << this->layer->id() << "_1_"<< i <<"_only_one_peri"<< ".svg";
// SVG svg(stri.str());
// svg.draw(to_polylines(oldLast), "orange");
// svg.draw(to_polylines(fill_clip), "purple");
// svg.draw(to_polylines(top_fills), "green");
// svg.draw(to_polylines(inner_polygons), "yellow");
// svg.draw(to_polylines(top_polygons), "cyan");
// svg.draw(to_polylines(oldLast), "orange");
// svg.draw(to_polylines(last), "red");
// svg.draw(to_polylines(fill_clip_old), "green");
// svg.Close();
//}
}
@ -700,9 +675,8 @@ void PerimeterGenerator::process()
offset2_ex(gaps, - float(max / 2.), float(max / 2. + ClipperSafetyOffset)));
ThickPolylines polylines;
for (ExPolygon& ex : gaps_ex) {
//BBS: medial axis algorithm can't handle duplicated points in expolygon.
//Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION);
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(surface_simplify_resolution);
ex.medial_axis(max, min, &polylines);
}

View file

@ -58,7 +58,7 @@ public:
overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config),
m_spiral_vase(spiral_mode),
m_scaled_resolution(scaled<double>(print_config->resolution.value)),
m_scaled_resolution(scaled<double>(print_config->resolution.value > EPSILON ? print_config->resolution.value : EPSILON)),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1), m_ext_mm3_per_mm_smaller_width(-1)
{}

View file

@ -311,6 +311,54 @@ bool Polyline::is_straight() const
return true;
}
void Polyline::append(const Polyline &src)
{
if (!src.is_valid()) return;
if (this->points.empty()) {
this->points = src.points;
this->fitting_result = src.fitting_result;
} else {
//BBS: append the first point to create connection first, update the fitting date as well
this->append(src.points[0]);
//BBS: append a polyline which has fitting data to a polyline without fitting data.
//Then create a fake fitting data first, so that we can keep the fitting data in last polyline
if (this->fitting_result.empty() &&
!src.fitting_result.empty()) {
this->fitting_result.emplace_back(PathFittingData{ 0, this->points.size() - 1, EMovePathType::Linear_move, ArcSegment() });
}
//BBS: then append the remain points
MultiPoint::append(src.points.begin() + 1, src.points.end());
//BBS: finally append the fitting data
append_fitting_result_after_append_polyline(src);
}
}
void Polyline::append(Polyline &&src)
{
if (!src.is_valid()) return;
if (this->points.empty()) {
this->points = std::move(src.points);
this->fitting_result = std::move(src.fitting_result);
} else {
//BBS: append the first point to create connection first, update the fitting date as well
this->append(src.points[0]);
//BBS: append a polyline which has fitting data to a polyline without fitting data.
//Then create a fake fitting data first, so that we can keep the fitting data in last polyline
if (this->fitting_result.empty() &&
!src.fitting_result.empty()) {
this->fitting_result.emplace_back(PathFittingData{ 0, this->points.size() - 1, EMovePathType::Linear_move, ArcSegment() });
}
//BBS: then append the remain points
MultiPoint::append(src.points.begin() + 1, src.points.end());
//BBS: finally append the fitting data
append_fitting_result_after_append_polyline(src);
src.points.clear();
src.fitting_result.clear();
}
}
void Polyline::append_fitting_result_after_append_points() {
if (!fitting_result.empty()) {
if (fitting_result.back().is_linear_move()) {
@ -326,14 +374,6 @@ void Polyline::append_fitting_result_after_append_points() {
void Polyline::append_fitting_result_after_append_polyline(const Polyline& src)
{
//BBS: append a polyline which has fitting data to a polyline without fitting data.
//Then create a fake fitting data first, so that we can keep the fitting data in last polyline
if (this->fitting_result.empty() &&
!src.fitting_result.empty()) {
if (!this->points.empty())
this->fitting_result.emplace_back(PathFittingData{ 0, this->size() - 1, EMovePathType::Linear_move, ArcSegment() });
}
if (!this->fitting_result.empty()) {
//BBS: offset and save the fitting_result from src polyline
if (!src.fitting_result.empty()) {
@ -346,7 +386,7 @@ void Polyline::append_fitting_result_after_append_polyline(const Polyline& src)
}
} else {
//BBS: the append polyline has no fitting data, then append as linear move directly
size_t new_start = fitting_result.back().end_point_index;
size_t new_start = this->fitting_result.back().end_point_index;
size_t new_end = this->size() - 1;
if (new_start != new_end)
this->fitting_result.emplace_back(PathFittingData{ new_start, new_end, EMovePathType::Linear_move, ArcSegment() });

View file

@ -99,41 +99,8 @@ public:
MultiPoint::append(std::move(src));
append_fitting_result_after_append_points();
}
void append(const Polyline &src)
{
if (!src.is_valid()) return;
if (this->points.empty()) {
this->points = src.points;
this->fitting_result = src.fitting_result;
} else {
//BBS: append the first point to create connection first, update the fitting date as well
this->append(src.points[0]);
//BBS: then append the remain points
MultiPoint::append(src.points.begin() + 1, src.points.end());
//BBS: finally append the fitting data
append_fitting_result_after_append_polyline(src);
}
}
void append(Polyline &&src)
{
if (!src.is_valid()) return;
if (this->points.empty()) {
this->points = std::move(src.points);
this->fitting_result = std::move(src.fitting_result);
} else {
//BBS: append the first point to create connection first, update the fitting date as well
this->append(src.points[0]);
//BBS: then append the remain points
MultiPoint::append(src.points.begin() + 1, src.points.end());
//BBS: finally append the fitting data
append_fitting_result_after_append_polyline(src);
src.points.clear();
src.fitting_result.clear();
}
}
void append(const Polyline& src);
void append(Polyline&& src);
const Point& last_point() const override { return this->points.back(); }
const Point& leftmost_point() const;

View file

@ -666,7 +666,7 @@ static std::vector<std::string> s_Preset_print_options {
//"independent_support_layer_height",
"support_angle", "support_interface_top_layers", "support_interface_bottom_layers",
"support_interface_pattern", "support_interface_spacing", "support_interface_loop_pattern",
"support_top_z_distance", "support_on_build_plate_only", "bridge_no_support","max_bridge_length", "print_sequence",
"support_top_z_distance", "support_on_build_plate_only", "bridge_no_support", "thick_bridges", "max_bridge_length", "print_sequence",
"filename_format", "wall_filament",
"sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament",
"ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width",
@ -675,7 +675,7 @@ static std::vector<std::string> s_Preset_print_options {
"elefant_foot_compensation", "xy_contour_compensation", "xy_hole_compensation", "resolution", "enable_prime_tower",
"prime_tower_width", "prime_tower_brim_width", "prime_volume",
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
"flush_into_infill", "flush_into_objects",
"flush_into_infill", "flush_into_objects", "flush_into_support",
// BBS
"tree_support_branch_angle", "tree_support_with_infill", "tree_support_wall_count", "tree_support_branch_distance",
"tree_support_branch_diameter",

View file

@ -181,6 +181,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|| opt_key == "flush_volumes_matrix"
|| opt_key == "prime_volume"
|| opt_key == "flush_into_infill"
|| opt_key == "flush_into_support"
|| opt_key == "initial_layer_infill_speed"
|| opt_key == "travel_speed"
|| opt_key == "travel_speed_z"

View file

@ -165,7 +165,6 @@ class ConstSupportLayerPtrsAdaptor : public ConstVectorOfPtrsAdaptor<SupportLaye
// BBS
typedef std::vector<TreeSupportLayer*> TreeSupportLayerPtrs;
typedef std::vector<const TreeSupportLayer*> ConstTreeSupportLayerPtrs;
class ConstTreeSupportLayerPtrsAdaptor : public ConstVectorOfPtrsAdaptor<TreeSupportLayer> {
friend PrintObject;
ConstTreeSupportLayerPtrsAdaptor(const TreeSupportLayerPtrs* data) : ConstVectorOfPtrsAdaptor<TreeSupportLayer>(data) {}
@ -300,7 +299,8 @@ public:
const Layer* current_layer,
float extrusion_width,
PolysType* overhang_regions,
float max_bridge_length = scale_(10));
float max_bridge_length = scale_(10),
bool break_bridge=false);
// Bounding box is used to align the object infill patterns, and to calculate attractor for the rear seam.
// The bounding box may not be quite snug.
@ -340,6 +340,10 @@ public:
// Get a layer approximately at print_z.
const Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const;
Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon);
// BBS
const Layer* get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon) const;
Layer* get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon);
// Get the first layer approximately bellow print_z.
const Layer* get_first_layer_bellow_printz(coordf_t print_z, coordf_t epsilon) const;
@ -354,6 +358,7 @@ public:
void clear_tree_support_layers();
size_t tree_support_layer_count() const { return m_tree_support_layers.size(); }
std::shared_ptr<TreeSupportData> alloc_tree_support_preview_cache();
void clear_tree_support_preview_cache() { m_tree_support_preview_cache.reset(); }
size_t support_layer_count() const { return m_support_layers.size(); }
void clear_support_layers();

View file

@ -686,7 +686,15 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Don't support the whole bridge area which make support very large. "
"Bridge usually can be printing directly without support if not very long");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def->set_default_value(new ConfigOptionBool(false));
def = this->add("thick_bridges", coBool);
def->label = L("Thick bridges");
def->category = L("Layers and Perimeters");
def->tooltip = L("If enabled, bridges are more reliable, can bridge longer distances, but may look worse. "
"If disabled, bridges look better but are reliable just for shorter bridged distances.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("max_bridge_length", coFloat);
def->label = L("Max bridge length");
@ -722,10 +730,7 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("concentric");
def->enum_values.push_back("zig-zag");
#if !BBL_RELEASE_TO_PUBLIC
def->enum_values.push_back("monotonic");
#endif
//BBS: use monotonicline pattern to replace monotonic for top and bottom surface
def->enum_values.push_back("monotonicline");
//def->enum_values.push_back("alignedrectilinear");
//def->enum_values.push_back("hilbertcurve");
@ -733,9 +738,7 @@ void PrintConfigDef::init_fff_params()
//def->enum_values.push_back("octagramspiral");
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Zig zag"));
#if !BBL_RELEASE_TO_PUBLIC
def->enum_labels.push_back(L("Monotonic"));
#endif
def->enum_labels.push_back(L("Monotonic line"));
//def->enum_labels.push_back(L("Aligned Rectilinear"));
//def->enum_labels.push_back(L("Hilbert Curve"));
@ -1627,8 +1630,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("reduce_infill_retraction", coBool);
def->label = L("Reduce infill retraction");
def->tooltip = L("Don't retract when the travel is in infill area absolutely. That means the oozing can't been seen");
def->mode = comDevelop;
def->tooltip = L("Don't retract when the travel is in infill area absolutely. That means the oozing can't been seen. "
"This can reduce times of retraction for complex model and save printing time, but make slicing and "
"G-code generating slower");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("ooze_prevention", coBool);
@ -2545,6 +2550,13 @@ void PrintConfigDef::init_fff_params()
"If the walls are printed with transparent filament, the mixed color infill will be seen outside");
def->set_default_value(new ConfigOptionBool(false));
def = this->add("flush_into_support", coBool);
def->category = L("Flush options");
def->label = L("Flush into objects' support");
def->tooltip = L("Purging after filament change will be done inside objects' support. "
"This may lower the amount of waste and decrease the print time");
def->set_default_value(new ConfigOptionBool(true));
def = this->add("flush_into_objects", coBool);
def->category = L("Flush options");
def->label = L("Flush into this object");
@ -3345,12 +3357,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
//But now these key-value must be absolute value.
//Reset to default value by erasing these key to avoid parsing error.
opt_key = "";
} else if (opt_key == "top_surface_pattern" || opt_key == "bottom_surface_pattern") {
#if BBL_RELEASE_TO_PUBLIC
//BBS: replace monotonic pattern to be monotonicline for top and bottom surface
if (value == "monotonic")
value = "monotonicline";
#endif
} else if (opt_key == "filament_type" && value == "PA-CF") {
value == "PA";
} else if (opt_key == "inherits_cummulative") {
@ -3372,7 +3378,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
, "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative"
#endif /* HAS_PRESSURE_EQUALIZER */
// BBS
, "thick_bridges","support_sharp_tails","remove_small_overhangs", "support_with_sheath",
, "support_sharp_tails","remove_small_overhangs", "support_with_sheath",
"tree_support_branch_diameter_angle", "tree_support_collision_resolution",
"small_perimeter_speed", "max_volumetric_speed", "max_print_speed",
"support_bottom_z_distance", "support_closing_radius", "slicing_mode", "slice_closing_radius",

View file

@ -596,6 +596,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionEnum<SupportMaterialStyle>, support_style))
// BBS
((ConfigOptionBool, independent_support_layer_height))
((ConfigOptionBool, thick_bridges))
// Overhang angle threshold.
((ConfigOptionInt, support_threshold_angle))
((ConfigOptionFloat, support_object_xy_distance))
@ -604,6 +605,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, flush_into_objects))
// BBS
((ConfigOptionBool, flush_into_infill))
((ConfigOptionBool, flush_into_support))
// BBS
((ConfigOptionFloat, tree_support_branch_distance))
((ConfigOptionFloat, tree_support_branch_diameter))

View file

@ -566,7 +566,7 @@ void PrintObject::clear_tree_support_layers()
std::shared_ptr<TreeSupportData> PrintObject::alloc_tree_support_preview_cache()
{
if (m_tree_support_preview_cache == nullptr) {
if (!m_tree_support_preview_cache) {
const coordf_t layer_height = m_config.layer_height.value;
const coordf_t xy_distance = m_config.support_object_xy_distance.value;
const double angle = m_config.tree_support_branch_angle.value * M_PI / 180.;
@ -787,7 +787,8 @@ bool PrintObject::invalidate_state_by_config_options(
invalidated |= m_print->invalidate_step(psGCodeExport);
} else if (
opt_key == "flush_into_infill"
|| opt_key == "flush_into_objects") {
|| opt_key == "flush_into_objects"
|| opt_key == "flush_into_support") {
invalidated |= m_print->invalidate_step(psWipeTower);
invalidated |= m_print->invalidate_step(psGCodeExport);
} else {
@ -827,7 +828,7 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
}
// Wipe tower depends on the ordering of extruders, which in turn depends on everything.
// It also decides about what the flush_into_infill / wipe_into_object features will do,
// It also decides about what the flush_into_infill / wipe_into_object / flush_into_support features will do,
// and that too depends on many of the settings.
invalidated |= m_print->invalidate_step(psWipeTower);
// Invalidate G-code export in any case.
@ -2297,7 +2298,8 @@ void PrintObject::remove_bridges_from_contacts(
const Layer* current_layer,
float extrusion_width,
PolysType* overhang_regions,
float max_bridge_length)
float max_bridge_length,
bool break_bridge)
{
// Extrusion width accounts for the roundings of the extrudates.
// It is the maximum widh of the extrudate.
@ -2305,6 +2307,7 @@ void PrintObject::remove_bridges_from_contacts(
Lines overhang_perimeters = to_lines(*overhang_regions);
auto layer_regions = current_layer->regions();
Polygons lower_layer_polygons = to_polygons(lower_layer->lslices);
const PrintObjectConfig& object_config = current_layer->object()->config();
Polygons all_bridges;
for (LayerRegion* layerm : layer_regions)
@ -2321,7 +2324,7 @@ void PrintObject::remove_bridges_from_contacts(
// since we're dealing with bridges, we can't assume width is larger than spacing,
// so we take the largest value and also apply safety offset to be ensure no gaps
// are left in between
Flow bridge_flow = layerm->bridging_flow(frPerimeter, g_config_thick_bridges);
Flow bridge_flow = layerm->bridging_flow(frPerimeter, object_config.thick_bridges);
float w = float(std::max(bridge_flow.scaled_width(), bridge_flow.scaled_spacing()));
for (Polyline& polyline : overhang_perimeters)
if (polyline.is_straight()) {
@ -2338,12 +2341,16 @@ void PrintObject::remove_bridges_from_contacts(
if (supported[0] && supported[1]) {
Polylines lines;
if (polyline.length() > max_bridge_length + 10) {
// equally divide the polyline
float len = polyline.length() / ceil(polyline.length() / max_bridge_length);
lines = polyline.equally_spaced_lines(len);
for (auto& line : lines) {
line.clip_start(fw);
line.clip_end(fw);
if (break_bridge) {
// equally divide the polyline
float len = polyline.length() / ceil(polyline.length() / max_bridge_length);
lines = polyline.equally_spaced_lines(len);
for (auto& line : lines) {
if (line.is_valid())
line.clip_start(fw);
if (line.is_valid())
line.clip_end(fw);
}
}
}
else
@ -2357,8 +2364,52 @@ void PrintObject::remove_bridges_from_contacts(
// remove the entire bridges and only support the unsupported edges
//FIXME the brided regions are already collected as layerm->bridged. Use it?
for (const Surface& surface : layerm->fill_surfaces.surfaces)
if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1)
polygons_append(bridges, surface.expolygon);
if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1) {
auto bbox = get_extents(surface.expolygon);
auto bbox_size = bbox.size();
if (bbox_size[0] < max_bridge_length || bbox_size[1] < max_bridge_length)
polygons_append(bridges, surface.expolygon);
else {
if (break_bridge) {
Polygons holes;
int x0 = bbox.min.x();
int x1 = bbox.max.x();
int y0 = bbox.min.y();
int y1 = bbox.max.y();
const int grid_lw = int(w/2); // grid line width
#if 1
if (fabs(surface.bridge_angle-0)<fabs(surface.bridge_angle-M_PI_2)) {
int step = bbox_size(0) / ceil(bbox_size(0) / max_bridge_length);
for (int x = x0 + step; x < x1; x += step) {
Polygon poly;
poly.points = {Point(x - grid_lw, y0), Point(x + grid_lw, y0), Point(x + grid_lw, y1), Point(x - grid_lw, y1)};
holes.emplace_back(poly);
}
} else {
int step = bbox_size(1) / ceil(bbox_size(1) / max_bridge_length);
for (int y = y0 + step; y < y1; y += step) {
Polygon poly;
poly.points = {Point(x0, y - grid_lw), Point(x0, y + grid_lw), Point(x1, y + grid_lw), Point(x1, y - grid_lw)};
holes.emplace_back(poly);
}
}
#else
int stepx = bbox_size(0) / ceil(bbox_size(0) / max_bridge_length);
int stepy = bbox_size(1) / ceil(bbox_size(1) / max_bridge_length);
for (int x = x0 + stepx; x < x1; x += stepx)
for (int y = y0 + stepy; y < y1; y += stepy) {
Polygon poly;
poly.points = {Point(x-grid_lw, y - grid_lw), Point(x+grid_lw, y - grid_lw), Point(x+grid_lw, y + grid_lw), Point(x-grid_lw, y + grid_lw)};
holes.emplace_back(poly);
}
#endif
auto expoly = diff_ex(surface.expolygon, holes);
polygons_append(bridges, expoly);
}
}
}
//FIXME add the gap filled areas. Extrude the gaps with a bridge flow?
// Remove the unsupported ends of the bridges from the bridged areas.
//FIXME add supports at regular intervals to support long bridges!
@ -2380,13 +2431,13 @@ template void PrintObject::remove_bridges_from_contacts<ExPolygons>(
const Layer* current_layer,
float extrusion_width,
ExPolygons* overhang_regions,
float max_bridge_length);
float max_bridge_length, bool break_bridge);
template void PrintObject::remove_bridges_from_contacts<Polygons>(
const Layer* lower_layer,
const Layer* current_layer,
float extrusion_width,
Polygons* overhang_regions,
float max_bridge_length);
float max_bridge_length, bool break_bridge);
bool PrintObject::is_support_necessary()
@ -2721,4 +2772,20 @@ const Layer *PrintObject::get_first_layer_bellow_printz(coordf_t print_z, coordf
return (it == m_layers.begin()) ? nullptr : *(--it);
}
// BBS
const Layer* PrintObject::get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon) const {
coordf_t limit_upper = bottom_z + epsilon;
coordf_t limit_lower = bottom_z - epsilon;
for (const Layer* layer : m_layers) {
if (layer->bottom_z() > limit_lower)
return layer->bottom_z() < limit_upper ? layer : nullptr;
}
return nullptr;
}
Layer* PrintObject::get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_bottomz(bottom_z, epsilon)); }
} // namespace Slic3r

View file

@ -446,6 +446,9 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
std::string fix_slicing_errors(PrintObject* object, LayerPtrs &layers, const std::function<void()> &throw_if_canceled)
{
std::string error_msg;//BBS
if (layers.size() == 0) return error_msg;
// Collect layers with slicing errors.
// These layers will be fixed in parallel.
std::vector<size_t> buggy_layers;
@ -740,24 +743,39 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
bool doesVolumeIntersect(VolumeSlices& vs1, VolumeSlices& vs2)
{
if (vs1.volume_id == vs2.volume_id) return true;
if (vs1.slices.size() != vs1.slices.size()) return false;
if (vs1.slices.size() != vs2.slices.size()) return false;
double offsetValue = 0.4 / SCALING_FACTOR;
for (int i = 0; i != vs1.slices.size(); ++i) {
auto eps1 = offset_ex(vs1.slices[i], offsetValue);
auto eps2 = offset_ex(vs2.slices[i], offsetValue);
if (!intersection_ex(eps1, eps2).empty()) return true;
if (vs1.slices[i].empty()) continue;
if (!vs2.slices[i].empty() && !intersection_ex(vs1.slices[i], vs2.slices[i]).empty()) return true;
if (i + 1 != vs2.slices.size() && !vs2.slices[i + 1].empty()) {
if (!intersection_ex(vs1.slices[i], vs2.slices[i + 1]).empty()) return true;
}
if (i - 1 >= 0 && !vs2.slices[i - 1].empty()) {
if (!intersection_ex(vs1.slices[i], vs2.slices[i - 1]).empty()) return true;
}
}
return false;
}
//BBS: grouping the volumes of an object according to their connection relationship
bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<groupedVolumeSlices>& groups)
bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution)
{
int existGroups = 0;
std::vector<int> groupIndex(objSliceByVolume.size(), -1);
double offsetValue = 0.4 / SCALING_FACTOR;
for (int i = 0; i != objSliceByVolume.size(); ++i) {
for (int j = 0; j != objSliceByVolume[i].slices.size(); ++j) {
objSliceByVolume[i].slices[j] = offset_ex(objSliceByVolume[i].slices[j], offsetValue);
for (ExPolygon& poly_ex : objSliceByVolume[i].slices[j])
poly_ex.douglas_peucker(resolution);
}
}
for (int i = 0; i != objSliceByVolume.size(); ++i) {
if (groupIndex[i] < 0) {
groupIndex[i] = i;
@ -765,7 +783,7 @@ bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<gr
}
for (int j = i + 1; j != objSliceByVolume.size(); ++j) {
if (doesVolumeIntersect(objSliceByVolume[i], objSliceByVolume[j])) {
if (groupIndex[j] < 0) groupIndex[j] = i;
if (groupIndex[j] < 0) groupIndex[j] = groupIndex[i];
if (groupIndex[j] != groupIndex[i]) {
int retain = std::min(groupIndex[i], groupIndex[j]);
int cover = std::max(groupIndex[i], groupIndex[j]);
@ -791,9 +809,6 @@ bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<gr
if (!exist) groupVector.push_back(gi);
}
if (groupVector.size() != existGroups);
// group volumes and their slices according to the grouping Vector
groups.clear();
@ -808,9 +823,7 @@ bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<gr
}
// the slices of a group should be unioned
double offsetValue = 0.4 / SCALING_FACTOR;
gvs.slices = offset_ex(union_ex(offset_ex(gvs.slices, offsetValue)), -offsetValue);
double resolution = 0.0125 / SCALING_FACTOR;
gvs.slices = offset_ex(union_ex(gvs.slices), -offsetValue);
for (ExPolygon& poly_ex : gvs.slices)
poly_ex.douglas_peucker(resolution);
@ -830,6 +843,24 @@ std::vector<VolumeSlices> findPartVolumes(const std::vector<VolumeSlices>& objSl
return outPut;
}
void applyNegtiveVolumes(ModelVolumePtrs model_volumes, const std::vector<VolumeSlices>& objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution) {
ExPolygons negTotal;
for (const auto& vs : objSliceByVolume) {
for (const auto& mv : model_volumes) {
if (vs.volume_id == mv->id() && mv->is_negative_volume()) {
if (vs.slices.size() > 0) {
append(negTotal, vs.slices.front());
}
}
}
}
for (auto& g : groups) {
g.slices = diff_ex(g.slices, negTotal);
for (ExPolygon& poly_ex : g.slices)
poly_ex.douglas_peucker(resolution);
}
}
// 1) Decides Z positions of the layers,
// 2) Initializes layers and their regions
// 3) Slices the object meshes
@ -873,9 +904,10 @@ void PrintObject::slice_volumes()
}
//BBS: "model_part" volumes are grouded according to their connections
const auto scaled_resolution = scaled<double>(print->config().resolution.value);
std::vector<VolumeSlices> objSliceByVolumeParts = findPartVolumes(objSliceByVolume, this->model_object()->volumes);
groupingVolumes(objSliceByVolumeParts, firstLayerObjSliceByGroups);
groupingVolumes(objSliceByVolumeParts, firstLayerObjSliceByGroups, scaled_resolution);
applyNegtiveVolumes(this->model_object()->volumes, objSliceByVolume, firstLayerObjSliceByGroups, scaled_resolution);
std::vector<std::vector<ExPolygons>> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs,
std::move(objSliceByVolume),

View file

@ -29,12 +29,13 @@ enum MachineBedType {
struct FilamentInfo
{
int id; // filament id = extruder id, start with 0.
int id; // filament id = extruder id, start with 0.
std::string type;
std::string color;
float used_m;
float used_g;
int tray_id;
int tray_id; // start with 0
float distance;
};
class BBLSliceInfo {

View file

@ -19,6 +19,7 @@ public:
float height;
bool flipY;
SVG() = default;
SVG(const char* afilename) :
arrows(false), fill("grey"), stroke("black"), filename(afilename), flipY(false)
{ open(filename); }

View file

@ -118,10 +118,11 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters
sp1.first_print_layer_height == sp2.first_print_layer_height &&
sp1.first_object_layer_height == sp2.first_object_layer_height &&
sp1.first_object_layer_bridging == sp2.first_object_layer_bridging &&
// BBS: following are not required for equal layer height.
// Since the z-gap diff may be multiple of layer height.
#if 0
sp1.soluble_interface == sp2.soluble_interface &&
sp1.gap_raft_object == sp2.gap_raft_object &&
// BBS
#if 0
sp1.gap_object_support == sp2.gap_object_support &&
sp1.gap_support_object == sp2.gap_support_object &&
#endif

View file

@ -379,7 +379,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
m_support_params.gap_xy = m_object_config->support_object_xy_distance.value;
bridge_flow /= object->num_printing_regions();
m_support_params.support_material_bottom_interface_flow = m_slicing_params.soluble_interface || ! g_config_thick_bridges ?
m_support_params.support_material_bottom_interface_flow = m_slicing_params.soluble_interface || ! m_object_config->thick_bridges ?
m_support_params.support_material_interface_flow.with_flow_ratio(bridge_flow) :
Flow::bridging_flow(bridge_flow * m_support_params.support_material_interface_flow.nozzle_diameter(), m_support_params.support_material_interface_flow.nozzle_diameter());
@ -1339,7 +1339,7 @@ namespace SupportMaterialInternal {
}
}
static void remove_bridges_from_contactsxx(
static void remove_bridges_from_contacts(
const PrintConfig &print_config,
const Layer &lower_layer,
const Polygons &lower_layer_polygons,
@ -1374,7 +1374,9 @@ namespace SupportMaterialInternal {
// since we're dealing with bridges, we can't assume width is larger than spacing,
// so we take the largest value and also apply safety offset to be ensure no gaps
// are left in between
Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter, g_config_thick_bridges);
// BBS
const PrintObjectConfig& object_config = layerm.layer()->object()->config();
Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter, object_config.thick_bridges);
//FIXME one may want to use a maximum of bridging flow width and normal flow width, as the perimeters are calculated using the normal flow
// and then turned to bridging flow, thus their centerlines are derived from non-bridging flow and expanding them by a bridging flow
// may not expand them to the edge of their respective islands.
@ -1509,7 +1511,7 @@ static inline Polygons detect_overhangs(
M_PI * double(object_config.support_threshold_angle.value + 1) / 180. : // +1 makes the threshold inclusive
0.;
const coordf_t max_bridge_length = scale_(object_config.max_bridge_length.value);
const bool bridge_no_support = max_bridge_length > 0;// config.bridge_no_support.value;
const bool bridge_no_support = object_config.bridge_no_support.value;
if (layer_id == 0)
{
@ -1667,7 +1669,8 @@ static inline Polygons detect_overhangs(
if (bridge_no_support) {
//FIXME Expensive, potentially not precise enough. Misses gap fill extrusions, which bridge.
PrintObject::remove_bridges_from_contacts(&lower_layer, &layer, fw, &diff_polygons, max_bridge_length);
SupportMaterialInternal::remove_bridges_from_contacts(
print_config, lower_layer, lower_layer_polygons, *layerm, fw, diff_polygons);
}
if (diff_polygons.empty() || offset(diff_polygons, -0.1 * fw).empty())
@ -1861,7 +1864,7 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport
// Contact layer will be printed with a normal flow, but
// it will support layers printed with a bridging flow.
if (g_config_thick_bridges && SupportMaterialInternal::has_bridging_extrusions(layer)) {
if (object_config.thick_bridges && SupportMaterialInternal::has_bridging_extrusions(layer)) {
coordf_t bridging_height = 0.;
for (const LayerRegion* region : layer.regions())
bridging_height += region->region().bridging_height_avg(print_config);
@ -2429,7 +2432,7 @@ static inline PrintObjectSupportMaterial::MyLayer* detect_bottom_contacts(
layer.print_z + layer_new.height + slicing_params.gap_object_support;
layer_new.bottom_z = layer.print_z;
layer_new.idx_object_layer_below = layer_id;
layer_new.bridging = !slicing_params.soluble_interface && g_config_thick_bridges;
layer_new.bridging = !slicing_params.soluble_interface && object.config().thick_bridges;
//FIXME how much to inflate the bottom surface, as it is being extruded with a bridging flow? The following line uses a normal flow.
layer_new.polygons = expand(touching, float(support_params.support_material_flow.scaled_width()), SUPPORT_SURFACES_OFFSET_PARAMETERS);
@ -3234,7 +3237,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
polygons_append(polygons_trimming, offset({ expoly }, trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
}
}
if (! m_slicing_params.soluble_interface && g_config_thick_bridges) {
if (! m_slicing_params.soluble_interface && m_object_config->thick_bridges) {
// Collect all bottom surfaces, which will be extruded with a bridging flow.
for (; i < object.layers().size(); ++ i) {
const Layer &object_layer = *object.layers()[i];
@ -4515,6 +4518,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
angles[support_layer_id % angles.size()] :
// Use interface angle for the interface layers.
m_support_params.interface_angle + interface_angle_delta;
double density = interface_as_base ? m_support_params.support_density : m_support_params.interface_density;
filler_interface->spacing = interface_as_base ? m_support_params.support_material_flow.spacing() : m_support_params.support_material_interface_flow.spacing();
filler_interface->link_max_length = coord_t(scale_(filler_interface->spacing * link_max_length_factor / density));

View file

@ -9,15 +9,11 @@
#include "SVG.hpp"
#include "ShortestPath.hpp"
#include "I18N.hpp"
#include <libnest2d/backends/libslic3r/geometries.hpp>
#define _L(s) Slic3r::I18N::translate(s)
#define SQUARE_SUPPORT 0
#if SQUARE_SUPPORT
#define CIRCLE_RESOLUTION 4 // 100 //The number of vertices in each circle.
#else
#define CIRCLE_RESOLUTION 100 //The number of vertices in each circle.
#endif
#define MAX_BRANCH_RADIUS 10.0
#define HEIGHT_TO_SWITCH_INFILL_DIRECTION 30 // change infill direction every 20mm
#define DO_NOT_MOVER_UNDER_MM 5 // do not move contact points under 5mm
@ -31,7 +27,7 @@
#define TAU (2.0 * M_PI)
#define NO_INDEX (std::numeric_limits<unsigned int>::max())
//#define SUPPORT_TREE_DEBUG_TO_SVG
#define SUPPORT_TREE_DEBUG_TO_SVG
namespace Slic3r
{
@ -225,14 +221,18 @@ static void draw_contours_and_nodes_to_svg
bbox.max.x() = std::max(bbox.max.x(), (coord_t)scale_(10));
bbox.max.y() = std::max(bbox.max.y(), (coord_t)scale_(10));
SVG svg(get_svg_filename(std::to_string(layer_nr), name_prefix), bbox);
SVG svg;
if(layer_nr>=0)
svg.open(get_svg_filename(std::to_string(layer_nr), name_prefix), bbox);
else
svg.open(name_prefix, bbox);
if (!svg.is_opened()) return;
// draw grid
svg.draw_grid(bbox, "gray", coord_t(scale_(0.05)));
// draw overhang areas
svg.draw(union_ex(overhangs), colors[0]);
svg.draw_outline(union_ex(overhangs), colors[0]);
svg.draw_outline(union_ex(overhangs_after_offset), colors[1]);
svg.draw_outline(outlines_below, colors[2]);
@ -661,6 +661,8 @@ void TreeSupport::detect_object_overhangs()
// Create Tree Support Layers
m_object->clear_tree_support_layers();
m_object->clear_tree_support_preview_cache();
create_tree_support_layers();
m_ts_data = m_object->alloc_tree_support_preview_cache();
@ -932,7 +934,7 @@ void TreeSupport::detect_object_overhangs()
if (bridge_no_support && overhang_areas.size()>0) {
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length);
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length, true);
}
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
@ -1081,9 +1083,6 @@ void TreeSupport::detect_object_overhangs()
}
}
total_overhang_area = 0;
max_overhang_area = 0;
total_overhang_layer_cnt = 0;
for (int layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) {
if (m_object->print()->canceled())
break;
@ -1095,6 +1094,10 @@ void TreeSupport::detect_object_overhangs()
ts_layer->overhang_areas = diff_ex(ts_layer->overhang_areas, offset_ex(blocker, scale_(radius_sample_resolution)));
}
for (auto &area : ts_layer->overhang_areas) {
ts_layer->overhang_types.emplace(&area, TreeSupportLayer::Detected);
}
if (layer_nr < enforcers.size()) {
Polygons& enforcer = enforcers[layer_nr];
// coconut: enforcer can't do offset2_ex, otherwise faces with angle near 90 degrees can't have enforcers, which
@ -1102,15 +1105,9 @@ void TreeSupport::detect_object_overhangs()
//enforcer = std::move(offset2_ex(enforcer, -0.1 * extrusion_width_scaled, 0.1 * extrusion_width_scaled));
for (const Polygon& poly : enforcer) {
ts_layer->overhang_areas.emplace_back(poly);
ts_layer->overhang_types.emplace(&ts_layer->overhang_areas.back(), TreeSupportLayer::Enforced);
}
}
if (!ts_layer->overhang_areas.empty()) {
float a = area(ts_layer->overhang_areas);
total_overhang_area += a;
max_overhang_area = std::max(max_overhang_area, a);
total_overhang_layer_cnt++;
}
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
@ -1825,17 +1822,25 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
{
const PrintObjectConfig &config = m_object->config();
bool has_brim = m_object->print()->has_brim();
bool has_infill = config.tree_support_with_infill.value;
int bottom_gap_layers = round(m_slicing_params.gap_object_support / m_slicing_params.layer_height);
const coordf_t branch_radius = config.tree_support_branch_diameter.value / 2;
const coordf_t branch_radius_scaled = scale_(branch_radius);
Polygon branch_circle; //Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time.
// Use square support if there are too many nodes per layer because circle support needs much longer time to compute
// Hower circle support can be printed faster, so we prefer circle for fewer nodes case.
const bool SQUARE_SUPPORT = avg_node_per_layer > 200;
const int CIRCLE_RESOLUTION = SQUARE_SUPPORT ? 4 : 100; // The number of vertices in each circle.
for (unsigned int i = 0; i < CIRCLE_RESOLUTION; i++)
{
#if SQUARE_SUPPORT
double angle = (double)i / CIRCLE_RESOLUTION * TAU + TAU/8.0;
#else
double angle = (double)i / CIRCLE_RESOLUTION * TAU;
#endif
double angle;
if (SQUARE_SUPPORT)
angle = (double) i / CIRCLE_RESOLUTION * TAU + PI / 4.0 + nodes_angle;
else
angle = (double) i / CIRCLE_RESOLUTION * TAU;
branch_circle.append(Point(cos(angle) * branch_radius_scaled, sin(angle) * branch_radius_scaled));
}
@ -1850,7 +1855,6 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
}
// generate areas
const coordf_t circle_side_length = 2 * branch_radius * sin(M_PI / CIRCLE_RESOLUTION); //Side length of a regular polygon.
const coordf_t layer_height = config.layer_height.value;
const size_t top_interface_layers = config.support_interface_top_layers.value;
const size_t bottom_interface_layers = config.support_interface_bottom_layers.value;
@ -2024,16 +2028,12 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
base_areas = std::move(diff_ex(base_areas, roof_areas));
base_areas = std::move(diff_ex(base_areas, roof_1st_layer));
#if SQUARE_SUPPORT
if (m_object->print()->config().enable_arc_fitting.value == false) {
// simplify support contours if arc fitting is disabled
if (SQUARE_SUPPORT) {
// simplify support contours
ExPolygons base_areas_simplified;
for (auto& area : base_areas) {
area.simplify(scale_(line_width / 2), &base_areas_simplified, SimplifyMethodDP);
}
for (auto &area : base_areas) { area.simplify(scale_(line_width / 2), &base_areas_simplified, SimplifyMethodDP); }
base_areas = std::move(base_areas_simplified);
}
#endif
//Subtract support floors. We can only compute floor_areas here instead of with roof_areas,
// or we'll get much wider floor than necessary.
if (bottom_interface_layers + bottom_gap_layers > 0)
@ -2073,15 +2073,13 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
}),
expoly->holes.end());
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
draw_contours_and_nodes_to_svg(layer_nr, base_areas, roof_areas, roof_1st_layer, {}, {}, "circles", { "base","roof","roof1st" });
#endif
}
});
#if 1
// move the holes to contour so they can be well supported
if (!has_infill) {
// check if poly's contour intersects with expoly's contour
auto intersects_contour = [](Polygon poly, ExPolygon expoly, Point &pt_on_poly, Point &pt_on_expoly, Point &pt_far_on_poly, float dist_thresh = 0.01) {
float min_dist = std::numeric_limits<float>::max();
@ -2099,18 +2097,15 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
max_dist = dist2;
pt_far_on_poly = from;
}
if (dist2 < dist_thresh) {
return true;
}
if (dist2 < dist_thresh) { return true; }
}
}
return false;
};
std::map<const Polygon *, int> holeDepth;
std::map<const Polygon *, Point> holeDiretions;
std::map<const Polygon *, Point> holeFarPoints;
for (int layer_nr = m_object->layer_count()-1; layer_nr >0; layer_nr--) {
// polygon pointer: depth, direction, farPoint
std::map<const Polygon *, std::tuple<int, Point, Point>> holePropagationInfos;
for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) {
if (print->canceled()) break;
m_object->print()->set_status(66, (boost::format(_L("Support: fix holes at layer %d")) % layer_nr).str());
@ -2127,47 +2122,88 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
for (layer_nr_lower; layer_nr_lower >= 0; layer_nr_lower--) {
if (!m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups.empty()) break;
}
auto & area_groups_lower = m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups;
auto &area_groups_lower = m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups;
for (const auto& area_group:ts_layer->area_groups){
if (area_group.second == 1 || area_group.second == 2) continue;
const auto base_area = area_group.first;
for (const auto &hole : base_area->holes) {
for (const auto &area_group : ts_layer->area_groups) {
if (area_group.second != TreeSupportLayer::BaseType) continue;
const auto area = area_group.first;
for (const auto &hole : area->holes) {
// auto hole_bbox = get_extents(hole).polygon();
for (auto & area_group_lower: area_groups_lower) {
if (area_group.second == 1 || area_group.second == 2) continue;
for (auto &area_group_lower : area_groups_lower) {
if (area_group.second != TreeSupportLayer::BaseType) continue;
auto &base_area_lower = *area_group_lower.first;
Point pt_on_poly, pt_on_expoly, pt_far_on_poly;
// if a hole doesn't intersect with lower layer's contours, add a hole to lower layer and move it slightly to the contour
if (base_area_lower.contour.contains(hole.points.front()) && !intersects_contour(hole, base_area_lower, pt_on_poly, pt_on_expoly, pt_far_on_poly)) {
Polygon hole_lower = hole;
Point direction = normal(pt_on_expoly - pt_on_poly, line_width_scaled/2);
Point direction = normal(pt_on_expoly - pt_on_poly, line_width_scaled / 2);
hole_lower.translate(direction);
// note to expand a hole, we need to do negative offset
auto hole_expanded = offset(hole_lower, -line_width_scaled / 4, ClipperLib::JoinType::jtSquare);
if (!hole_expanded.empty()) {
base_area_lower.holes.push_back(std::move(hole_expanded[0]));
holeDepth.insert({&base_area_lower.holes.back(), 15});
holeDiretions.insert({&base_area_lower.holes.back(), direction});
holeFarPoints.insert({&base_area_lower.holes.back(), pt_far_on_poly});
holePropagationInfos.insert({&base_area_lower.holes.back(), {25, direction, pt_far_on_poly}});
}
break;
} else if (holeDepth.find(&hole) != holeDepth.end() && holeDepth[&hole] > 0 && base_area_lower.contour.contains(holeFarPoints[&hole])) {
} else if (holePropagationInfos.find(&hole) != holePropagationInfos.end() && std::get<0>(holePropagationInfos[&hole]) > 0 &&
base_area_lower.contour.contains(std::get<2>(holePropagationInfos[&hole]))) {
Polygon hole_lower = hole;
hole_lower.translate(holeDiretions[&hole]);
Point farPoint = holeFarPoints[&hole] + holeDiretions[&hole];
{
base_area_lower.holes.push_back(std::move(hole_lower));
holeDepth.insert({&base_area_lower.holes.back(), holeDepth[&hole]-1});
holeDiretions.insert({&base_area_lower.holes.back(), holeDiretions[&hole]});
holeFarPoints.insert({&base_area_lower.holes.back(), farPoint});
auto && direction = std::get<1>(holePropagationInfos[&hole]);
hole_lower.translate(direction);
// note to shrink a hole, we need to do positive offset
auto hole_expanded = offset(hole_lower, line_width_scaled / 2, ClipperLib::JoinType::jtSquare);
Point farPoint = std::get<2>(holePropagationInfos[&hole]) + direction * 2;
if (!hole_expanded.empty()) {
base_area_lower.holes.push_back(std::move(hole_expanded[0]));
holePropagationInfos.insert({&base_area_lower.holes.back(), {std::get<0>(holePropagationInfos[&hole]) - 1, direction, farPoint}});
}
break;
}
}
{
// if roof1 interface is inside a hole, need to expand the interface
for (auto &roof1 : ts_layer->roof_1st_layer) {
//if (hole.contains(roof1.contour.points.front()) && hole.contains(roof1.contour.bounding_box().center()))
bool is_inside_hole = std::all_of(roof1.contour.points.begin(), roof1.contour.points.end(), [&hole](Point &pt) { return hole.contains(pt); });
if (is_inside_hole) {
Polygon hole_reoriented = hole;
if (roof1.contour.is_counter_clockwise())
hole_reoriented.make_counter_clockwise();
else if (roof1.contour.is_clockwise())
hole_reoriented.make_clockwise();
auto tmp = union_({roof1.contour}, {hole_reoriented});
if (!tmp.empty()) roof1.contour = tmp[0];
// make sure 1) roof1 and object 2) roof1 and roof, won't intersect
// Note: We can't replace roof1 directly, as we have recorded its address.
// So instead we need to replace its members one by one.
auto tmp1 = diff_ex(roof1, m_ts_data->get_collision((layer_nr == 0 && has_brim) ? config.brim_object_gap : m_ts_data->m_xy_distance, layer_nr));
tmp1 = diff_ex(tmp1, ts_layer->roof_areas);
if (!tmp1.empty()) {
roof1.contour = std::move(tmp1[0].contour);
roof1.holes = std::move(tmp1[0].holes);
}
break;
}
}
}
}
}
}
}
#endif
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) {
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
ExPolygons& base_areas = ts_layer->base_areas;
ExPolygons& roof_areas = ts_layer->roof_areas;
ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer;
ExPolygons& floor_areas = ts_layer->floor_areas;
if (base_areas.empty() && roof_areas.empty() && roof_1st_layer.empty()) continue;
char fname[10]; sprintf(fname, "%d_%.2f", layer_nr, ts_layer->print_z);
draw_contours_and_nodes_to_svg(-1, base_areas, roof_areas, roof_1st_layer, {}, {}, get_svg_filename(fname, "circles"), {"base", "roof", "roof1st"});
}
#endif
TreeSupportLayerPtrs& ts_layers = m_object->tree_support_layers();
@ -2257,6 +2293,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
next_node->distance_to_top++;
next_node->support_roof_layers_below--;
next_node->print_z -= m_object->get_layer(layer_nr)->height;
next_node->to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], next_node->position);
contact_nodes[layer_nr - 1].emplace_back(next_node);
}
}
@ -2290,10 +2327,6 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
for (Node* p_node : layer_contact_nodes)
{
const Node& node = *p_node;
if (node.type == ePolygon) {
// polygon node do not merge or move
continue;
}
if (support_on_buildplate_only && !node.to_buildplate) //Can't rest on model and unable to reach the build plate. Then we must drop the node and leave parts unsupported.
{
@ -2305,6 +2338,10 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
nodes_per_part[0][node.position] = p_node;
continue;
}
if (node.type == ePolygon) {
// polygon node do not merge or move
continue;
}
/* Find which part this node is located in and group the nodes in
* the same part together. Since nodes have a radius and the
* avoidance areas are offset by that radius, the set of parts may
@ -2720,7 +2757,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
coordf_t z_distance_top = m_slicing_params.gap_support_object;
// BBS: add extra distance if thick bridge is enabled
// Note: normal support uses print_z, but tree support uses integer layers, so we need to subtract layer_height
if (!m_slicing_params.soluble_interface && g_config_thick_bridges) {
if (!m_slicing_params.soluble_interface && m_object_config->thick_bridges) {
z_distance_top += m_object->layers()[0]->regions()[0]->region().bridging_height_avg(m_object->print()->config()) - layer_height;
}
const size_t z_distance_top_layers = round_up_divide(scale_(z_distance_top), scale_(layer_height)) + 1; //Support must always be 1 layer below overhang.
@ -2729,17 +2766,20 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
coordf_t thresh_angle = config.support_threshold_angle.value < EPSILON ? 30.f : config.support_threshold_angle.value;
coordf_t half_overhang_distance = scale_(tan(thresh_angle * M_PI / 180.0) * layer_height / 2);
m_highest_overhang_layer = 0;
// fix bug of generating support for very thin objects
if (m_object->layers().size() <= z_distance_top_layers + 1)
return;
m_highest_overhang_layer = 0;
int nonempty_layers = 0;
std::vector<Slic3r::Vec3f> all_nodes;
for (size_t layer_nr = 1; layer_nr < m_object->layers().size() - z_distance_top_layers; layer_nr++)
{
if (m_object->print()->canceled())
break;
const ExPolygons &overhang = m_object->get_tree_support_layer(layer_nr + m_raft_layers + z_distance_top_layers)->overhang_areas;
auto ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers + z_distance_top_layers);
const ExPolygons &overhang = ts_layer->overhang_areas;
auto & curr_nodes = contact_nodes[layer_nr];
if (overhang.empty())
continue;
@ -2757,7 +2797,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
Node *contact_node = new Node(candidate, 0, (layer_nr + z_distance_top_layers) % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height);
contact_node->type = ePolygon;
contact_node->overhang = &overhang_part;
contact_nodes[layer_nr].emplace_back(contact_node);
curr_nodes.emplace_back(contact_node);
continue;
}
@ -2783,7 +2823,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
constexpr size_t distance_to_top = 0;
constexpr bool to_buildplate = true;
Node* contact_node = new Node(candidate, distance_to_top, (layer_nr + z_distance_top_layers) % 2, support_roof_layers, to_buildplate, Node::NO_PARENT,print_z,height);
contact_nodes[layer_nr].emplace_back(contact_node);
curr_nodes.emplace_back(contact_node);
added = true;
}
}
@ -2793,38 +2833,81 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported.
{
auto bbox = overhang_part.contour.bounding_box();
Points candidates = { bbox.min, bounding_box_middle(bbox), bbox.max };
Points candidates;
if (ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Detected)
candidates = {bbox.min, bounding_box_middle(bbox), bbox.max};
else
candidates = {bounding_box_middle(bbox)};
for (Point candidate : candidates) {
if (!overhang_part.contains(candidate))
move_inside_expoly(overhang_part, candidate);
constexpr size_t distance_to_top = 0;
constexpr bool to_buildplate = true;
Node * contact_node = new Node(candidate, distance_to_top, layer_nr % 2, support_roof_layers, to_buildplate, Node::NO_PARENT, print_z, height);
contact_nodes[layer_nr].emplace_back(contact_node);
curr_nodes.emplace_back(contact_node);
}
}
// add points at corners
auto& points = overhang_part.contour.points;
for (int i=0;i<points.size();i++)
{
auto pt = points[i];
auto v1 = (pt - points[(i - 1 + points.size()) % points.size()]).normalized();
auto v2 = (pt - points[(i + 1) % points.size()]).normalized();
if (v1.dot(v2) > -0.7) {
Node* contact_node = new Node(pt, 0, layer_nr % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height);
contact_nodes[layer_nr].emplace_back(contact_node);
if (ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Detected) {
// add points at corners
auto &points = overhang_part.contour.points;
for (int i = 0; i < points.size(); i++) {
auto pt = points[i];
auto v1 = (pt - points[(i - 1 + points.size()) % points.size()]).normalized();
auto v2 = (pt - points[(i + 1) % points.size()]).normalized();
if (v1.dot(v2) > -0.7) {
Node *contact_node = new Node(pt, 0, layer_nr % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height);
curr_nodes.emplace_back(contact_node);
}
}
} else if(ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Enforced){
// remove close points in Enforcers
auto above_nodes = contact_nodes[layer_nr - 1];
if (!curr_nodes.empty() && !above_nodes.empty()) {
for (auto it = curr_nodes.begin(); it != curr_nodes.end();) {
bool is_duplicate = false;
Slic3r::Vec3f curr_pt((*it)->position(0), (*it)->position(1), scale_((*it)->print_z));
for (auto &pt : all_nodes) {
auto dif = curr_pt - pt;
if (dif.norm() < scale_(2)) {
delete (*it);
it = curr_nodes.erase(it);
is_duplicate = true;
break;
}
}
if (!is_duplicate) it++;
}
}
}
}
if (!curr_nodes.empty()) nonempty_layers++;
for (auto node : curr_nodes) { all_nodes.emplace_back(node->position(0), node->position(1), scale_(node->print_z)); }
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
draw_contours_and_nodes_to_svg(layer_nr, overhang, m_ts_data->m_layer_outlines_below[layer_nr], {},
contact_nodes[layer_nr], {}, "init_contact_points", { "overhang","outlines","" });
#endif
}
int nNodes = all_nodes.size();
avg_node_per_layer = nodes_angle = 0;
if (nNodes > 0) {
avg_node_per_layer = nNodes / nonempty_layers;
// get orientation of nodes by line fitting
// line: y=kx+b, where
// k=tan(nodes_angle)=(n\sum{xy}-\sum{x}\sum{y})/(n\sum{x^2}-\sum{x}^2)
float mx = 0, my = 0, mxy = 0, mx2 = 0;
for (auto &pt : all_nodes) {
float x = unscale_(pt(0));
float y = unscale_(pt(1));
mx += x;
my += y;
mxy += x * y;
mx2 += x * x;
}
nodes_angle = atan2(nNodes * mxy - mx * my, nNodes * mx2 - SQ(mx));
BOOST_LOG_TRIVIAL(info) << "avg_node_per_layer=" << avg_node_per_layer << ", nodes_angle=" << nodes_angle;
}
}
void TreeSupport::insert_dropped_node(std::vector<Node*>& nodes_layer, Node* p_node)

View file

@ -340,9 +340,8 @@ public:
bool with_sheath;
};
float total_overhang_area;
float max_overhang_area;
size_t total_overhang_layer_cnt;
int avg_node_per_layer = 0;
float nodes_angle = 0;
bool has_sharp_tail;
private:
/*!

View file

@ -497,15 +497,10 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafod,
TriangleMesh TriangleMesh::convex_hull_3d() const
{
// BBS: don't compute convex hull for objects like a single sheet
if (this->m_stats.volume>0.001) {
TriangleMesh mesh(its_convex_hull(this->its));
// Quite often qhull produces non-manifold mesh.
// assert(mesh.stats().manifold());
return mesh;
}
else
return TriangleMesh();
TriangleMesh mesh(its_convex_hull(this->its));
// Quite often qhull produces non-manifold mesh.
// assert(mesh.stats().manifold());
return mesh;
}
std::vector<ExPolygons> TriangleMesh::slice(const std::vector<double> &z) const

View file

@ -84,6 +84,124 @@ static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline& thi
return paths;
}
//BBS: new function to filter width to avoid too fragmented segments
static ExtrusionPaths thick_polyline_to_extrusion_paths_2(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance)
{
ExtrusionPaths paths;
ExtrusionPath path(role);
ThickLines lines = thick_polyline.thicklines();
size_t start_index = 0;
double max_width, min_width;
for (int i = 0; i < (int)lines.size(); ++i) {
const ThickLine& line = lines[i];
if (i == 0) {
max_width = line.a_width;
min_width = line.a_width;
}
const coordf_t line_len = line.length();
if (line_len < SCALED_EPSILON) continue;
double thickness_delta = std::max(fabs(max_width - line.b_width), fabs(min_width - line.b_width));
//BBS: has large difference in width
if (thickness_delta > tolerance) {
//BBS: 1 generate path from start_index to i(not included)
if (start_index != i){
path = ExtrusionPath(role);
double length = lines[start_index].length();
double sum = lines[start_index].length() * lines[start_index].a_width;
path.polyline.append(lines[start_index].a);
for (int idx = start_index + 1; idx < i; idx++) {
length += lines[idx].length();
sum += lines[idx].length() * lines[idx].a_width;
path.polyline.append(lines[idx].a);
}
path.polyline.append(lines[i].a);
if (length > SCALED_EPSILON) {
double w = sum / length;
Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI));
path.mm3_per_mm = new_flow.mm3_per_mm();
path.width = new_flow.width();
path.height = new_flow.height();
paths.emplace_back(std::move(path));
}
}
start_index = i;
max_width = line.a_width;
min_width = line.a_width;
//BBS: 2 handle the i-th segment
thickness_delta = fabs(line.a_width - line.b_width);
if (thickness_delta > tolerance){
const unsigned int segments = (unsigned int)ceil(thickness_delta / tolerance);
const coordf_t seg_len = line_len / segments;
Points pp;
std::vector<coordf_t> width;
{
pp.push_back(line.a);
width.push_back(line.a_width);
for (size_t j = 1; j < segments; ++j) {
pp.push_back((line.a.cast<double>() + (line.b - line.a).cast<double>().normalized() * (j * seg_len)).cast<coord_t>());
coordf_t w = line.a_width + (j * seg_len) * (line.b_width - line.a_width) / line_len;
width.push_back(w);
width.push_back(w);
}
pp.push_back(line.b);
width.push_back(line.b_width);
assert(pp.size() == segments + 1u);
assert(width.size() == segments * 2);
}
// delete this line and insert new ones
lines.erase(lines.begin() + i);
for (size_t j = 0; j < segments; ++j) {
ThickLine new_line(pp[j], pp[j + 1]);
new_line.a_width = width[2 * j];
new_line.b_width = width[2 * j + 1];
lines.insert(lines.begin() + i + j, new_line);
}
--i;
continue;
}
}
//BBS: just update the max and min width and continue
else {
max_width = std::max(max_width, std::max(line.a_width, line.b_width));
min_width = std::min(min_width, std::min(line.a_width, line.b_width));
}
}
//BBS: handle the remaining segment
size_t final_size = lines.size();
if (start_index < final_size) {
path = ExtrusionPath(role);
double length = lines[start_index].length();
double sum = lines[start_index].length() * lines[start_index].a_width;
path.polyline.append(lines[start_index].a);
for (int idx = start_index + 1; idx < final_size; idx++) {
length += lines[idx].length();
sum += lines[idx].length() * lines[idx].a_width;
path.polyline.append(lines[idx].a);
}
path.polyline.append(lines[final_size - 1].b);
if (length > SCALED_EPSILON) {
double w = sum / length;
Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI));
path.mm3_per_mm = new_flow.mm3_per_mm();
path.width = new_flow.width();
path.height = new_flow.height();
paths.emplace_back(std::move(path));
}
}
return paths;
}
void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const Flow& flow, std::vector<ExtrusionEntity*>& out)
{
// This value determines granularity of adaptive width, as G-code does not allow
@ -91,7 +209,7 @@ void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const F
// of segments, and any pruning shall be performed before we apply this tolerance.
const float tolerance = float(scale_(0.05));
for (const ThickPolyline& p : polylines) {
ExtrusionPaths paths = thick_polyline_to_extrusion_paths(p, role, flow, tolerance);
ExtrusionPaths paths = thick_polyline_to_extrusion_paths_2(p, role, flow, tolerance);
// Append paths to collection.
if (!paths.empty()) {
if (paths.front().first_point() == paths.back().last_point())

View file

@ -84,7 +84,6 @@ static constexpr bool RELATIVE_E_AXIS = 1;
#endif /* UNUSED */
//BBS: some global const config which user can not change, but developer can
static constexpr bool g_config_thick_bridges = true;
static constexpr bool g_config_support_sharp_tails = true;
static constexpr bool g_config_remove_small_overhangs = true;
static constexpr float g_config_tree_support_collision_resolution = 0.2;

View file

@ -11,6 +11,10 @@
#include "Time.hpp"
#include "libslic3r.h"
#ifdef __APPLE__
#include "MacUtils.hpp"
#endif
#ifdef WIN32
#include <windows.h>
#include <psapi.h>
@ -292,12 +296,21 @@ namespace keywords = boost::log::keywords;
namespace attrs = boost::log::attributes;
void set_log_path_and_level(const std::string& file, unsigned int level)
{
#ifdef __APPLE__
//currently on old macos, the boost::log::add_file_log will crash
//TODO: need to be fixed
if (!is_macos_support_boost_add_file_log()) {
return;
}
#endif
//BBS log file at C:\\Users\\[yourname]\\AppData\\Roaming\\BambuStudio\\log\\[log_filename].log
auto log_folder = boost::filesystem::path(g_data_dir) / "log";
if (!boost::filesystem::exists(log_folder)) {
boost::filesystem::create_directory(log_folder);
}
auto full_path = (log_folder / file).make_preferred();
g_log_sink = boost::log::add_file_log(
keywords::file_name = full_path.string() + ".%N",
keywords::rotation_size = 100 * 1024 * 1024,
@ -309,6 +322,7 @@ void set_log_path_and_level(const std::string& file, unsigned int level)
<< ":" << expr::smessage
)
);
logging::add_common_attributes();
set_logging_level(level);

View file

@ -221,8 +221,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Monitor.hpp
GUI/WebViewDialog.cpp
GUI/WebViewDialog.hpp
GUI/WebDailytipDialog.hpp
GUI/WebDailytipDialog.cpp
GUI/WebDownPluginDlg.hpp
GUI/WebDownPluginDlg.cpp
GUI/WebGuideDialog.hpp
GUI/WebGuideDialog.cpp
GUI/WebUserLoginDialog.cpp
@ -268,12 +268,16 @@ set(SLIC3R_GUI_SOURCES
GUI/ConfigWizard_private.hpp
GUI/MsgDialog.cpp
GUI/MsgDialog.hpp
GUI/DownloadProgressDialog.hpp
GUI/DownloadProgressDialog.cpp
GUI/UpdateDialogs.cpp
GUI/UpdateDialogs.hpp
GUI/Jobs/Job.hpp
GUI/Jobs/Job.cpp
GUI/Jobs/PlaterJob.hpp
GUI/Jobs/PlaterJob.cpp
GUI/Jobs/UpgradeNetworkJob.hpp
GUI/Jobs/UpgradeNetworkJob.cpp
GUI/Jobs/ArrangeJob.hpp
GUI/Jobs/ArrangeJob.cpp
GUI/Jobs/OrientJob.hpp

View file

@ -4,9 +4,14 @@
#include "I18N.hpp"
namespace Slic3r { namespace GUI {
static bool show_flag;
AMSMaterialsSetting::AMSMaterialsSetting(wxWindow *parent, wxWindowID id): wxPopupTransientWindow(parent, id)
{
#ifdef __APPLE__
#define COMBOBOX_FILAMENT (m_comboBox_filament_mac)
#else
#define COMBOBOX_FILAMENT (m_comboBox_filament)
#endif
AMSMaterialsSetting::AMSMaterialsSetting(wxWindow *parent, wxWindowID id) : wxPopupTransientWindow(parent, wxPU_CONTAINS_CONTROLS) {
create();
}
@ -28,9 +33,13 @@ void AMSMaterialsSetting::create()
m_sizer_filament->Add(0, 0, 0, wxEXPAND, 0);
#ifdef __APPLE__
m_comboBox_filament_mac = new wxComboBox(m_panel_body, wxID_ANY, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_COMBOX_WIDTH, 0, nullptr, wxCB_READONLY);
#else
m_comboBox_filament = new ::ComboBox(m_panel_body, wxID_ANY, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_COMBOX_WIDTH, 0, nullptr, wxCB_READONLY);
m_sizer_filament->Add(m_comboBox_filament, 0, wxALIGN_CENTER, 0);
#endif
m_sizer_filament->Add(COMBOBOX_FILAMENT, 1, wxALIGN_CENTER, 0);
wxBoxSizer *m_sizer_colour = new wxBoxSizer(wxHORIZONTAL);
m_title_colour = new wxStaticText(m_panel_body, wxID_ANY, _L("Colour"), wxDefaultPosition, wxSize(AMS_MATERIALS_SETTING_LABEL_WIDTH, -1), 0);
@ -77,18 +86,18 @@ void AMSMaterialsSetting::create()
wxBoxSizer *sizer_other = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *sizer_tempinput = new wxBoxSizer(wxHORIZONTAL);
m_input_nozzle_max = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE,
wxTE_CENTRE | wxTE_PROCESS_ENTER);
m_input_nozzle_max = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER);
m_input_nozzle_min = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER);
m_input_nozzle_max->Enable(false);
m_input_nozzle_min->Enable(false);
m_input_nozzle_max->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
m_input_nozzle_max->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20)));
auto bitmap_max_degree = new wxStaticBitmap(m_panel_body, -1, create_scaled_bitmap("degree", nullptr, 16), wxDefaultPosition, wxDefaultSize);
m_input_nozzle_min = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE,
wxTE_CENTRE | wxTE_PROCESS_ENTER);
m_input_nozzle_min->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20)));
m_input_nozzle_min->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
m_input_nozzle_min->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20)));
auto bitmap_max_degree = new wxStaticBitmap(m_panel_body, -1, create_scaled_bitmap("degree", nullptr, 16), wxDefaultPosition, wxDefaultSize);
auto bitmap_min_degree = new wxStaticBitmap(m_panel_body, -1, create_scaled_bitmap("degree", nullptr, 16), wxDefaultPosition, wxDefaultSize);
sizer_tempinput->Add(m_input_nozzle_max, 1, wxALIGN_CENTER, 0);
@ -125,7 +134,7 @@ void AMSMaterialsSetting::create()
warning_text->SetMinSize(wxSize(AMS_MATERIALS_SETTING_BODY_WIDTH, -1));
warning_text->Hide();
m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent &e) {
m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent &e) {
warning_text->Hide();
Layout();
Fit();
@ -135,22 +144,22 @@ void AMSMaterialsSetting::create()
input_min_finish();
e.Skip();
});
m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &e) {
m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &e) {
input_min_finish();
e.Skip();
});
m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent& e) {
m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent &e) {
warning_text->Hide();
Layout();
Fit();
e.Skip();
});
m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent& e) {
m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent &e) {
input_max_finish();
e.Skip();
});
m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) {
m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &e) {
input_max_finish();
e.Skip();
});
@ -170,13 +179,6 @@ void AMSMaterialsSetting::create()
m_button_confirm->Bind(wxEVT_LEFT_DOWN, &AMSMaterialsSetting::on_select_ok, this);
m_sizer_button->Add(m_button_confirm, 0, wxALIGN_CENTER, 0);
StateColor btn_bg_white(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
StateColor btn_bd_white(std::pair<wxColour, int>(*wxWHITE, StateColor::Disabled), std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Enabled));
m_sizer_body->Add(m_sizer_filament, 0, wxEXPAND, 0);
m_sizer_body->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(16));
m_sizer_body->Add(m_sizer_colour, 0, wxEXPAND, 0);
@ -200,7 +202,7 @@ void AMSMaterialsSetting::create()
this->Centre(wxBOTH);
Bind(wxEVT_PAINT, &AMSMaterialsSetting::paintEvent, this);
m_comboBox_filament->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this);
COMBOBOX_FILAMENT->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this);
}
void AMSMaterialsSetting::paintEvent(wxPaintEvent &evt)
@ -214,13 +216,13 @@ void AMSMaterialsSetting::paintEvent(wxPaintEvent &evt)
AMSMaterialsSetting::~AMSMaterialsSetting()
{
m_comboBox_filament->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this);
COMBOBOX_FILAMENT->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this);
}
void AMSMaterialsSetting::input_min_finish()
{
if (m_input_nozzle_min->GetTextCtrl()->GetValue().empty())return;
if (m_input_nozzle_min->GetTextCtrl()->GetValue().empty()) return;
auto val = std::atoi(m_input_nozzle_min->GetTextCtrl()->GetValue().c_str());
@ -235,7 +237,7 @@ void AMSMaterialsSetting::input_min_finish()
void AMSMaterialsSetting::input_max_finish()
{
if (m_input_nozzle_max->GetTextCtrl()->GetValue().empty())return;
if (m_input_nozzle_max->GetTextCtrl()->GetValue().empty()) return;
auto val = std::atoi(m_input_nozzle_max->GetTextCtrl()->GetValue().c_str());
@ -279,8 +281,8 @@ void AMSMaterialsSetting::enable_confirm_button(bool en)
void AMSMaterialsSetting::on_select_ok(wxMouseEvent &event)
{
wxString nozzle_temp_min = m_input_nozzle_min->GetTextCtrl()->GetValue();
auto filament = m_comboBox_filament->GetValue();
wxString nozzle_temp_min = m_input_nozzle_min->GetTextCtrl()->GetValue();
auto filament = COMBOBOX_FILAMENT->GetValue();
wxString nozzle_temp_max = m_input_nozzle_max->GetTextCtrl()->GetValue();
@ -295,7 +297,7 @@ void AMSMaterialsSetting::on_select_ok(wxMouseEvent &event)
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
if (preset_bundle) {
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) {
if (it->alias.compare(COMBOBOX_FILAMENT->GetValue().ToStdString()) == 0) {
ams_filament_id = it->filament_id;
}
}
@ -313,19 +315,12 @@ void AMSMaterialsSetting::on_select_ok(wxMouseEvent &event)
void AMSMaterialsSetting::set_color(wxColour color)
{
m_clrData = new wxColourData();
m_clrData->SetColour(color);
}
static bool show_flag;
void AMSMaterialsSetting::on_clr_picker(wxCommandEvent & event) {
void AMSMaterialsSetting::on_clr_picker(wxCommandEvent & event)
{
auto clr_dialog = new wxColourDialog(this, m_clrData);
clr_dialog->Bind(wxEVT_ACTIVATE, [this](wxActivateEvent &e) {
int a ;
});
show_flag = true;
if (clr_dialog->ShowModal() == wxID_OK) {
m_clrData = &(clr_dialog->GetColourData());
@ -338,12 +333,14 @@ void AMSMaterialsSetting::Dismiss()
if (show_flag)
{
show_flag = false;
}
else
} else
{
wxPopupTransientWindow::Dismiss();
#ifdef __APPLE__
#else
wxPopupTransientWindow::Dismiss();
#endif
}
}
bool AMSMaterialsSetting::Show(bool show)
@ -360,12 +357,14 @@ void AMSMaterialsSetting::Popup(bool show, bool third, wxString filament, wxColo
{
if (!m_is_third) {
m_panel_SN->Show();
m_comboBox_filament->SetValue(filament);
COMBOBOX_FILAMENT->SetValue(filament);
m_sn_number->SetLabelText(sn);
m_input_nozzle_min->GetTextCtrl()->SetValue(tep);
m_clrData->SetColour(colour);
m_comboBox_filament->Disable();
COMBOBOX_FILAMENT->Disable();
m_input_nozzle_min->Disable();
wxPopupTransientWindow::Popup();
Layout();
return;
@ -438,13 +437,13 @@ void AMSMaterialsSetting::Popup(bool show, bool third, wxString filament, wxColo
}
}
}
m_comboBox_filament->Set(filament_items);
COMBOBOX_FILAMENT->Set(filament_items);
if (selection_idx >= 0 && selection_idx < filament_items.size()) {
m_comboBox_filament->SetSelection(selection_idx);
COMBOBOX_FILAMENT->SetSelection(selection_idx);
post_select_event();
}
else {
m_comboBox_filament->SetSelection(selection_idx);
COMBOBOX_FILAMENT->SetSelection(selection_idx);
post_select_event();
}
}
@ -453,8 +452,8 @@ void AMSMaterialsSetting::Popup(bool show, bool third, wxString filament, wxColo
void AMSMaterialsSetting::post_select_event() {
wxCommandEvent event(wxEVT_COMBOBOX);
event.SetEventObject(m_comboBox_filament);
wxPostEvent(m_comboBox_filament, event);
event.SetEventObject(COMBOBOX_FILAMENT);
wxPostEvent(COMBOBOX_FILAMENT, event);
}
void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
@ -464,7 +463,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
if (preset_bundle) {
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
auto a = it->alias;
if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) {
if (it->alias.compare(COMBOBOX_FILAMENT->GetValue().ToStdString()) == 0) {
// ) if nozzle_temperature_range is found
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
if (opt_min) {
@ -498,10 +497,24 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
}
}
if (m_input_nozzle_min->GetTextCtrl()->GetValue().IsEmpty()) {
m_input_nozzle_min->GetTextCtrl()->SetValue("220");
m_input_nozzle_min->GetTextCtrl()->SetValue("220");
}
if (m_input_nozzle_max->GetTextCtrl()->GetValue().IsEmpty()) {
m_input_nozzle_max->GetTextCtrl()->SetValue("220");
m_input_nozzle_max->GetTextCtrl()->SetValue("220");
}
}
bool AMSMaterialsSetting::ProcessLeftDown(wxMouseEvent &evt)
{
wxPoint mouse_pos = ClientToScreen(evt.GetPosition());
wxPoint top_left = this->ClientToScreen(wxPoint(0, 0));
wxPoint range = wxPoint(this->GetRect().width, this->GetRect().height);
wxPoint bottom_right = top_left + range;
if (mouse_pos.x > top_left.x && mouse_pos.y > top_left.y && mouse_pos.x < bottom_right.x && mouse_pos.y < bottom_right.y) {
return true;
} else {
wxPopupTransientWindow::Dismiss();
return false;
}
}

View file

@ -39,13 +39,13 @@ public:
void input_max_finish();
void update();
void enable_confirm_button(bool en);
void on_select_cancel(wxMouseEvent &event);
void Dismiss() override;
bool Show(bool show) override;
void Popup(bool show, bool third = true, wxString filament = wxEmptyString, wxColour colour = *wxWHITE, wxString sn = wxEmptyString, wxString tep = wxEmptyString);
void post_select_event();
void on_select_ok(wxMouseEvent &event);
void set_color(wxColour color);
void on_clr_picker(wxCommandEvent &event);
@ -67,6 +67,8 @@ protected:
//void on_dpi_changed(const wxRect &suggested_rect) override;
void on_select_filament(wxCommandEvent& evt);
bool ProcessLeftDown(wxMouseEvent &evt);
protected:
StateColor m_btn_bg_green;
wxPanel * m_panel_SN;
@ -82,6 +84,9 @@ protected:
TextInput * m_input_nozzle_min;
TextInput* m_input_nozzle_max;
Button * m_button_confirm;
#ifdef __APPLE__
wxComboBox *m_comboBox_filament_mac;
#endif
wxColourData * m_clrData;
};

View file

@ -80,7 +80,7 @@ CopyrightsDialog::CopyrightsDialog()
SetSizer(sizer);
sizer->SetSizeHints(this);
CenterOnParent();
}
void CopyrightsDialog::fill_entries()
@ -88,6 +88,7 @@ void CopyrightsDialog::fill_entries()
m_entries = {
{ "Admesh", "", "https://admesh.readthedocs.io/" },
{ "Anti-Grain Geometry", "", "http://antigrain.com" },
{ "ArcWelderLib", "", "https://plugins.octoprint.org/plugins/arc_welder" },
{ "Boost", "", "http://www.boost.org" },
{ "Cereal", "", "http://uscilab.github.io/cereal" },
{ "CGAL", "", "https://www.cgal.org" },
@ -115,6 +116,7 @@ void CopyrightsDialog::fill_entries()
{ "Real-Time DXT1/DXT5 C compression library", "", "https://github.com/Cyan4973/RygsDXTc" },
{ "SemVer", "", "https://semver.org" },
{ "Shinyprofiler", "", "https://code.google.com/p/shinyprofiler" },
{ "SuperSlicer", "", "https://github.com/supermerill/SuperSlicer" },
{ "TBB", "", "https://www.intel.cn/content/www/cn/zh/developer/tools/oneapi/onetbb.html" },
{ "wxWidgets", "", "https://www.wxwidgets.org" },
{ "zlib", "", "http://zlib.net" },
@ -219,7 +221,7 @@ AboutDialog::AboutDialog()
std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
wxPanel *m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(430), FromDIP(237)), wxTAB_TRAVERSAL);
wxPanel *m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(560), FromDIP(237)), wxTAB_TRAVERSAL);
wxBoxSizer *panel_versizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *vesizer = new wxBoxSizer(wxVERTICAL);
@ -233,7 +235,7 @@ AboutDialog::AboutDialog()
main_sizer->Add(ver_sizer, 0, wxEXPAND | wxALL, 0);
// logo
m_logo_bitmap = ScalableBitmap(this, "BambuStudio_about", 240);
m_logo_bitmap = ScalableBitmap(this, "BambuStudio_about", 250);
m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bitmap.bmp(), wxDefaultPosition,wxDefaultSize, 0);
m_logo->SetSizer(vesizer);
@ -250,20 +252,70 @@ AboutDialog::AboutDialog()
#else
version_font.SetPointSize(11);
#endif
version_font.SetPointSize(12);
version_font.SetPointSize(FromDIP(16));
version->SetFont(version_font);
version->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
version->SetForegroundColour(wxColour(255, 255, 255));
version->SetBackgroundColour(wxColour(0, 174, 66));
vesizer->Add(version, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, FromDIP(5));
vesizer->Add(0, 0, 1, wxEXPAND, FromDIP(5));
}
wxStaticText *html_text = new wxStaticText(this, wxID_ANY, "Copyright(C) 2021-2022 Bambu Lab", wxDefaultPosition, wxDefaultSize);
ver_sizer->Add(0, 0, 0, wxTOP, FromDIP(38));
html_text->SetForegroundColour(wxColour(107, 107, 107));
ver_sizer->Add(html_text, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 0);
wxBoxSizer *text_sizer_horiz = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *text_sizer = new wxBoxSizer(wxVERTICAL);
text_sizer_horiz->Add( 0, 0, 0, wxLEFT, FromDIP(23));
std::vector<wxString> text_list;
text_list.push_back(_L("Bambu Studio is based on PrusaSlicer by PrusaResearch and SuperSlicer by Merill(supermerill)."));
text_list.push_back(_L("PrusaSlicer is originally based on Slic3r by Alessandro Ranellucci."));
text_list.push_back(_L("Slic3r was created by Alessandro Ranellucci with the help of many other contributors."));
text_list.push_back(_L("Bambu Studio also referenced some ideas from Cura by Ultimaker."));
text_list.push_back(_L("There many parts of the software that come from community contributions, so we're unable to list them one-by-one, and instead, they'll be attributed in the corresponding code comments."));
text_sizer->Add( 0, 0, 0, wxTOP, FromDIP(33));
bool is_zh = wxGetApp().app_config->get("language") == "zh_CN";
for (int i = 0; i < text_list.size(); i++)
{
auto staticText = new wxStaticText( this, wxID_ANY, wxEmptyString,wxDefaultPosition,wxSize(FromDIP(520), -1), wxALIGN_LEFT );
staticText->SetForegroundColour(wxColour(107, 107, 107));
staticText->SetMinSize(wxSize(FromDIP(520), -1));
staticText->SetFont(Label::Body_12);
if (is_zh) {
wxString find_txt = "";
wxString count_txt = "";
for (auto o = 0; o < text_list[i].length(); o++) {
auto size = staticText->GetTextExtent(count_txt);
if (size.x < FromDIP(506)) {
find_txt += text_list[i][o];
count_txt += text_list[i][o];
} else {
find_txt += std::string("\n") + text_list[i][o];
count_txt = text_list[i][o];
}
}
staticText->SetLabel(find_txt);
} else {
staticText->SetLabel(text_list[i]);
staticText->Wrap(FromDIP(520));
}
text_sizer->Add( staticText, 0, wxUP | wxDOWN, FromDIP(3));
}
text_sizer_horiz->Add(text_sizer, 1, wxALL,0);
ver_sizer->Add(text_sizer_horiz, 0, wxALL,0);
ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(43));
wxBoxSizer *copyright_ver_sizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *copyright_hor_sizer = new wxBoxSizer(wxHORIZONTAL);
copyright_hor_sizer->Add(copyright_ver_sizer, 0, wxALL,5);
copyright_hor_sizer->Add( 0, 0, 0, wxLEFT, FromDIP(120));
wxStaticText *html_text = new wxStaticText(this, wxID_ANY, "Copyright(C) 2021-2022 Bambu Lab", wxDefaultPosition, wxDefaultSize);
html_text->SetForegroundColour(wxColour(107, 107, 107));
copyright_ver_sizer->Add(html_text, 0, wxALL , 0);
// text
m_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER /*NEVER*/);
{
wxFont font = get_default_font(this);
@ -276,12 +328,12 @@ AboutDialog::AboutDialog()
(boost::format(
"<html>"
"<body>"
"<p style=\"text-align:center\"><a href=\"www.bambulab.com\">www.bambulab.com</ a></p>"
"<p style=\"text-align:left\"><a href=\"www.bambulab.com\">www.bambulab.com</ a></p>"
"</body>"
"</html>")
).str());
m_html->SetPage(text);
ver_sizer->Add(m_html, 0, wxEXPAND, 0);
copyright_ver_sizer->Add(m_html, 0, wxEXPAND, 0);
m_html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this);
}
//Add "Portions copyright" button
@ -298,14 +350,21 @@ AboutDialog::AboutDialog()
button_portions->SetCornerRadius(FromDIP(12));
button_portions->SetMinSize(wxSize(FromDIP(120), FromDIP(24)));
ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(22));
ver_sizer->Add(button_portions, 0, wxALIGN_CENTER_HORIZONTAL|wxALL,0);
ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(38));
wxBoxSizer *copyright_button_ver = new wxBoxSizer(wxVERTICAL);
copyright_button_ver->Add( 0, 0, 0, wxTOP, FromDIP(10));
copyright_button_ver->Add(button_portions, 0, wxALL,0);
copyright_hor_sizer->Add(copyright_button_ver, 0, wxALL,0);
copyright_hor_sizer->Add( 0, 0, 0, wxRIGHT, FromDIP(13));
ver_sizer->Add(copyright_hor_sizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL,0);
ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(30));
button_portions->Bind(wxEVT_BUTTON, &AboutDialog::onCopyrightBtn, this);
m_panel->Layout();
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
Layout();
Fit();
CenterOnParent();
}
void AboutDialog::on_dpi_changed(const wxRect &suggested_rect)

View file

@ -48,11 +48,12 @@ wxDEFINE_EVENT(EVT_SET_FINISH_MAPPING, wxCommandEvent);
void MaterialItem::msw_rescale() {}
void MaterialItem::set_ams_info(wxColour col, wxString txt)
void MaterialItem::set_ams_info(wxColour col, wxString txt)
{
m_ams_coloul = col;
m_ams_name = txt;
Refresh();
auto need_refresh = false;
if (m_ams_coloul != col) { m_ams_coloul = col; need_refresh = true;}
if (m_ams_name != txt) {m_ams_name = txt;need_refresh = true;}
if (need_refresh) { Refresh();}
}
void MaterialItem::on_selected()
@ -74,17 +75,22 @@ void MaterialItem::on_warning()
void MaterialItem::on_normal()
{
m_selected = false;
m_warning = false;
Refresh();
if (m_selected || m_warning) {
m_selected = false;
m_warning = false;
Refresh();
}
}
void MaterialItem::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
//PrepareDC(buffdc);
//PrepareDC(dc);
}
void MaterialItem::render(wxDC &dc)
@ -107,29 +113,33 @@ void MaterialItem::render(wxDC &dc)
doRender(dc);
#endif
//materials name
dc.SetFont(::Label::Body_13);
// materials name
dc.SetFont(::Label::Body_13);
auto material_name_colour = m_material_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26,0x2E,0x30);
dc.SetTextForeground(material_name_colour);
auto material_name_colour = m_material_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26, 0x2E, 0x30);
dc.SetTextForeground(material_name_colour);
auto material_txt_size = dc.GetTextExtent(m_material_name);
dc.DrawText(m_material_name, wxPoint((MATERIAL_ITEM_SIZE.x - material_txt_size.x) / 2, FromDIP(3)));
if (dc.GetTextExtent(m_material_name).x > GetSize().x - 10) {
dc.SetFont(::Label::Body_10);
//mapping num
dc.SetFont(::Label::Body_10);
dc.SetTextForeground(m_ams_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26,0x2E,0x30));
}
auto material_txt_size = dc.GetTextExtent(m_material_name);
dc.DrawText(m_material_name, wxPoint((MATERIAL_ITEM_SIZE.x - material_txt_size.x) / 2, (FromDIP(22) - material_txt_size.y) / 2));
wxString mapping_txt = wxEmptyString;
if (m_ams_name.empty()) {
mapping_txt = "-";
}else{
mapping_txt = m_ams_name;
}
auto mapping_txt_size = dc.GetTextExtent(mapping_txt);
dc.DrawText(mapping_txt, wxPoint((MATERIAL_ITEM_SIZE.x - mapping_txt_size.x) / 2, FromDIP(2) + material_txt_size.y ));
// mapping num
dc.SetFont(::Label::Body_10);
dc.SetTextForeground(m_ams_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26, 0x2E, 0x30));
wxString mapping_txt = wxEmptyString;
if (m_ams_name.empty()) {
mapping_txt = "-";
} else {
mapping_txt = m_ams_name;
}
auto mapping_txt_size = dc.GetTextExtent(mapping_txt);
dc.DrawText(mapping_txt, wxPoint((MATERIAL_ITEM_SIZE.x - mapping_txt_size.x) / 2, FromDIP(20) + (FromDIP(14) - mapping_txt_size.y) / 2));
}
void MaterialItem::doRender(wxDC &dc)
@ -137,36 +147,33 @@ void MaterialItem::doRender(wxDC &dc)
//top
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(m_material_coloul));
dc.DrawRoundedRectangle(FromDIP(3), FromDIP(3), MATERIAL_ITEM_SIZE.x - FromDIP(6), MATERIAL_ITEM_SIZE.y / 2, 5);
dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(18), 5);
//bottom
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(wxColour(m_ams_coloul)));
dc.DrawRoundedRectangle(FromDIP(3), MATERIAL_ITEM_SIZE.y / 2 - FromDIP(2), MATERIAL_ITEM_SIZE.x - FromDIP(6), MATERIAL_ITEM_SIZE.y / 2, 5);
dc.DrawRoundedRectangle(FromDIP(1), FromDIP(18), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(16), 5);
//middle
////middle
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(m_material_coloul));
dc.DrawRectangle(FromDIP(3), FromDIP(10), MATERIAL_ITEM_SIZE.x - FromDIP(6), FromDIP(8));
dc.DrawRectangle(FromDIP(1), FromDIP(11), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(8));
//border
if (m_material_coloul == *wxWHITE) {
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(m_ams_coloul));
dc.DrawRectangle(FromDIP(1), FromDIP(18), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(8));
////border
if (m_material_coloul == *wxWHITE || m_ams_coloul == *wxWHITE) {
dc.SetPen(wxColour(0xAC, 0xAC, 0xAC));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRoundedRectangle(3, 3, MATERIAL_ITEM_SIZE.x -6, MATERIAL_ITEM_SIZE.y - 6, 5);
dc.DrawRoundedRectangle(0, 0, MATERIAL_ITEM_SIZE.x, MATERIAL_ITEM_SIZE.y, 5);
}
if (m_selected) {
dc.SetPen(wxColour(0x00, 0xAE, 0x42));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRoundedRectangle(1, 1, MATERIAL_ITEM_SIZE.x - 2, MATERIAL_ITEM_SIZE.y - 2, 5);
}
if (m_warning) {
dc.SetPen(wxColour(0xFF, 0x6F, 0x00));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRoundedRectangle(1, 1, MATERIAL_ITEM_SIZE.x - 2, MATERIAL_ITEM_SIZE.y - 2, 5);
dc.DrawRoundedRectangle(0, 0, MATERIAL_ITEM_SIZE.x, MATERIAL_ITEM_SIZE.y, 5);
}
}
@ -186,10 +193,6 @@ void MaterialItem::doRender(wxDC &dc)
Layout();
}
void AmsMapingPopup::Popup(wxWindow *focus /*= NULL*/)
{
wxPopupTransientWindow::Popup();
}
void AmsMapingPopup::update_materials_list(std::vector<std::string> list)
{
@ -210,6 +213,11 @@ bool AmsMapingPopup::is_match_material(int id, std::string material)
void AmsMapingPopup::update_ams_data(std::map<std::string, Ams*> amsList)
{
if (m_amsmapping_sizer_list.size() > 0) {
for (wxBoxSizer *bz : m_amsmapping_sizer_list) { bz->Clear(true); }
m_amsmapping_sizer_list.clear();
}
std::map<std::string, Ams *>::iterator ams_iter;
BOOST_LOG_TRIVIAL(trace) << "ams_mapping total count " << amsList.size();
@ -229,8 +237,6 @@ void AmsMapingPopup::update_ams_data(std::map<std::string, Ams*> amsList)
td.id = ams_indx * AMS_TOTAL_COUNT + atoi(tray_data->id.c_str());
BOOST_LOG_TRIVIAL(trace) << "ams_mapping ams data ==type==" << tray_data->type << "==colour=="<<tray_data->color << "==trayid=="<<tray_data->id.c_str() << "==ftrayid=="<<td.id;
if (!tray_data->is_exists) {
td.type = EMPTY;
} else {
@ -254,9 +260,7 @@ void AmsMapingPopup::update_ams_data(std::map<std::string, Ams*> amsList)
void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data)
{
wxBoxSizer *sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL);
auto sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL);
for (auto i = 0; i < tray_data.size(); i++) {
wxBoxSizer *sizer_mapping_item = new wxBoxSizer(wxVERTICAL);
@ -299,7 +303,7 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data)
if (!is_match_material(tray_data[i].id, tray_data[i].name)) return;
wxCommandEvent event(EVT_SET_FINISH_MAPPING);
event.SetInt(tray_data[i].id);
wxString param = wxString::Format("%d|%d|%d|%02d", tray_data[i].colour.Red(), tray_data[i].colour.Green(), tray_data[i].colour.Blue(), tray_data[i].id + 1);
wxString param = wxString::Format("%d|%d|%d|%02d|%d", tray_data[i].colour.Red(), tray_data[i].colour.Green(), tray_data[i].colour.Blue(), tray_data[i].id + 1, m_current_filament_id);
event.SetString(param);
event.SetEventObject(this->GetParent());
wxPostEvent(this->GetParent(), event);
@ -317,7 +321,7 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data)
m_filament_name->Bind(wxEVT_BUTTON, [this, tray_data, i](wxCommandEvent &e) {
wxCommandEvent event(EVT_SET_FINISH_MAPPING);
event.SetInt(tray_data[i].id);
wxString param = wxString::Format("%d|%d|%d|%02d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1);
wxString param = wxString::Format("%d|%d|%d|%02d|%d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1, m_current_filament_id);
event.SetString(param);
event.SetEventObject(this->GetParent());
wxPostEvent(this->GetParent(), event);
@ -334,7 +338,7 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data)
m_filament_name->Bind(wxEVT_BUTTON, [this, tray_data, i](wxCommandEvent &e) {
wxCommandEvent event(EVT_SET_FINISH_MAPPING);
event.SetInt(tray_data[i].id);
wxString param = wxString::Format("%d|%d|%d|%02d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1);
wxString param = wxString::Format("%d|%d|%d|%02d|%d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1, m_current_filament_id);
event.SetString(param);
event.SetEventObject(this->GetParent());
wxPostEvent(this->GetParent(), event);
@ -342,17 +346,17 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data)
});
}
sizer_mapping_item->Add(number, 0, wxALIGN_CENTER_HORIZONTAL, 0);
sizer_mapping_item->Add(m_filament_name, 0, wxALIGN_CENTER_HORIZONTAL, 0);
sizer_mapping_list->Add(sizer_mapping_item, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, FromDIP(5));
m_amsmapping_sizer_list.push_back(sizer_mapping_list);
}
m_sizer_main->Add(sizer_mapping_list, 0, wxALIGN_CENTER_HORIZONTAL, 0);
}
void AmsMapingPopup::OnDismiss()
{
delete this;
}
bool AmsMapingPopup::ProcessLeftDown(wxMouseEvent &event)

View file

@ -39,7 +39,8 @@
namespace Slic3r { namespace GUI {
#define MATERIAL_ITEM_SIZE wxSize(FromDIP(42), FromDIP(31))
#define MATERIAL_ITEM_SIZE wxSize(FromDIP(64), FromDIP(34))
#define MATERIAL_ITEM_REAL_SIZE wxSize(FromDIP(62), FromDIP(32))
#define AMS_TOTAL_COUNT 4
enum TrayType {
@ -92,14 +93,18 @@ public:
~AmsMapingPopup() {};
std::vector<std::string> m_materials_list;
std::string m_tag_material;
wxBoxSizer *m_sizer_main;
std::vector<wxBoxSizer*> m_amsmapping_sizer_list;
int m_current_filament_id;
std::string m_tag_material;
wxBoxSizer *m_sizer_main{nullptr};
virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE;
void update_materials_list(std::vector<std::string> list);
void set_tag_texture(std::string texture);
void update_ams_data(std::map<std::string, Ams *> amsList);
void add_ams_mapping(std::vector<TrayData> tray_data);
void set_current_filament_id(int id){m_current_filament_id = id;};
int get_current_filament_id(){return m_current_filament_id;};
bool is_match_material(int id, std::string material);
virtual void OnDismiss() wxOVERRIDE;
virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE;

View file

@ -501,7 +501,7 @@ AuFolderPanel::AuFolderPanel(wxWindow *parent, AuxiliaryFolderType type, wxWindo
m_button_add = new Button(m_scrolledWindow, _L("Add"), "auxiliary_add_file", 12, 12);
m_button_add->SetBackgroundColor(btn_bg_white);
m_button_add->SetBorderColor(btn_bd_white);
m_button_add->SetMinSize(wxSize(FromDIP(80), FromDIP(24)));
m_button_add->SetMinSize(wxSize(-1, FromDIP(24)));
m_button_add->SetCornerRadius(12);
m_button_add->SetFont(Label::Body_14);
// m_button_add->Bind(wxEVT_LEFT_UP, &AuxiliaryPanel::on_add, this);
@ -563,7 +563,7 @@ void AuFolderPanel::update(std::vector<fs::path> paths)
void AuFolderPanel::msw_rescale()
{
m_button_add->SetMinSize(wxSize(FromDIP(80), FromDIP(24)));
m_button_add->SetMinSize(wxSize(-1, FromDIP(24)));
for (auto i = 0; i < m_aufiles_list.GetCount(); i++) {
AuFiles *aufile = m_aufiles_list[i];
aufile->file->msw_rescale();
@ -707,21 +707,14 @@ void AuxiliaryPanel::init_tabpanel()
m_tabpanel->SetBackgroundColour(*wxWHITE);
m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent &e) { ; });
#if !BBL_RELEASE_TO_PUBLIC
m_designer_panel = new DesignerPanel(m_tabpanel, AuxiliaryFolderType::DESIGNER);
#endif
m_pictures_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::MODEL_PICTURE);
m_bill_of_materials_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::BILL_OF_MATERIALS);
m_assembly_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::ASSEMBLY_GUIDE);
m_others_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::OTHERS);
#if !BBL_RELEASE_TO_PUBLIC
m_tabpanel->AddPage(m_designer_panel, _L("Basic Info"), "", true);
m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), "", false);
#else
m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), "", true);
#endif
m_tabpanel->AddPage(m_bill_of_materials_panel, _L("Bill of Materials"), "", false);
m_tabpanel->AddPage(m_assembly_panel, _L("Assembly Guide"), "", false);
m_tabpanel->AddPage(m_others_panel, _L("Others"), "", false);
@ -743,9 +736,7 @@ void AuxiliaryPanel::msw_rescale() {
m_bill_of_materials_panel->msw_rescale();
m_assembly_panel->msw_rescale();
m_others_panel->msw_rescale();
#if !BBL_RELEASE_TO_PUBLIC
m_designer_panel->msw_rescale();
#endif
}
void AuxiliaryPanel::on_size(wxSizeEvent &event)
@ -897,9 +888,7 @@ void AuxiliaryPanel::Reload(wxString aux_path)
fs::create_directory(folder_path.ToStdWstring());
}
update_all_panel();
#if !BBL_RELEASE_TO_PUBLIC
m_designer_panel->update_info();
#endif
return;
}
@ -947,9 +936,7 @@ void AuxiliaryPanel::Reload(wxString aux_path)
update_all_panel();
update_all_cover();
#if !BBL_RELEASE_TO_PUBLIC
m_designer_panel->update_info();
#endif
}
void AuxiliaryPanel::update_all_panel()

View file

@ -77,28 +77,13 @@ void BBLStatusBarBind::set_progress(int val)
if(val < 0)
return;
bool need_layout = false;
//add the logic for arrange/orient jobs, which don't call stop_busy
if(val == m_prog->GetRange()) {
m_prog->SetValue(0);
set_percent_text("0%");
//m_sizer->Hide(m_prog);
need_layout = true;
}
else
{
if (!m_sizer->IsShown(m_prog)) {
m_sizer->Show(m_prog);
m_sizer->Show(m_cancelbutton);
need_layout = true;
}
m_prog->SetValue(val);
set_percent_text(wxString::Format("%d%%", val));
}
if (need_layout) {
m_sizer->Layout();
if (!m_sizer->IsShown(m_prog)) {
m_sizer->Show(m_prog);
m_sizer->Show(m_cancelbutton);
}
m_prog->SetValue(val);
set_percent_text(wxString::Format("%d%%", val));
m_sizer->Layout();
}
int BBLStatusBarBind::get_range() const

View file

@ -26,19 +26,19 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id)
wxBoxSizer *m_sizer_body = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *m_sizer_bottom = new wxBoxSizer(wxHORIZONTAL);
m_status_text = new wxStaticText(m_self, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, 0);
m_status_text = new wxStaticText(m_self, wxID_ANY, L(""), wxDefaultPosition, wxSize(m_self->FromDIP(280), -1), 0);
m_status_text->SetForegroundColour(wxColour(107, 107, 107));
m_status_text->SetFont(::Label::Body_13);
m_status_text->Wrap(-1);
m_sizer_body->Add(m_status_text, 0, 0, 0);
m_status_text->Wrap(m_self->FromDIP(280));
m_prog = new wxGauge(m_self, wxID_ANY, 100, wxDefaultPosition, wxSize(-1, m_self->FromDIP(6)), wxGA_HORIZONTAL);
m_prog->SetValue(0);
block_left = new wxWindow(m_prog, wxID_ANY, wxPoint(0, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2));
block_left->SetBackgroundColour(wxColour(255, 255, 255));
block_right = new wxWindow(m_prog, wxID_ANY, wxPoint(m_prog->GetSize().GetWidth() - 2, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2));
block_right->SetBackgroundColour(wxColour(255, 255, 255));
/* block_left = new wxWindow(m_prog, wxID_ANY, wxPoint(0, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2));
block_left->SetBackgroundColour(wxColour(255, 255, 255));
block_right = new wxWindow(m_prog, wxID_ANY, wxPoint(m_prog->GetSize().GetWidth() - 2, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2));
block_right->SetBackgroundColour(wxColour(255, 255, 255));*/
m_sizer_bottom->Add(m_prog, 1, wxALIGN_CENTER, 0);
@ -47,9 +47,10 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id)
m_cancelbutton->SetTextColor(wxColour(107, 107, 107));
m_cancelbutton->SetBackgroundColor(wxColour(255, 255, 255));
m_cancelbutton->SetCornerRadius(12);
m_cancelbutton->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) {
m_cancelbutton->Bind(wxEVT_BUTTON,
[this](wxCommandEvent &evt) {
m_was_cancelled = true;
if (m_cancel_cb_fina)
if (m_cancel_cb_fina)
m_cancel_cb_fina();
});
@ -60,7 +61,9 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id)
m_sizer_bottom->Add(m_stext_percent, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, 10);
m_sizer_bottom->Add(m_cancelbutton, 0, wxALIGN_CENTER, 0);
m_sizer_body->Add(0, 0, 0, wxTOP, 5);
m_sizer_body->Add(m_status_text, 0, 0, 0);
m_sizer_body->Add(0, 0, 0, wxTOP, 1);
m_sizer_body->Add(m_sizer_bottom, 1, wxEXPAND, 0);
m_sizer->Add(m_sizer_body, 1, wxALIGN_CENTER, 0);
@ -73,8 +76,8 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id)
void BBLStatusBarSend::set_prog_block()
{
block_left->SetPosition(wxPoint(0, 0));
block_right->SetPosition(wxPoint(m_prog->GetSize().GetWidth() - 2, 0));
//block_left->SetPosition(wxPoint(0, 0));
//block_right->SetPosition(wxPoint(m_prog->GetSize().GetWidth() - 2, 0));
}
int BBLStatusBarSend::get_progress() const
@ -84,33 +87,19 @@ int BBLStatusBarSend::get_progress() const
void BBLStatusBarSend::set_progress(int val)
{
set_prog_block();
//set_prog_block();
if(val < 0)
return;
bool need_layout = false;
//add the logic for arrange/orient jobs, which don't call stop_busy
if(val == m_prog->GetRange()) {
m_prog->SetValue(0);
set_percent_text("0%");
m_sizer->Hide(m_prog);
need_layout = true;
}
else
{
if (!m_sizer->IsShown(m_prog)) {
m_sizer->Show(m_prog);
m_sizer->Show(m_cancelbutton);
need_layout = true;
}
m_prog->SetValue(val);
set_percent_text(wxString::Format("%d%%", val));
}
if (need_layout) {
m_sizer->Layout();
if (!m_sizer->IsShown(m_prog)) {
m_sizer->Show(m_prog);
m_sizer->Show(m_cancelbutton);
}
m_prog->SetValue(val);
set_percent_text(wxString::Format("%d%%", val));
m_sizer->Layout();
}
int BBLStatusBarSend::get_range() const
@ -185,6 +174,9 @@ void BBLStatusBarSend::set_status_text(const wxString& txt)
//auto txtss = "The printing project is being uploaded... 25%%";
//m_status_text->SetLabelText(txtss);
m_status_text->SetLabelText(txt);
m_status_text->SetSize(wxSize(m_self->FromDIP(280), -1));
m_status_text->SetMaxSize(wxSize(m_self->FromDIP(280), -1));
m_status_text->Wrap(m_self->FromDIP(280));
}
void BBLStatusBarSend::set_percent_text(const wxString &txt)
@ -203,7 +195,7 @@ void BBLStatusBarSend::set_status_text(const char *txt)
}
void BBLStatusBarSend::msw_rescale() {
set_prog_block();
//set_prog_block();
m_cancelbutton->SetMinSize(wxSize(m_self->FromDIP(56), m_self->FromDIP(24)));
}
@ -230,6 +222,7 @@ void BBLStatusBarSend::reset()
set_status_text("");
m_was_cancelled = false;
set_progress(0);
set_percent_text(wxString::Format("%d%%", 0));
}
@ -250,4 +243,9 @@ void BBLStatusBarSend::hide_cancel_button()
m_sizer->Layout();
}
void BBLStatusBarSend::change_button_label(wxString name)
{
m_cancelbutton->SetLabel(name);
}
}

View file

@ -73,6 +73,7 @@ public:
// Temporary methods to satisfy Perl side
void show_cancel_button();
void hide_cancel_button();
void change_button_label(wxString name);
private:
bool m_busy = false;

View file

@ -11,6 +11,7 @@
#include "PartPlate.hpp"
#define TOPBAR_ICON_SIZE 18
#define TOPBAR_TITLE_WIDTH 300
using namespace Slic3r;
@ -243,7 +244,7 @@ void BBLTopbar::Init(wxFrame* parent)
this->AddSpacer(FromDIP(10));
this->AddStretchSpacer(1);
m_title_item = this->AddLabel(ID_TITLE, "", FromDIP(300));
m_title_item = this->AddLabel(ID_TITLE, "", FromDIP(TOPBAR_TITLE_WIDTH));
m_title_item->SetAlignment(wxCENTER);
this->AddSpacer(FromDIP(10));
@ -402,6 +403,9 @@ wxMenu* BBLTopbar::GetTopMenu()
void BBLTopbar::SetTitle(wxString title)
{
wxGCDC dc(this);
title = wxControl::Ellipsize(title, dc, wxELLIPSIZE_END, FromDIP(TOPBAR_TITLE_WIDTH));
m_title_item->SetLabel(title);
m_title_item->SetAlignment(wxALIGN_CENTRE_HORIZONTAL);
this->Refresh();

View file

@ -436,17 +436,23 @@ void UnBindMachineDilaog::on_unbind_printer(wxCommandEvent &event)
if (result == 0) {
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev) return;
dev->update_user_machine_list_info();
// clean local machine access code info
MachineObject* obj = dev->get_local_machine(m_machine_info->dev_id);
if (obj) {
obj->set_access_code("");
}
dev->erase_user_machine(m_machine_info->dev_id);
m_status_text->SetLabelText(_L("Log out successful."));
m_button_cancel->SetLabel(_L("Close"));
m_button_unbind->Hide();
EndModal(wxID_OK);
}
else {
m_status_text->SetLabelText(_L("Failed to log out."));
EndModal(wxID_CANCEL);
return;
}
EndModal(wxID_OK);
}
void UnBindMachineDilaog::on_dpi_changed(const wxRect &suggested_rect)

View file

@ -97,13 +97,23 @@ CalibrationDialog::CalibrationDialog(Plater *plater)
auto staticline = new ::StaticLine(cali_right_panel);
staticline->SetLineColour(wxColour(0x00, 0xAE, 0x42));
m_calibration_flow = new StepIndicator(cali_right_panel, wxID_ANY);
auto calibration_panel = new wxPanel(cali_right_panel);
calibration_panel->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8));
auto calibration_sizer = new wxBoxSizer(wxVERTICAL);
calibration_panel->SetMinSize(wxSize(FromDIP(170), FromDIP(160)));
calibration_panel->SetSize(wxSize(FromDIP(170), FromDIP(160)));
m_calibration_flow = new StepIndicator(calibration_panel, wxID_ANY);
StateColor bg_color(std::pair<wxColour, int>(wxColour(248, 248, 248), StateColor::Normal));
m_calibration_flow->SetBackgroundColor(bg_color);
m_calibration_flow->SetFont(Label::Body_12);
m_calibration_flow->SetMinSize(wxSize(FromDIP(170), FromDIP(160)));
m_calibration_flow->SetSize(wxSize(FromDIP(170), FromDIP(160)));
calibration_panel->SetSizer(calibration_sizer);
calibration_panel->Layout();
calibration_sizer->Add(m_calibration_flow, 0, wxALIGN_CENTER_HORIZONTAL | wxEXPAND, 0);
StateColor btn_bg_green(std::pair<wxColour, int>(AMS_CONTROL_DISABLE_COLOUR, StateColor::Disabled), std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered), std::pair<wxColour, int>(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal));
@ -119,10 +129,10 @@ CalibrationDialog::CalibrationDialog(Plater *plater)
cali_right_sizer_v->Add(cali_text_right_top, 0, wxALIGN_CENTER, 0);
cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(7));
cali_right_sizer_v->Add(staticline, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10));
cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(9));
cali_right_sizer_v->Add(m_calibration_flow, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(6));
cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(10));
cali_right_sizer_v->Add(m_calibration_btn, 0, wxALIGN_CENTER, 0);
cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(3));
cali_right_sizer_v->Add(calibration_panel, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, FromDIP(6));
cali_right_sizer_v->Add(0, 0, 1, wxEXPAND, 5);
cali_right_sizer_v->Add(m_calibration_btn, 0, wxALIGN_CENTER_HORIZONTAL, 0);
cali_right_sizer_h->Add(cali_right_sizer_v, 0, wxALIGN_CENTER, 0);
cali_right_panel->SetSizer(cali_right_sizer_h);
@ -137,7 +147,6 @@ CalibrationDialog::CalibrationDialog(Plater *plater)
SetSizer(m_sizer_main);
Layout();
Fit();
Centre(wxBOTH);
Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent &evt) { Hide(); });
@ -151,29 +160,41 @@ void CalibrationDialog::on_dpi_changed(const wxRect &suggested_rect) {}
void CalibrationDialog::update_cali(MachineObject *obj)
{
if (!obj) return;
// in printing
if (obj->is_in_printing()) {
m_calibration_flow->DeleteAllItems();
m_calibration_btn->Disable();
return;
} else {
m_calibration_btn->Enable();
if (!obj->is_in_calibration()) {
m_calibration_flow->DeleteAllItems();
m_calibration_btn->SetLabel(_L("Start Calibration"));
if (obj->is_in_calibration() || obj->is_calibration_done()) {
if (obj->is_calibration_done()) {
m_calibration_btn->Enable();
m_calibration_btn->SetLabel(_L("Completed"));
} else {
// RUNNING && IDLE
m_calibration_btn->Disable();
m_calibration_btn->SetLabel(_L("Calibrating"));
if (is_stage_list_info_changed(obj)) {
// change items if stage_list_info changed
m_calibration_flow->DeleteAllItems();
for (int i = 0; i < obj->stage_list_info.size(); i++) { m_calibration_flow->AppendItem(get_stage_string(obj->stage_list_info[i])); }
}
int index = obj->get_curr_stage_idx();
m_calibration_flow->SelectItem(index);
}
auto size = wxSize(-1, obj->stage_list_info.size() * FromDIP(44));
if (m_calibration_flow->GetSize().y != size.y) {
m_calibration_flow->SetSize(size);
m_calibration_flow->SetMinSize(size);
m_calibration_flow->SetMaxSize(size);
Layout();
}
if (is_stage_list_info_changed(obj)) {
// change items if stage_list_info changed
m_calibration_flow->DeleteAllItems();
for (int i = 0; i < obj->stage_list_info.size(); i++) {
m_calibration_flow->AppendItem(get_stage_string(obj->stage_list_info[i]));
}
}
int index = obj->get_curr_stage_idx();
m_calibration_flow->SelectItem(index);
} else {
// IDLE
if (obj->is_in_printing()) {
m_calibration_btn->Disable();
}
else {
m_calibration_btn->Enable();
}
m_calibration_flow->DeleteAllItems();
m_calibration_btn->SetLabel(_L("Start Calibration"));
}
}
@ -193,11 +214,23 @@ bool CalibrationDialog::is_stage_list_info_changed(MachineObject *obj)
void CalibrationDialog::on_start_calibration(wxMouseEvent &event)
{
if (m_obj) {
BOOST_LOG_TRIVIAL(trace) << "on_start_calibration";
m_obj->command_start_calibration();
if (m_obj->is_calibration_done()) {
m_obj->calibration_done = false;
EndModal(wxID_CANCEL);
Close();
} else {
BOOST_LOG_TRIVIAL(info) << "on_start_calibration";
m_obj->command_start_calibration();
}
}
}
void CalibrationDialog::update_machine_obj(MachineObject *obj) { m_obj = obj; }
bool CalibrationDialog::Show(bool show)
{
if (show) { CentreOnParent(); }
return DPIDialog::Show(show);
}
}} // namespace Slic3r::GUI

View file

@ -50,6 +50,7 @@ public:
bool is_stage_list_info_changed(MachineObject *obj);
void on_start_calibration(wxMouseEvent &event);
void update_machine_obj(MachineObject *obj);
bool Show(bool show) override;
};
}} // namespace Slic3r::GUI

View file

@ -3,6 +3,10 @@
#include "I18N.hpp"
#include "Widgets/Label.hpp"
#include "libslic3r/Utils.hpp"
#include "BitmapCache.hpp"
#include <wx/progdlg.h>
#include <wx/clipbrd.h>
#include <wx/dcgraph.h>
namespace Slic3r {
namespace GUI {
@ -128,5 +132,94 @@ void CameraPopup::OnMouse(wxMouseEvent &event)
}
CameraItem::CameraItem(wxWindow *parent,std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
m_bitmap_on_normal = create_scaled_bitmap(on_normal, nullptr, 20);
m_bitmap_off_normal = create_scaled_bitmap(off_normal, nullptr, 20);
m_bitmap_on_hover = create_scaled_bitmap(on_hover, nullptr, 20);
m_bitmap_off_hover = create_scaled_bitmap(off_hover, nullptr, 20);
SetSize(wxSize(FromDIP(20), FromDIP(20)));
SetMinSize(wxSize(FromDIP(20), FromDIP(20)));
SetMaxSize(wxSize(FromDIP(20), FromDIP(20)));
Bind(wxEVT_PAINT, &CameraItem::paintEvent, this);
Bind(wxEVT_ENTER_WINDOW, &CameraItem::on_enter_win, this);
Bind(wxEVT_LEAVE_WINDOW, &CameraItem::on_level_win, this);
}
CameraItem::~CameraItem() {}
void CameraItem::msw_rescale() {}
void CameraItem::set_switch(bool is_on)
{
m_on = is_on;
Refresh();
}
void CameraItem::on_enter_win(wxMouseEvent &evt)
{
m_hover = true;
Refresh();
}
void CameraItem::on_level_win(wxMouseEvent &evt)
{
m_hover = false;
Refresh();
}
void CameraItem::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
// PrepareDC(buffdc);
// PrepareDC(dc);
}
void CameraItem::render(wxDC &dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({0, 0}, size, &dc, {0, 0});
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void CameraItem::doRender(wxDC &dc)
{
if (m_on) {
if (m_hover) {
dc.DrawBitmap(m_bitmap_on_hover, wxPoint((GetSize().x - m_bitmap_on_hover.GetSize().x) / 2, (GetSize().y - m_bitmap_on_hover.GetSize().y) / 2));
} else {
dc.DrawBitmap(m_bitmap_on_normal, wxPoint((GetSize().x - m_bitmap_on_normal.GetSize().x) / 2, (GetSize().y - m_bitmap_on_normal.GetSize().y) / 2));
}
} else {
if (m_hover) {
dc.DrawBitmap(m_bitmap_off_hover, wxPoint((GetSize().x - m_bitmap_off_hover.GetSize().x) / 2, (GetSize().y - m_bitmap_off_hover.GetSize().y) / 2));
} else {
dc.DrawBitmap(m_bitmap_off_normal, wxPoint((GetSize().x - m_bitmap_off_normal.GetSize().x) / 2, (GetSize().y - m_bitmap_off_normal.GetSize().y) / 2));
}
}
}
}
}

View file

@ -5,6 +5,11 @@
#include "DeviceManager.hpp"
#include "GUI.hpp"
#include <wx/panel.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/sizer.h>
#include <wx/gbsizer.h>
#include <wx/webrequest.h>
#include "Widgets/SwitchButton.hpp"
namespace Slic3r {
@ -44,6 +49,31 @@ private:
wxDECLARE_EVENT_TABLE();
};
class CameraItem : public wxPanel
{
public:
CameraItem(wxWindow *parent, std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover);
~CameraItem();
MachineObject *m_obj{nullptr};
bool m_on{false};
bool m_hover{false};
wxBitmap m_bitmap_on_normal;
wxBitmap m_bitmap_on_hover;
wxBitmap m_bitmap_off_normal;
wxBitmap m_bitmap_off_hover;
void msw_rescale();
void set_switch(bool is_on);
bool get_switch_status() { return m_on; };
void on_enter_win(wxMouseEvent &evt);
void on_level_win(wxMouseEvent &evt);
void paintEvent(wxPaintEvent &evt);
void render(wxDC &dc);
void doRender(wxDC &dc);
};
}
}
#endif

View file

@ -519,7 +519,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "support_style", "support_base_pattern",
"support_base_pattern_spacing", "support_angle",
"support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers",
"bridge_no_support","max_bridge_length" "support_top_z_distance",
"bridge_no_support", "thick_bridges", "max_bridge_length", "support_top_z_distance",
//BBS: add more support params to dependent of enable_support
"support_type","support_on_build_plate_only",
"support_object_xy_distance", "independent_support_layer_height"})
@ -537,6 +537,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("tree_support_branch_angle", support_is_tree);
toggle_line("tree_support_wall_count", support_is_tree);
toggle_line("tree_support_with_infill", support_is_tree);
toggle_line("max_bridge_length", support_is_tree);
// tree support use max_bridge_length instead of bridge_no_support
toggle_line("bridge_no_support", !support_is_tree);
for (auto el : { "support_interface_spacing", "support_interface_filament",
"support_interface_loop_pattern", "support_bottom_interface_spacing" })

View file

@ -96,7 +96,7 @@ ConnectPrinterDialog::ConnectPrinterDialog(wxWindow *parent, wxWindowID id, cons
this->SetSizer(main_sizer);
this->Layout();
this->Fit();
this->Centre(wxBOTH);
CentreOnParent();
m_textCtrl_code->Bind(wxEVT_TEXT, &ConnectPrinterDialog::on_input_enter, this);
m_button_confirm->Bind(wxEVT_BUTTON, &ConnectPrinterDialog::on_button_confirm, this);

View file

@ -8,8 +8,9 @@
#include "libslic3r/PlaceholderParser.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "MsgDialog.hpp"
#include "Plater.hpp"
#include "GUI_App.hpp"
#include "nlohmann/json.hpp"
#include <thread>
#include <mutex>
@ -24,7 +25,6 @@ using namespace nlohmann;
namespace pt = boost::property_tree;
const int PRINTING_STAGE_COUNT = 20;
std::string PRINTING_STAGE_STR[PRINTING_STAGE_COUNT] = {
"printing",
@ -455,6 +455,16 @@ void MachineObject::_parse_ams_status(int ams_status)
BOOST_LOG_TRIVIAL(trace) << "ams_debug: main = " << ams_status_main_int << ", sub = " << ams_status_sub;
}
bool MachineObject::is_U0_firmware()
{
auto ota_ver_it = module_vers.find("ota");
if (ota_ver_it != module_vers.end()) {
if (ota_ver_it->second.sw_ver.compare("00.01.04.00") < 0)
return true;
}
return false;
}
bool MachineObject::is_support_ams_mapping()
{
AppConfig* config = Slic3r::GUI::wxGetApp().app_config;
@ -590,7 +600,6 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std
// tray_index : tray_color
std::map<int, FilamentInfo> tray_filaments;
for (auto ams = amsList.begin(); ams != amsList.end(); ams++) {
for (auto tray = ams->second->trayList.begin(); tray != ams->second->trayList.end(); tray++) {
int ams_id = atoi(ams->first.c_str());
@ -634,45 +643,48 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std
// is_support_ams_mapping
if (!is_support_ams_mapping()) {
BOOST_LOG_TRIVIAL(info) << "ams_mapping: do not support, use order mapping";
for (int i = 0; i < filaments.size(); i++) {
FilamentInfo info;
if (i < tray_info_list.size()) {
info.id = filaments[i].id;
info.tray_id = filaments[i].id;
info.color = tray_info_list[i].color;
info.type = tray_info_list[i].type;
} else {
info.id = filaments[i].id;
info.tray_id = -1;
}
info.id = filaments[i].id;
info.tray_id = -1;
result.push_back(info);
}
return 0;
}
// calc distance map
struct DisValue {
int tray_id;
float distance;
bool is_same_color = true;
bool is_type_match = true;
};
char buffer[256];
std::vector<std::vector<DisValue>> distance_map;
// print title
::sprintf(buffer, "F(id)");
std::string line = std::string(buffer);
for (auto tray = tray_filaments.begin(); tray != tray_filaments.end(); tray++) {
::sprintf(buffer, " AMS%02d", tray->second.id+1);
line += std::string(buffer);
}
BOOST_LOG_TRIVIAL(info) << "ams_mapping_distance:" << line;
for (int i = 0; i < filaments.size(); i++) {
std::vector<DisValue> rol;
::sprintf(buffer, "F(%02d)", filaments[i].id+1);
line = std::string(buffer);
for (auto tray = tray_filaments.begin(); tray != tray_filaments.end(); tray++) {
DisValue val;
val.tray_id = tray->first;
val.tray_id = tray->second.id;
wxColour c = wxColour(filaments[i].color);
val.distance = calc_color_distance(c, AmsTray::decode_color(tray->second.color));
//val.is_same_color = val.distance < MAPPING_COLOR_THRESHOLD;
if (filaments[i].type != tray->second.type) {
val.distance = 999999;
val.is_type_match = false;
} else {
val.is_type_match = true;
}
::sprintf(buffer, " %6.0f", val.distance);
line += std::string(buffer);
rol.push_back(val);
}
BOOST_LOG_TRIVIAL(info) << "ams_mapping_distance:" << line;
distance_map.push_back(rol);
}
@ -683,6 +695,7 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std
info.tray_id = -1;
result.push_back(info);
}
std::set<int> picked_src;
std::set<int> picked_tar;
for (int k = 0; k < distance_map.size(); k++) {
@ -693,8 +706,9 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std
if (picked_src.find(i) != picked_src.end())
continue;
for (int j = 0; j < distance_map[i].size(); j++) {
if (picked_tar.find(j) == picked_tar.end()
&& distance_map[i][j].is_same_color
if (picked_tar.find(j) != picked_tar.end())
continue;
if (distance_map[i][j].is_same_color
&& distance_map[i][j].is_type_match) {
if (min_val > distance_map[i][j].distance) {
min_val = distance_map[i][j].distance;
@ -707,25 +721,31 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std
if (picked_src_idx >= 0 && picked_tar_idx >= 0) {
auto tray = tray_filaments.find(distance_map[k][picked_tar_idx].tray_id);
if (tray != tray_filaments.end()) {
result[picked_src_idx].tray_id = tray->first;
result[picked_src_idx].color = tray->second.color;
result[picked_src_idx].type = tray->second.type;
BOOST_LOG_TRIVIAL(trace) << "tray_id = " << tray->first << ", distance = " << distance_map[k][picked_tar_idx].distance;
result[picked_src_idx].tray_id = tray->first;
result[picked_src_idx].color = tray->second.color;
result[picked_src_idx].type = tray->second.type;
result[picked_src_idx].distance = tray->second.distance;
}
else {
FilamentInfo info;
info.tray_id = -1;
}
picked_tar.insert(picked_tar_idx);
::sprintf(buffer, "ams_mapping, picked F(%02d) AMS(%02d), distance=%6.0f", picked_src_idx+1, picked_tar_idx+1,
distance_map[picked_src_idx][picked_tar_idx].distance);
BOOST_LOG_TRIVIAL(info) << std::string(buffer);
picked_src.insert(picked_src_idx);
picked_tar.insert(picked_tar_idx);
}
}
std::vector<FilamentInfo> cache_map_result = result;
//check ams mapping result
if (is_valid_mapping_result(result)) {
return 0;
}
reset_mapping_result(result);
try {
// try to use ordering ams mapping
bool order_mapping_result = true;
@ -749,15 +769,23 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std
}
//check order mapping result
if (!is_valid_mapping_result(result)) {
reset_mapping_result(result);
return -1;
if (is_valid_mapping_result(result)) {
return 0;
}
} catch(...) {
reset_mapping_result(result);
return -1;
}
// try to match some color
reset_mapping_result(result);
result = cache_map_result;
for (auto it = result.begin(); it != result.end(); it++) {
if (it->distance >= 6000) {
it->tray_id = -1;
}
}
return 0;
}
@ -778,6 +806,7 @@ void MachineObject::reset_mapping_result(std::vector<FilamentInfo>& result)
{
for (int i = 0; i < result.size(); i++) {
result[i].tray_id = -1;
result[i].distance = 99999;
}
}
@ -904,7 +933,7 @@ std::map<int, MachineObject::ModuleVersionInfo> MachineObject::get_ams_version()
bool MachineObject::is_system_printing()
{
if (is_in_calibration())
if (is_in_calibration() && is_in_printing_status(print_status))
return true;
//FIXME
//if (print_type == "system" && is_in_printing_status(print_status))
@ -936,10 +965,40 @@ bool MachineObject::is_in_calibration()
if (boost::contains(m_gcode_file, "auto_cali_for_user.gcode")
&& stage_curr != 0) {
return true;
} else {
// reset
if (stage_curr != 0) {
calibration_done = false;
}
}
return false;
}
bool MachineObject::is_calibration_done()
{
return calibration_done;
}
bool MachineObject::is_calibration_running()
{
if (is_in_calibration() && is_in_printing_status(print_status))
return true;
return false;
}
void MachineObject::parse_state_changed_event()
{
// parse calibration done
if (last_mc_print_stage != mc_print_stage) {
if (mc_print_stage == 1 && boost::contains(m_gcode_file, "auto_cali_for_user.gcode")) {
calibration_done = true;
} else {
calibration_done = false;
}
}
last_mc_print_stage = mc_print_stage;
}
PrintingSpeedLevel MachineObject::_parse_printing_speed_lvl(int lvl)
{
if (lvl < (int)SPEED_LEVEL_COUNT)
@ -950,7 +1009,10 @@ PrintingSpeedLevel MachineObject::_parse_printing_speed_lvl(int lvl)
bool MachineObject::is_sdcard_printing()
{
if (can_abort() && obj_subtask_id.compare("0") == 0 && profile_id_ == "0" && project_id_ == "0")
if (can_abort()
&& (obj_subtask_id.compare("0") == 0 || obj_subtask_id.empty())
&& (profile_id_ == "0" || profile_id_.empty())
&& (project_id_ == "0" || project_id_.empty()))
return true;
else
return false;
@ -961,6 +1023,16 @@ bool MachineObject::has_sdcard()
return camera_has_sdcard;
}
bool MachineObject::has_timelapse()
{
return camera_timelapse;
}
bool MachineObject::has_recording()
{
return camera_recording;
}
int MachineObject::command_get_version()
{
json j;
@ -974,10 +1046,10 @@ int MachineObject::command_request_push_all()
auto curr_time = std::chrono::system_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(curr_time - last_request_push);
if (diff.count() < REQUEST_PUSH_MIN_TIME) {
BOOST_LOG_TRIVIAL(trace) << "command_request_push_all: send request too fast";
BOOST_LOG_TRIVIAL(trace) << "static: command_request_push_all: send request too fast, dev_id=" << dev_id;
return -1;
} else {
BOOST_LOG_TRIVIAL(trace) << "command_request_push_all";
BOOST_LOG_TRIVIAL(trace) << "static: command_request_push_all, dev_id=" << dev_id;
last_request_push = std::chrono::system_clock::now();
}
json j;
@ -1365,6 +1437,11 @@ bool MachineObject::is_in_printing()
return false;
}
bool MachineObject::is_in_prepare()
{
return print_status == "PREPARE";
}
bool MachineObject::is_printing_finished()
{
if (print_status.compare("FINISH") == 0
@ -1388,8 +1465,10 @@ void MachineObject::reset()
camera_recording = false;
camera_timelapse = false;
printing_speed_mag = 100;
gcode_file_prepare_percent = 0;
iot_print_status = "";
print_status = "";
last_mc_print_stage = -1;
subtask_ = nullptr;
@ -1444,6 +1523,11 @@ bool MachineObject::is_connected()
return true;
}
bool MachineObject::is_connecting()
{
return is_connected() && m_push_count == 0;
}
void MachineObject::set_online_state(bool on_off)
{
m_is_online = on_off;
@ -1508,9 +1592,10 @@ int MachineObject::parse_json(std::string payload)
if (j_pre.contains("print")) {
if (j_pre["print"].contains("command")) {
if (j_pre["print"]["command"].get<std::string>() == "push_status") {
m_push_count++;
if (j_pre["print"].contains("msg")) {
if (j_pre["print"]["msg"].get<int>() == 0) { //all message
BOOST_LOG_TRIVIAL(trace) << "static: get push_all msg, dev_id=" << dev_id;
m_push_count++;
print_json.diff2all_base_reset(j_pre);
} else if (j_pre["print"]["msg"].get<int>() == 1) { //diff message
if (print_json.diff2all(j_pre, j) == 0) {
@ -1544,11 +1629,14 @@ int MachineObject::parse_json(std::string payload)
json jj = j["print"];
if (jj.contains("command")) {
if (jj["command"].get<std::string>() == "push_status") {
m_push_count++;
last_push_time = std::chrono::system_clock::now();
#pragma region printing
// U0 firmware
if (jj.contains("print_type")) {
print_type = jj["print_type"].get<std::string>();
}
if (jj.contains("mc_remaining_time")) {
if (jj["mc_remaining_time"].is_string())
mc_left_time = stoi(j["print"]["mc_remaining_time"].get<std::string>()) * 60;
@ -1603,8 +1691,15 @@ int MachineObject::parse_json(std::string payload)
if (jj.contains("gcode_file"))
this->m_gcode_file = jj["gcode_file"].get<std::string>();
if (jj.contains("project_id")
if (jj.contains("gcode_file_prepare_percent")) {
std::string percent_str = jj["gcode_file_prepare_percent"].get<std::string>();
if (!percent_str.empty()) {
try{
this->gcode_file_prepare_percent = atoi(percent_str.c_str());
} catch(...) {}
}
}
if (jj.contains("project_id")
&& jj.contains("profile_id")
&& jj.contains("subtask_id")
){
@ -1633,11 +1728,11 @@ int MachineObject::parse_json(std::string payload)
curr_task->task_progress = mc_print_percent;
curr_task->printing_status = print_status;
curr_task->task_id = jj["subtask_id"].get<std::string>();
}
}
#pragma endregion
#pragma region status
/* temperature */
if (jj.contains("bed_temper")) {
@ -1755,14 +1850,14 @@ int MachineObject::parse_json(std::string payload)
camera_has_sdcard = jj["sdcard"].get<bool>();
} else {
//do not check sdcard if no sdcard field
camera_has_sdcard = true;
camera_has_sdcard = false;
}
}
catch (...) {
;
}
#pragma endregion
#pragma region upgrade
try {
if (jj.contains("upgrade_state")) {
@ -1788,9 +1883,15 @@ int MachineObject::parse_json(std::string payload)
upgrade_force_upgrade = jj["upgrade_state"]["force_upgrade"].get<bool>();
if (jj["upgrade_state"].contains("err_code"))
upgrade_err_code = jj["upgrade_state"]["err_code"].get<int>();
if (jj["upgrade_state"].contains("dis_state"))
if (jj["upgrade_state"].contains("dis_state")) {
if (upgrade_display_state != jj["upgrade_state"]["dis_state"].get<int>()
&& jj["upgrade_state"]["dis_state"].get<int>() == 3) {
GUI::wxGetApp().CallAfter([this] {
this->command_get_version();
});
}
upgrade_display_state = jj["upgrade_state"]["dis_state"].get<int>();
else {
} else {
//BBS compatibility with old version
if (upgrade_status == "DOWNLOADING"
|| upgrade_status == "FLASHING"
@ -1847,7 +1948,7 @@ int MachineObject::parse_json(std::string payload)
catch (...) {
;
}
#pragma endregion
#pragma endregion
#pragma region hms
// parse hms msg
@ -1977,9 +2078,17 @@ int MachineObject::parse_json(std::string payload)
curr_tray = tray_iter->second;
}
if (!curr_tray) continue;
if (curr_tray->hold_count > 0) {
curr_tray->hold_count--;
continue;
}
curr_tray->id = (*tray_it)["id"].get<std::string>();
if (tray_it->contains("tag_uid"))
curr_tray->tag_uid = (*tray_it)["tag_uid"].get<std::string>();
else
curr_tray->tag_uid = "0";
if (tray_it->contains("tray_info_idx") && tray_it->contains("tray_type")) {
curr_tray->setting_id = (*tray_it)["tray_info_idx"].get<std::string>();
std::string type = (*tray_it)["tray_type"].get<std::string>();
@ -1990,32 +2099,59 @@ int MachineObject::parse_json(std::string payload)
} else {
curr_tray->type = type;
}
} else {
curr_tray->setting_id = "";
curr_tray->type = "";
}
if (tray_it->contains("tray_sub_brands"))
curr_tray->sub_brands = (*tray_it)["tray_sub_brands"].get<std::string>();
else
curr_tray->sub_brands = "";
if (tray_it->contains("tray_weight"))
curr_tray->weight = (*tray_it)["tray_weight"].get<std::string>();
else
curr_tray->weight = "";
if (tray_it->contains("tray_diameter"))
curr_tray->diameter = (*tray_it)["tray_diameter"].get<std::string>();
else
curr_tray->diameter = "";
if (tray_it->contains("tray_temp"))
curr_tray->temp = (*tray_it)["tray_temp"].get<std::string>();
else
curr_tray->temp = "";
if (tray_it->contains("tray_time"))
curr_tray->time = (*tray_it)["tray_time"].get<std::string>();
else
curr_tray->time = "";
if (tray_it->contains("bed_temp_type"))
curr_tray->bed_temp_type = (*tray_it)["bed_temp_type"].get<std::string>();
else
curr_tray->bed_temp_type = "";
if (tray_it->contains("bed_temp"))
curr_tray->bed_temp = (*tray_it)["bed_temp"].get<std::string>();
else
curr_tray->bed_temp = "";
if (tray_it->contains("nozzle_temp_max"))
curr_tray->nozzle_temp_max = (*tray_it)["nozzle_temp_max"].get<std::string>();
else
curr_tray->nozzle_temp_max = "";
if (tray_it->contains("nozzle_temp_min"))
curr_tray->nozzle_temp_min = (*tray_it)["nozzle_temp_min"].get<std::string>();
else
curr_tray->nozzle_temp_min = "";
if (tray_it->contains("xcam_info"))
curr_tray->xcam_info = (*tray_it)["xcam_info"].get<std::string>();
else
curr_tray->xcam_info = "";
if (tray_it->contains("tray_uuid"))
curr_tray->uuid = (*tray_it)["tray_uuid"].get<std::string>();
else
curr_tray->uuid = "0";
if (tray_it->contains("tray_color")) {
auto color = (*tray_it)["tray_color"].get<std::string>();
curr_tray->update_color_from_str(color);
} else {
curr_tray->color = "";
}
try {
if (!ams_id.empty() && !curr_tray->id.empty()) {
@ -2051,12 +2187,20 @@ int MachineObject::parse_json(std::string payload)
}
#pragma endregion
} else if (jj["command"].get<std::string>() == "gcode_line") {
//ack of gcode_line
BOOST_LOG_TRIVIAL(debug) << "parse_json, ack of gcode_line = " << j.dump(4);
} else if (jj["command"].get<std::string>() == "project_file") {
//ack of project file
BOOST_LOG_TRIVIAL(debug) << "parse_json, ack of project_file = " << j.dump(4);
std::string result;
if (jj.contains("result")) {
result = jj["result"].get<std::string>();
if (result == "FAIL") {
wxString text = _L("Failed to start printing job");
GUI::wxGetApp().show_dialog(text);
}
}
} else if (jj["command"].get<std::string>() == "ams_filament_setting") {
if (jj["ams_id"].is_number()) {
int ams_id = jj["ams_id"].get<int>();
@ -2071,6 +2215,8 @@ int MachineObject::parse_json(std::string payload)
tray_it->second->type = jj["tray_type"].get<std::string>();
tray_it->second->color = jj["tray_color"].get<std::string>();
tray_it->second->setting_id = jj["tray_info_idx"].get<std::string>();
// delay update
tray_it->second->set_hold_count();
} else {
BOOST_LOG_TRIVIAL(warning) << "ams_filament_setting, can not find in trayList, tray_id=" << tray_id;
}
@ -2133,6 +2279,8 @@ int MachineObject::parse_json(std::string payload)
}
}
catch (...) {}
parse_state_changed_event();
}
catch (...) {
BOOST_LOG_TRIVIAL(trace) << "parse_json failed! dev_id=" << this->dev_id <<", payload = " << payload;
@ -2339,6 +2487,10 @@ DeviceManager::~DeviceManager()
userMachineList.clear();
}
void DeviceManager::set_agent(NetworkAgent* agent)
{
m_agent = agent;
}
void DeviceManager::on_machine_alive(std::string json_str)
{
@ -2376,7 +2528,12 @@ void DeviceManager::on_machine_alive(std::string json_str)
obj->wifi_signal = printer_signal;
obj->dev_connection_type = connect_type;
obj->bind_state = bind_state;
BOOST_LOG_TRIVIAL(info) << "SsdpDiscovery:: Update Machine Info, printer_sn = " << dev_id << ", signal = " << printer_signal;
// U0 firmware
if (obj->dev_connection_type.empty() && obj->bind_state.empty())
obj->bind_state = "free";
BOOST_LOG_TRIVIAL(debug) << "SsdpDiscovery:: Update Machine Info, printer_sn = " << dev_id << ", signal = " << printer_signal;
obj->last_alive = Slic3r::Utils::get_current_time_utc();
obj->m_is_online = true;
}
@ -2396,7 +2553,7 @@ void DeviceManager::on_machine_alive(std::string json_str)
localMachineList.insert(std::make_pair(dev_id, obj));
BOOST_LOG_TRIVIAL(info) << "SsdpDiscovery::New Machine, ip = " << dev_ip << ", printer_name= " << dev_name << ", printer_type = " << printer_type_str << ", signal = " << printer_signal;
BOOST_LOG_TRIVIAL(debug) << "SsdpDiscovery::New Machine, ip = " << dev_ip << ", printer_name= " << dev_name << ", printer_type = " << printer_type_str << ", signal = " << printer_signal;
}
}
catch (...) {
@ -2480,6 +2637,11 @@ MachineObject* DeviceManager::get_local_machine(std::string dev_id)
return it->second;
}
void DeviceManager::erase_user_machine(std::string dev_id)
{
userMachineList.erase(dev_id);
}
MachineObject* DeviceManager::get_user_machine(std::string dev_id)
{
if (!Slic3r::GUI::wxGetApp().is_user_login())
@ -2522,7 +2684,7 @@ void DeviceManager::clean_user_info()
bool DeviceManager::set_selected_machine(std::string dev_id)
{
BOOST_LOG_TRIVIAL(trace) << "set_selected_machine=" << dev_id;
BOOST_LOG_TRIVIAL(info) << "set_selected_machine=" << dev_id;
auto my_machine_list = get_my_machine_list();
auto it = my_machine_list.find(dev_id);
if (it != my_machine_list.end()) {
@ -2534,7 +2696,7 @@ bool DeviceManager::set_selected_machine(std::string dev_id)
if (m_agent) {
if (it->second->connection_type() != "lan" || it->second->connection_type().empty()) {
if (m_agent->get_user_selected_machine() != dev_id) {
BOOST_LOG_TRIVIAL(trace) << "set_selected_machine: same dev_id = " << dev_id;
BOOST_LOG_TRIVIAL(info) << "static: set_selected_machine: same dev_id = " << dev_id;
m_agent->set_user_selected_machine(dev_id);
it->second->reset();
} else {
@ -2680,7 +2842,7 @@ void DeviceManager::update_user_machine_list_info()
{
if (!m_agent) return;
BOOST_LOG_TRIVIAL(trace) << "update_user_machine_list_info";
BOOST_LOG_TRIVIAL(debug) << "update_user_machine_list_info";
unsigned int http_code;
std::string body;
int result = m_agent->get_user_print_info(&http_code, &body);

View file

@ -13,9 +13,9 @@
#define USE_LOCAL_SOCKET_BIND 0
#define DISCONNECT_TIMEOUT 10000.f // milliseconds
#define DISCONNECT_TIMEOUT 30000.f // milliseconds
#define PUSHINFO_TIMEOUT 15000.f // milliseconds
#define REQUEST_PUSH_MIN_TIME 3000.f // milliseconds
#define REQUEST_PUSH_MIN_TIME 15000.f // milliseconds
#define FILAMENT_MAX_TEMP 300
#define FILAMENT_DEF_TEMP 220
@ -153,11 +153,13 @@ public:
wxColour wx_color;
bool is_bbl;
bool is_exists = false;
int hold_count = 0;
AmsRoadPosition road_position;
AmsStep step_state;
AmsRfidState rfid_state;
void set_hold_count() { hold_count = 3; }
void update_color_from_str(std::string color);
wxColour get_color();
@ -244,7 +246,13 @@ public:
#define UpgradeFlashFailed -3
#define UpgradePrinting -4
// calc distance map
struct DisValue {
int tray_id;
float distance;
bool is_same_color = true;
bool is_type_match = true;
};
class MachineObject
{
@ -347,6 +355,7 @@ public:
// parse amsStatusMain and ams_status_sub
void _parse_ams_status(int ams_status);
bool has_ams() { return ams_exist_bits != 0; }
bool is_U0_firmware();
bool is_support_ams_mapping();
bool is_only_support_cloud_print();
static bool is_support_ams_mapping_version(std::string module, std::string version);
@ -415,16 +424,22 @@ public:
int mc_print_line_number;
int mc_print_percent; /* left print progess in percent */
int mc_left_time; /* left time in seconds */
int last_mc_print_stage;
bool is_system_printing();
std::vector<int> stage_list_info;
int stage_curr = 0;
int m_push_count = 0;
bool calibration_done { false };
wxString get_curr_stage();
// return curr stage index of stage list
int get_curr_stage_idx();
bool is_in_calibration();
bool is_calibration_running();
bool is_calibration_done();
void parse_state_changed_event();
/* printing status */
std::string print_status; /* enum string: FINISH, RUNNING, PAUSE, INIT, FAILED */
@ -455,11 +470,14 @@ public:
BBLSliceInfo* slice_info {nullptr};
int plate_index { -1 };
std::string m_gcode_file;
int gcode_file_prepare_percent = 0;
BBLSubTask* subtask_;
std::string obj_subtask_id; // subtask_id == 0 for sdcard
std::string subtask_name;
bool is_sdcard_printing();
bool has_sdcard();
bool has_timelapse();
bool has_recording();
MachineObject(NetworkAgent* agent, std::string name, std::string id, std::string ip);
@ -517,6 +535,7 @@ public:
bool can_pause();
bool can_abort();
bool is_in_printing();
bool is_in_prepare();
bool is_printing_finished();
void reset_update_time();
void reset();
@ -525,6 +544,7 @@ public:
void set_print_state(std::string status);
bool is_connected();
bool is_connecting();
void set_online_state(bool on_off);
bool is_online() { return m_is_online; }
bool is_info_ready();
@ -554,6 +574,7 @@ private:
public:
DeviceManager(NetworkAgent* agent = nullptr);
~DeviceManager();
void set_agent(NetworkAgent* agent);
std::mutex listMutex;
std::string selected_machine; /* dev_id */
@ -566,6 +587,7 @@ public:
MachineObject* get_local_machine(std::string dev_id);
MachineObject* get_user_machine(std::string dev_id);
MachineObject* get_my_machine(std::string dev_id);
void erase_user_machine(std::string dev_id);
void clean_user_info();
bool set_selected_machine(std::string dev_id);
@ -588,8 +610,6 @@ public:
// get alive machine
std::map<std::string, MachineObject*> get_local_machine_list();
void load_last_machine();
void check_alive();
};
} // namespace Slic3r

View file

@ -0,0 +1,100 @@
#include "DownloadProgressDialog.hpp"
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/statbmp.h>
#include <wx/scrolwin.h>
#include <wx/clipbrd.h>
#include <wx/checkbox.h>
#include <wx/html/htmlwin.h>
#include <boost/algorithm/string/replace.hpp>
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include "I18N.hpp"
//#include "ConfigWizard.hpp"
#include "wxExtensions.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "GUI_App.hpp"
#define DESIGN_INPUT_SIZE wxSize(FromDIP(100), -1)
namespace Slic3r {
namespace GUI {
DownloadProgressDialog::DownloadProgressDialog(wxString title)
: DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
{
std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
SetBackgroundColour(*wxWHITE);
wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL);
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1));
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0);
m_status_bar = std::make_shared<BBLStatusBarSend>(this);
m_panel_download = m_status_bar->get_panel();
m_panel_download->SetSize(wxSize(FromDIP(340), -1));
m_panel_download->SetMinSize(wxSize(FromDIP(340), -1));
m_panel_download->SetMaxSize(wxSize(FromDIP(340), -1));
m_sizer_main->Add(m_panel_download, 0, wxALIGN_CENTER_VERTICAL|wxALL, FromDIP(20));
m_sizer_main->Add(0, 0, 1, wxBOTTOM, 10);
SetSizer(m_sizer_main);
Layout();
Fit();
CentreOnParent();
}
bool DownloadProgressDialog::Show(bool show)
{
if (show) {
m_upgrade_job = std::make_shared<UpgradeNetworkJob>(m_status_bar);
m_upgrade_job->set_event_handle(this);
m_status_bar->set_progress(0);
Bind(EVT_UPGRADE_NETWORK_SUCCESS, [this](wxCommandEvent& evt) {
m_status_bar->change_button_label(_L("Finish"));
wxGetApp().restart_networking();
m_status_bar->set_cancel_callback_fina(
[this]() {
this->Close();
}
);
});
Bind(EVT_UPGRADE_NETWORK_FAILED, [this](wxCommandEvent& evt) {
m_status_bar->change_button_label(_L("Close"));
m_status_bar->set_progress(0);
m_status_bar->set_cancel_callback_fina(
[this]() {
this->Close();
}
);
});
m_status_bar->set_cancel_callback_fina([this]() {
if (m_upgrade_job) {
m_upgrade_job->cancel();
//EndModal(wxID_CLOSE);
}
});
m_upgrade_job->start();
}
return DPIDialog::Show(show);
}
DownloadProgressDialog::~DownloadProgressDialog() {}
void DownloadProgressDialog::on_dpi_changed(const wxRect &suggested_rect) {}
void DownloadProgressDialog::update_release_note(std::string release_note, std::string version) {}
}} // namespace Slic3r::GUI

View file

@ -0,0 +1,55 @@
#ifndef slic3r_DownloadProgressDialog_hpp_
#define slic3r_DownloadProgressDialog_hpp_
#include <string>
#include <unordered_map>
#include "GUI_Utils.hpp"
#include <wx/dialog.h>
#include <wx/font.h>
#include <wx/bitmap.h>
#include <wx/msgdlg.h>
#include <wx/richmsgdlg.h>
#include <wx/textctrl.h>
#include <wx/statline.h>
#include "Widgets/Button.hpp"
#include "BBLStatusBar.hpp"
#include "BBLStatusBarSend.hpp"
#include "Jobs/UpgradeNetworkJob.hpp"
class wxBoxSizer;
class wxCheckBox;
class wxStaticBitmap;
#define MSG_DIALOG_BUTTON_SIZE wxSize(FromDIP(58), FromDIP(24))
#define MSG_DIALOG_MIDDLE_BUTTON_SIZE wxSize(FromDIP(76), FromDIP(24))
#define MSG_DIALOG_LONG_BUTTON_SIZE wxSize(FromDIP(90), FromDIP(24))
namespace Slic3r {
namespace GUI {
class DownloadProgressDialog : public DPIDialog
{
protected:
bool Show(bool show) override;
public:
DownloadProgressDialog(wxString title);
~DownloadProgressDialog();
void on_dpi_changed(const wxRect &suggested_rect) override;
void update_release_note(std::string release_note, std::string version);
std::shared_ptr<BBLStatusBarSend> m_status_bar;
std::shared_ptr<UpgradeNetworkJob> m_upgrade_job;
wxPanel * m_panel_download;
};
}
}
#endif

View file

@ -4988,7 +4988,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / /*1000*/koef);
imgui.text(buf);
ImGui::SameLine();
::sprintf(buf, " %.2f g", ps.total_weight);
double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1;
::sprintf(buf, imperial_units ?" %.2f oz":" %.2f g", ps.total_weight / unit_conver);
imgui.text(buf);
auto role_time = [time_mode](ExtrusionRole role) {

View file

@ -1349,7 +1349,12 @@ void GLCanvas3D::render(bool only_init)
right_margin = SLIDER_RIGHT_MARGIN;
bottom_margin = SLIDER_BOTTOM_MARGIN;
}
wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin);
#if ENABLE_RETINA_GL
float sc = m_retina_helper->get_scale_factor();
wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin * sc, right_margin);
#else
wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin);
#endif
}
wxGetApp().imgui()->render();
@ -3038,6 +3043,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// Grab keyboard focus for input in gizmo dialogs.
m_canvas->SetFocus();
if (evt.LeftDown()) {
// Clear hover state in main toolbar
wxMouseEvent evt2 = evt;
evt2.SetEventType(wxEVT_MOTION);
evt2.SetLeftDown(false);
m_main_toolbar.on_mouse(evt2, *this);
}
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
mouse_up_cleanup();
@ -6397,34 +6410,25 @@ void GLCanvas3D::_render_paint_toolbar() const
}
}
#ifdef __APPLE__
std::string item_text = (boost::format("%1% %2%") % (11) % filament_types[0]).str();
const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true);
int button_size = label_size.x + item_spacing;
#else
int button_size = GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale() + item_spacing;
#endif
float button_size = GLToolbar::Default_Icons_Size * f_scale * wxGetApp().toolbar_icon_scale() + item_spacing;
imgui.set_next_window_pos(0.5f * (canvas_w + (button_size + item_spacing) * extruder_num), button_size + item_spacing * 2, ImGuiCond_Always, 1.0f, 1.0f);
imgui.begin(_L("Paint Toolbar"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar);
bool disabled = !wxGetApp().plater()->can_fillcolor();
unsigned char rgb[3];
float max_text = 0;
for (int i = 0; i < extruder_num; i++) {
if (i > 0) {
if (filament_types.size() <= i) continue;
std::string item_text = (boost::format("%1% %2%") % (i + 1) % filament_types[i]).str();
const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true);
#ifdef __WINDOWS__
if (i > 8)
ImGui::SameLine(0.5 * item_spacing + (button_size - label_size.x) / 2 + (button_size + item_spacing) * i);
else
ImGui::SameLine((button_size - label_size.x) / 2 + (button_size + item_spacing) * i);
#else
ImGui::SameLine();
#endif
}
//ImGui::SameLine();
std::string item_text = (boost::format("%1%%2%") % (i + 1) % filament_types[i]).str();
ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true);
if (label_size.x > button_size)
label_size.x = button_size * 0.6;
max_text = std::max(max_text,label_size.x);
}
for (int i = 0; i < extruder_num; i++) {
if (filament_types.size() <= i) continue;
ImGui::SameLine(item_spacing / 2 + (button_size - max_text) / 2 + (button_size + item_spacing) * i);
ImGui::PushID(i);
Slic3r::GUI::BitmapCache::parse_color(colors[i], rgb);
ImGui::PushStyleColor(ImGuiCol_Button, ImColor(rgb[0], rgb[1], rgb[2]).Value);
@ -6450,21 +6454,78 @@ void GLCanvas3D::_render_paint_toolbar() const
ImGui::PopItemFlag();
ImGui::PopID();
}
for (int i = 0; i < extruder_num; i++){
if (filament_types.size() <= i) continue;
//TODO use filament type from filament management, current use PLA by default
std::string item_text = (boost::format("%1% %2%") % (i + 1) % filament_types[i]).str();
std::string item_text = (boost::format("%1%%2%") % (i + 1) % filament_types[i]).str();
const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true);
ImGui::SameLine(item_spacing + (button_size - label_size.x) / 2 + (button_size + item_spacing) * i);
int len = strlen(filament_types[i].c_str());
ImGui::SameLine(item_spacing / 2 + (button_size - max_text) / 2 + (button_size + item_spacing) * i);
int count = 0;
if (label_size.x > button_size)
{
for (int j = 0; j < filament_types[i].size(); j++)
{
if(std::isalpha(filament_types[i][j]))
count++;
else
break;
}
}
if (i > 8)
{
if (label_size.x > button_size)
{
if(count * ImGui::GetFontSize() > button_size){
if ((len - (count + 1)) <= 3)
item_text = "\t" + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count) + "\n" + "\t" + filament_types[i].substr(count, len);
else
item_text = "\t" + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n"+ filament_types[i].substr(count + 1, len);
} else {
if (count <= 4)
item_text = "\t" + std::to_string(i + 1) + "\n" + " " + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len);
else
item_text = "\t" + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len);
}
}
else
{
item_text = (boost::format("\t%1%\n %2%") % (i + 1) % filament_types[i]).str();
}
}
else
{
if (label_size.x > button_size)
{
if(count * ImGui::GetFontSize() > button_size){
if ((len - (count + 1)) <= 3)
item_text = "\t " + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count) + "\n" + "\t" + filament_types[i].substr(count, len);
else
item_text = "\t " + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n"+ filament_types[i].substr(count + 1, len);
} else {
if (count <= 4)
item_text = "\t " + std::to_string(i + 1) + "\n" + " " + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len);
else
item_text = "\t " + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len);
}
}
else
{
item_text = (boost::format("\t %1%\n\t%2%") % (i + 1) % filament_types[i]).str();
}
}
Slic3r::GUI::BitmapCache::parse_color(colors[i], rgb);
float gray = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2];
if (gray < 80)
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), item_text.c_str());
else
ImGui::TextColored(ImVec4(0.0f, 0.0f, 0.0f, 1.0f), item_text.c_str());
if (gray < 80){
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), item_text.c_str());
} else{
ImGui::TextColored(ImVec4(0.0f, 0.0f, 0.0f, 1.0f), item_text.c_str());
}
}
ImGui::AlignTextToFramePadding();
imgui.end();
@ -7468,8 +7529,8 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
case EWarning::SlaSupportsOutside: text = ("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
case EWarning::SomethingNotShown: text = _u8L("Only the object being edit is visible."); break;
case EWarning::ObjectClashed:
text = _u8L("An object is layed over the boundary of plate.\n"
"Please solve the problem by moving it totally inside or outside plate.");
text = _u8L("An object is laid over the boundary of plate or exceeds the height limit.\n"
"Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume.");
error = ErrorType::PLATER_ERROR;
break;
}

View file

@ -299,10 +299,12 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
::memcpy((void*)pressed_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i) {
int offset = i * 4;
if (pressed_data.data()[offset] == 0) {
::memset((void*)&pressed_data.data()[offset], 172, 3);
pressed_data.data()[offset + 3] = (unsigned char)150;
}
if (pressed_data.data()[offset + 0] == 0 &&
pressed_data.data()[offset + 1] == 0 &&
pressed_data.data()[offset + 2] == 0) {
::memset((void*)&pressed_data.data()[offset], 238, 3);
pressed_data.data()[offset + 3] = (unsigned char) 225;
}
}
::memcpy((void*)disable_data.data(), (const void*)sprite_data.data(), sprite_bytes);
@ -315,25 +317,36 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
::memcpy((void*)hover_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i) {
int offset = i * 4;
if (hover_data.data()[offset] == 0) {
::memset((void*)&hover_data.data()[offset], 172, 3);
hover_data.data()[offset + 3] = (unsigned char)75;
if (hover_data.data()[offset + 0] == 0 &&
hover_data.data()[offset + 1] == 0 &&
hover_data.data()[offset + 2] == 0)
{
::memset((void *) &hover_data.data()[offset], 238, 3);
hover_data.data()[offset + 3] = (unsigned char) 75;
}
}
::memcpy((void*)sprite_white_only_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i) {
int offset = i * 4;
if (sprite_white_only_data.data()[offset + 0] != 0 ||
sprite_white_only_data.data()[offset + 1] != 0 ||
sprite_white_only_data.data()[offset + 2] != 0){
sprite_white_only_data.data()[offset + 0] = (unsigned char) 43;
sprite_white_only_data.data()[offset + 1] = (unsigned char) 52;
sprite_white_only_data.data()[offset + 2] = (unsigned char) 54;
}
}
::memcpy((void*)sprite_gray_only_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i) {
int offset = i * 4;
if (sprite_gray_only_data.data()[offset + 0] == 0) {
if (sprite_gray_only_data.data()[offset + 0] != 0 ||
sprite_gray_only_data.data()[offset + 1] != 0 ||
sprite_gray_only_data.data()[offset + 2] != 0 ) {
::memset((void*)&sprite_gray_only_data.data()[offset], 200, 3);
}
else {
sprite_gray_only_data.data()[offset + 0] = (unsigned char)(sprite_data.data()[offset + 0] * 0.3 + 178);
sprite_gray_only_data.data()[offset + 1] = (unsigned char)(sprite_data.data()[offset + 1] * 0.3 + 178);
sprite_gray_only_data.data()[offset + 2] = (unsigned char)(sprite_data.data()[offset + 2] * 0.3 + 178);
}
}
@ -394,9 +407,9 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));

View file

@ -538,4 +538,52 @@ void desktop_open_datadir_folder()
#endif
}
void desktop_open_any_folder( const std::string path )
{
// Execute command to open a file explorer, platform dependent.
// FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade.
#ifdef _WIN32
const wxString widepath = from_u8(path);
const wchar_t *argv[] = {L"explorer", widepath.GetData(), nullptr};
::wxExecute(const_cast<wchar_t **>(argv), wxEXEC_ASYNC, nullptr);
#elif __APPLE__
const char *argv[] = {"open", path.data(), nullptr};
::wxExecute(const_cast<char **>(argv), wxEXEC_ASYNC, nullptr);
#else
const char *argv[] = {"xdg-open", path.data(), nullptr};
// Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars,
// because they may mess up the environment expected by the file manager.
// Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure.
if (wxGetEnv("APPIMAGE", nullptr)) {
// We're running from AppImage
wxEnvVariableHashMap env_vars;
wxGetEnvMap(&env_vars);
env_vars.erase("APPIMAGE");
env_vars.erase("APPDIR");
env_vars.erase("LD_LIBRARY_PATH");
env_vars.erase("LD_PRELOAD");
env_vars.erase("UNION_PRELOAD");
wxExecuteEnv exec_env;
exec_env.env = std::move(env_vars);
wxString owd;
if (wxGetEnv("OWD", &owd)) {
// This is the original work directory from which the AppImage image was run,
// set it as CWD for the child process:
exec_env.cwd = std::move(owd);
}
::wxExecute(const_cast<char **>(argv), wxEXEC_ASYNC, nullptr, &exec_env);
} else {
// Looks like we're NOT running from AppImage, we'll make no changes to the environment.
::wxExecute(const_cast<char **>(argv), wxEXEC_ASYNC, nullptr, nullptr);
}
#endif
}
} }

View file

@ -82,7 +82,8 @@ extern void about();
extern void login();
// Ask the destop to open the datadir using the default file explorer.
extern void desktop_open_datadir_folder();
// Ask the destop to open one folder
extern void desktop_open_any_folder(const std::string path);
} // namespace GUI
} // namespace Slic3r

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/Utils/NetworkAgent.hpp"
#include "slic3r/GUI/WebViewDialog.hpp"
#include "slic3r/GUI/Jobs/UpgradeNetworkJob.hpp"
#include <wx/app.h>
#include <wx/colour.h>
@ -22,7 +23,8 @@
#include <mutex>
#include <stack>
#define BBL_HAS_FIRST_PAGE 1
#define BBL_HAS_FIRST_PAGE 1
#define STUDIO_INACTIVE_TIMEOUT 15*60*1000
class wxMenuItem;
class wxMenuBar;
@ -104,6 +106,7 @@ enum CameraMenuIDs {
wxID_CAMERA_COUNT,
};
class Tab;
class ConfigWizard;
@ -186,6 +189,7 @@ public:
class GUI_App : public wxApp
{
public:
//BBS: remove GCodeViewer as seperate APP logic
enum class EAppMode : unsigned char
{
@ -241,9 +245,13 @@ private:
//BBS
bool m_is_closing {false};
Slic3r::DeviceManager* m_device_manager;
Slic3r::DeviceManager* m_device_manager { nullptr };
NetworkAgent* m_agent { nullptr };
std::vector<std::string> need_delete_presets; // store setting ids of preset
bool m_networking_compatible { false };
bool m_networking_need_update { false };
bool m_networking_cancel_update { false };
std::shared_ptr<UpgradeNetworkJob> m_upgrade_network_job;
VersionInfo version_info;
@ -335,7 +343,7 @@ public:
void load_gcode(wxWindow* parent, wxString& input_file) const;
void ShowUserGuide();
void ShowDailyTip();
void ShowDownNetPluginDlg();
void ShowUserLogin();
void ShowOnlyFilament();
//BBS
@ -358,11 +366,18 @@ public:
void on_http_error(wxCommandEvent &evt);
void on_user_login(wxCommandEvent &evt);
// BBS
bool is_studio_active();
void reset_to_active();
bool m_studio_active = true;
std::chrono::system_clock::time_point last_active_point;
void check_update(bool show_tips);
void check_new_version(bool show_tips = false);
void request_new_version();
void enter_force_upgrade();
void no_new_version();
void show_dialog(wxString msg);
void reload_settings();
void remove_user_presets();
void sync_preset(Preset* preset);
@ -484,12 +499,23 @@ public:
void associate_files(std::wstring extend);
void disassociate_files(std::wstring extend);
#endif // __WXMSW__
std::string get_plugin_url(std::string country_code);
int download_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr);
int install_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr);
std::string get_http_url(std::string country_code);
bool is_compatibility_version();
bool check_networking_version();
void cancel_networking_install();
void restart_networking();
private:
int updating_bambu_networking();
bool on_init_inner();
bool on_init_network();
void init_networking_callbacks();
void init_app_config();
//BBS set extra header for http request
std::map<std::string, std::string> get_extra_header();
void init_http_extra_header();
bool check_older_app_config(Semver current_version, bool backup);
void copy_older_config();

View file

@ -464,7 +464,8 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty
auto item = L("Timelapse Wipe Tower");
type = ModelVolumeType::TIMELAPSE_WIPE_TOWER;
append_menu_item(sub_menu, wxID_ANY, _(item), "",
[type, item](wxCommandEvent&) { obj_list()->load_generic_subobject(item, type); }, "", menu);
[type, item](wxCommandEvent &) { obj_list()->load_generic_subobject(item, type); }, "", menu,
[]() { return plater()->can_add_timelapse_wt(); }, m_parent);
}
return sub_menu;

View file

@ -264,6 +264,8 @@ ObjectList::ObjectList(wxWindow* parent) :
// which seems to be working as of now.
this->CallAfter([this](){ ensure_current_item_visible(); });
#else
update_name_column_width();
ensure_current_item_visible();
#endif
e.Skip();
@ -768,17 +770,21 @@ void ObjectList::update_filament_colors()
void ObjectList::update_name_column_width() const
{
auto em = em_unit(const_cast<ObjectList*>(this));
int extra_width = 0;
wxSize client_size = this->GetClientSize();
bool p_vbar = this->GetParent()->HasScrollbar(wxVERTICAL);
bool p_hbar = this->GetParent()->HasScrollbar(wxHORIZONTAL);
auto em = em_unit(const_cast<ObjectList*>(this));
// BBS: walkaround for wxDataViewCtrl::HasScrollbar() does not return correct status
int others_width = 0;
for (int cn = colName; cn < colCount; cn++) {
if (cn != colName) {
if (GetColumn(cn)->IsHidden())
extra_width += m_columns_width[cn];
if (!GetColumn(cn)->IsHidden())
others_width += m_columns_width[cn];
}
}
GetColumn(colName)->SetWidth((m_columns_width[colName] + extra_width) * em);
GetColumn(colName)->SetWidth(client_size.x - (others_width)*em);
}
void ObjectList::set_filament_column_hidden(const bool hide) const
@ -1145,6 +1151,8 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me
GLGizmosManager& gizmos_mgr = wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager();
if (gizmos_mgr.get_current_type() != GLGizmosManager::EType::FdmSupports)
gizmos_mgr.open_gizmo(GLGizmosManager::EType::FdmSupports);
else
gizmos_mgr.reset_all_states();
}
}
else if (col_num == colColorPaint) {
@ -1153,6 +1161,8 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me
GLGizmosManager& gizmos_mgr = wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager();
if (gizmos_mgr.get_current_type() != GLGizmosManager::EType::MmuSegmentation)
gizmos_mgr.open_gizmo(GLGizmosManager::EType::MmuSegmentation);
else
gizmos_mgr.reset_all_states();
}
}
else if (col_num == colEditing) {
@ -2028,13 +2038,16 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name
new_object->translate(-bb.center());
if (is_timelapse_wt) {
new_object->instances[0]->set_offset( Vec3d(80.0, 230.0, -new_object->origin_translation.z()) );
new_object->is_timelapse_wipe_tower = true;
auto curr_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate();
int highest_extruder = 0;
double max_height = curr_plate->estimate_timelapse_wipe_tower_height(&highest_extruder);
new_object->scale(1, 1, max_height / new_object->bounding_box().size()[2]);
// move to garbage bin of curr plate
auto offset = curr_plate->get_origin() + Vec3d(80.0, 230.0, -new_object->origin_translation.z());
new_object->instances[0]->set_offset(offset);
new_object->config.set_key_value("sparse_infill_density", new ConfigOptionPercent(0));
new_object->config.set_key_value("top_shell_layers", new ConfigOptionInt(0));
new_object->config.set("extruder", highest_extruder);
@ -2237,14 +2250,15 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
// update extruder color in ObjectList
wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx);
// BBS
#if 0
if (obj_item) {
// BBS
if (last_volume->config.has("extruder")) {
int extruder_id = last_volume->config.opt_int("extruder");
object->config.set("extruder", extruder_id);
}
wxString extruder = object->config.has("extruder") ? wxString::Format("%d", object->config.extruder()) : _devL("1");
m_objects_model->SetExtruder(extruder, obj_item);
}
#endif
// add settings to the object, if it has them
add_settings_item(obj_item, &object->config.get());
}

View file

@ -246,7 +246,7 @@ void GLGizmoBase::GizmoImguiEnd()
m_imgui->end();
}
void GLGizmoBase::GizmoImguiSetNextWIndowPos(float x, float y, int flag, float pivot_x, float pivot_y)
void GLGizmoBase::GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x, float pivot_y)
{
if (abs(last_input_window_width) > 0.01f) {
if (x + last_input_window_width > m_parent.get_canvas_size().get_width()) {

View file

@ -206,7 +206,7 @@ protected:
bool GizmoImguiBegin(const std::string& name, int flags);
void GizmoImguiEnd();
void GizmoImguiSetNextWIndowPos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
void GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
// Returns the picking color for the given id, based on the BASE_ID constant
// No check is made for clashing with other picking color (i.e. GLVolumes)
std::array<float, 4> picking_color_component(unsigned int id) const;

View file

@ -88,7 +88,7 @@ bool GLGizmoFdmSupports::on_init()
m_desc["remove"] = _L("Erase painting");
m_desc["remove_all"] = _L("Erase all painting");
m_desc["highlight_by_angle"] = _L("Highlight overhang areas") + ": ";
m_desc["fragment_filter"] = _L("Fragment filter");
m_desc["fragment_filter"] = _L("Gap fill");
m_desc["perform_filter"] = _L("Perform");
m_desc["fragment_area"] = _L("Fragment area");
m_desc["brush_size"] = _L("Set pen size");
@ -246,7 +246,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("tool_type"));
std::array<wchar_t, 4> tool_icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::FillButtonIcon, ImGui::FragmentFilterIcon };
std::array<wxString, 4> tool_tips = { _L("Circle"), _L("Sphere"), _L("Fill"), _L("Fragment Filter") };
std::array<wxString, 4> tool_tips = { _L("Circle"), _L("Sphere"), _L("Fill"), _L("Gap Fill") };
for (int i = 0; i < tool_icons.size(); i++) {
std::string str_label = std::string("##");
std::wstring btn_name = tool_icons[i] + boost::nowide::widen(str_label);

View file

@ -337,12 +337,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float clipping_slider_left = m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f);
const float clipping_slider_left = m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.f);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f);
const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f);
const float fragment_area_slider_left = m_imgui->calc_text_size(m_desc.at("fragment_area")).x + m_imgui->scaled(1.f);
const float height_range_slider_left = m_imgui->calc_text_size(m_desc.at("height_range")).x + m_imgui->scaled(1.f);
const float fragment_area_slider_left = m_imgui->calc_text_size(m_desc.at("fragment_area")).x + m_imgui->scaled(1.5f);
const float height_range_slider_left = m_imgui->calc_text_size(m_desc.at("height_range")).x + m_imgui->scaled(1.5f);
const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform_filter")).x + m_imgui->scaled(1.f);
@ -359,6 +359,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
total_text_max += caption_max + m_imgui->scaled(1.f);
caption_max += m_imgui->scaled(1.f);
const float circle_max_width = std::max(clipping_slider_left,cursor_slider_left);
const float height_max_width = std::max(clipping_slider_left,height_range_slider_left);
const float sliders_left_width = std::max(smart_fill_slider_left,
std::max(cursor_slider_left, std::max(edge_detect_slider_left, std::max(fragment_area_slider_left, std::max(height_range_slider_left,
clipping_slider_left)))));
@ -404,7 +406,15 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
// draw filament background
ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
if (m_selected_extruder_idx != extruder_idx) flags |= ImGuiColorEditFlags_NoBorder;
bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size);
#ifdef __APPLE__
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.4f, 0.4f, 0.4f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size);
ImGui::PopStyleVar(1);
ImGui::PopStyleColor(1);
#else
bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size);
#endif
color_button_high = ImGui::GetCursorPos().y - color_button - 2.0;
if (color_picked) { m_selected_extruder_idx = extruder_idx; }
@ -425,7 +435,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->text(m_desc.at("tool_type"));
std::array<wchar_t, 6> tool_icons = { ImGui::CircleButtonIcon,ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::FragmentFilterIcon };
std::array<wxString, 6> tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Fragment Filter") };
std::array<wxString, 6> tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill") };
for (int i = 0; i < tool_icons.size(); i++) {
std::string str_label = std::string("##");
std::wstring btn_name = tool_icons[i] + boost::nowide::widen(str_label);
@ -460,33 +470,54 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
if (m_current_tool != old_tool)
this->tool_changed(old_tool, m_current_tool);
if (m_current_tool == ImGui::CircleButtonIcon) {
m_cursor_type = TriangleSelector::CursorType::CIRCLE;
if (m_current_tool == ImGui::CircleButtonIcon || m_current_tool == ImGui::SphereButtonIcon) {
if (m_current_tool == ImGui::CircleButtonIcon)
m_cursor_type = TriangleSelector::CursorType::CIRCLE;
else
m_cursor_type = TriangleSelector::CursorType::SPHERE;
m_tool_type = ToolType::BRUSH;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width);
ImGui::SameLine(circle_max_width);
ImGui::PushItemWidth(window_width - circle_max_width - slider_width_times * slider_icon_width);
m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f");
} else if (m_current_tool == ImGui::SphereButtonIcon){
m_cursor_type = TriangleSelector::CursorType::SPHERE;
m_tool_type = ToolType::BRUSH;
ImGui::Separator();
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width);
m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true);
m_imgui->text(m_desc.at("clipping_of_view"));
auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(circle_max_width);
ImGui::PushItemWidth(window_width - circle_max_width - slider_width_times * slider_icon_width);
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f");
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
} else if (m_current_tool == ImGui::TriangleButtonIcon) {
m_cursor_type = TriangleSelector::CursorType::POINTER;
m_tool_type = ToolType::BRUSH;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("clipping_of_view"));
auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left - slider_width_times * slider_icon_width);
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
} else if (m_current_tool == ImGui::FillButtonIcon) {
m_cursor_type = TriangleSelector::CursorType::POINTER;
m_imgui->bbl_checkbox(m_desc["edge_detection"], m_detect_geometry_edge);
@ -511,34 +542,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
// set to negative value to disable edge detection
m_smart_fill_angle = -1.f;
}
} else if (m_current_tool == ImGui::HeightRangeIcon) {
m_tool_type = ToolType::BRUSH;
m_cursor_type = TriangleSelector::CursorType::HEIGHT_RANGE;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["height_range"] + ":");
ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width);
std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Heigh range," "Facet in [cursor z, cursor z + height] will be selected.");
m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f");
}
else if (m_current_tool == ImGui::FragmentFilterIcon) {
m_tool_type = ToolType::FRAGMENT_FILTER;
m_cursor_type = TriangleSelector::CursorType::POINTER;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["fragment_area"] + ":");
ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width);
std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold");
m_imgui->bbl_slider_float_style("##fragment_area", &TriangleSelectorPatch::fragment_area, TriangleSelectorPatch::FragmentAreaMin, TriangleSelectorPatch::FragmentAreaMax, format_str.data(), 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
ImGui::BBLDragFloat("##fragment_area_input", &TriangleSelectorPatch::fragment_area, 0.05f, 0.0f, 0.0f, "%.2f");
}
if (m_current_tool != ImGui::FragmentFilterIcon) {
ImGui::Separator();
ImGui::AlignTextToFramePadding();
@ -552,8 +555,49 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::PushItemWidth(1.5 * slider_icon_width);
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true);}
} else if (m_current_tool == ImGui::HeightRangeIcon) {
m_tool_type = ToolType::BRUSH;
m_cursor_type = TriangleSelector::CursorType::HEIGHT_RANGE;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["height_range"] + ":");
ImGui::SameLine(height_max_width);
ImGui::PushItemWidth(window_width - height_max_width - slider_width_times * slider_icon_width);
std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Heigh range," "Facet in [cursor z, cursor z + height] will be selected.");
m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f");
ImGui::Separator();
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("clipping_of_view"));
auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(height_max_width);
ImGui::PushItemWidth(window_width - height_max_width - slider_width_times * slider_icon_width);
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
}
else if (m_current_tool == ImGui::FragmentFilterIcon) {
m_tool_type = ToolType::FRAGMENT_FILTER;
m_cursor_type = TriangleSelector::CursorType::POINTER;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["fragment_area"] + ":");
ImGui::SameLine(fragment_area_slider_left);
ImGui::PushItemWidth(window_width - fragment_area_slider_left - slider_width_times * slider_icon_width);
std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold");
m_imgui->bbl_slider_float_style("##fragment_area", &TriangleSelectorPatch::fragment_area, TriangleSelectorPatch::FragmentAreaMin, TriangleSelectorPatch::FragmentAreaMax, format_str.data(), 1.0f, true);
ImGui::SameLine(window_width - slider_icon_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
ImGui::BBLDragFloat("##fragment_area_input", &TriangleSelectorPatch::fragment_area, 0.05f, 0.0f, 0.0f, "%.2f");
}
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));

View file

@ -85,7 +85,7 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
//if ((border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= border + icons_size))) {
if (((top_y + border) <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= (top_y + border + icons_size))) {
// which icon is it on?
size_t from_left = (size_t)((float)mouse_pos(0) - top_x) / stride_x;
int from_left = (float) mouse_pos(0) - top_x < 0 ? -1 : (int) ((float) mouse_pos(0) - top_x) / stride_x;
if (from_left < 0)
return Undefined;
// is it really on the icon or already past the border?

View file

@ -18,6 +18,9 @@
#include <boost/algorithm/string.hpp>
#define MAX_NUM 9999.99
#define MAX_SIZE "9999.99"
namespace Slic3r
{
namespace GUI
@ -25,6 +28,8 @@ namespace GUI
const double GizmoObjectManipulation::in_to_mm = 25.4;
const double GizmoObjectManipulation::mm_to_in = 0.0393700787;
const double GizmoObjectManipulation::oz_to_g = 28.34952;
const double GizmoObjectManipulation::g_to_oz = 0.035274;
// Helper function to be used by drop to bed button. Returns lowest point of this
// volume in world coordinate system.
@ -576,9 +581,10 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
else
original_position = this->m_new_position;
Vec3d display_position = m_buffered_position;
// Rotation
Vec3d rotation = this->m_buffered_rotation;
float unit_size = max_unit_size(2, display_position, display_position, "move") + space_size;;
float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size;
int index = 1;
int index_unit = 1;
@ -611,6 +617,12 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
ImGui::BBLInputDouble(label_values[0][2], &display_position[2], 0.0f, 0.0f, "%.2f");
ImGui::SameLine(caption_max + (++index_unit) * unit_size + (++index) * space_size);
imgui_wrapper->text(this->m_new_unit_string);
for (int i = 0;i<display_position.size();i++)
{
if (display_position[i] > MAX_NUM)display_position[i] = MAX_NUM;
}
m_buffered_position = display_position;
update(current_active_id, "position", original_position, m_buffered_position);
// the init position values are not zero, won't add reset button
@ -671,7 +683,7 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
};
float space_size = imgui_wrapper->get_style_scaling() * 8;
float position_size = imgui_wrapper->calc_text_size(_L("Position")).x + space_size;
float position_size = imgui_wrapper->calc_text_size(_L("Rotation")).x + space_size;
float World_size = imgui_wrapper->calc_text_size(_L("World coordinates")).x + space_size;
float caption_max = std::max(position_size, World_size) + 2 * space_size;
float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x;
@ -685,7 +697,8 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
Vec3d display_position = m_buffered_position;
// Rotation
Vec3d rotation = this->m_buffered_rotation;
float unit_size = max_unit_size(2, rotation, rotation, "rotate") + space_size * 2;
float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size;
int index = 1;
int index_unit = 1;
@ -792,7 +805,9 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
};
float space_size = imgui_wrapper->get_style_scaling() * 8;
float caption_max = imgui_wrapper->calc_text_size(_L("Position:")).x + space_size;
float scale_size = imgui_wrapper->calc_text_size(_L("Scale")).x + space_size;
float size_len = imgui_wrapper->calc_text_size(_L("Size")).x + space_size;
float caption_max = std::max(scale_size, size_len) + 2 * space_size;
float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x;
ImGui::AlignTextToFramePadding();
unsigned int current_active_id = ImGui::GetActiveID();
@ -802,12 +817,12 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
Vec3d display_position = m_buffered_position;
float unit_size = max_unit_size(2, scale, display_size, "scale") + space_size;
float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size;
bool imperial_units = this->m_imperial_units;
int index = 2;
int index_unit = 1;
ImGui::PushItemWidth(caption_max);
ImGui::Dummy(ImVec2(caption_max, -1));
//imgui_wrapper->text(_L(" "));
@ -839,8 +854,6 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
ImGui::BBLInputDouble(label_scale_values[0][2], &scale[2], 0.0f, 0.0f, "%.2f");
ImGui::SameLine(caption_max + (++index_unit) *unit_size + (++index) * space_size);
imgui_wrapper->text(_L("%"));
m_buffered_scale = scale;
if (m_show_clear_scale) {
ImGui::SameLine(caption_max + 3 * unit_size + 4 * space_size + end_text_size);
@ -851,7 +864,6 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
ImGui::InvisibleButton("", ImVec2(ImGui::GetFontSize(), ImGui::GetFontSize()));
}
//Size
Vec3d original_size;
if (this->m_imperial_units)
@ -875,6 +887,12 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
ImGui::BBLInputDouble(label_scale_values[1][2], &display_size[2], 0.0f, 0.0f, "%.2f");
ImGui::SameLine(caption_max + (++index_unit) *unit_size + (++index) * space_size);
imgui_wrapper->text(this->m_new_unit_string);
for (int i = 0;i<display_size.size();i++)
{
if (display_size[i] > MAX_NUM || scale[i]> MAX_NUM)display_size[i] = MAX_NUM;
}
m_buffered_scale = scale;
m_buffered_size = display_size;
int size_sel = update(current_active_id, "size", original_size, m_buffered_size);
ImGui::PopStyleVar(1);

View file

@ -19,6 +19,8 @@ class GizmoObjectManipulation
public:
static const double in_to_mm;
static const double mm_to_in;
static const double g_to_oz;
static const double oz_to_g;
struct Cache
{

View file

@ -451,6 +451,8 @@ bool IMSlider::init_texture()
result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off.svg", 28, 28, m_one_layer_off_id);
result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off_hover.svg", 28, 28, m_one_layer_off_hover_id);
result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_arrow.svg", 28, 28, m_one_layer_arrow_id);
result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/im_gcode_pause.svg", 14, 14, m_pause_icon_id);
result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/im_slider_delete.svg", 14, 14, m_delete_icon_id);
}
return result;
@ -859,11 +861,13 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) {
if (m_ticks.empty())
return;
ImGuiContext &context = *GImGui;
ImVec2 tick_box = ImVec2(46.0f, 16.0f) * m_scale;
ImVec2 tick_offset = ImVec2(19.0f, 11.0f) * m_scale;
float tick_width = 1.0f * m_scale;
ImVec2 icon_offset = ImVec2(13.0f, 7.0f) * m_scale;
ImVec2 icon_size = ImVec2(16.0f, 16.0f) * m_scale;
ImVec2 icon_size = ImVec2(14.0f, 14.0f) * m_scale;
const ImU32 tick_clr = IM_COL32(144, 144, 144, 255);
const ImU32 tick_hover_box_clr = IM_COL32(219, 253, 231, 255);
@ -876,12 +880,10 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) {
return get_pos_from_value(v_min, v_max, tick, slideable_region);
};
float tick_pos;
std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin();
while (tick_it != m_ticks.ticks.end())
{
tick_pos = get_tick_pos(tick_it->tick);
float tick_pos = get_tick_pos(tick_it->tick);
//draw tick hover box when hovered
ImRect tick_hover_box = ImRect(slideable_region.GetCenter().x - tick_box.x / 2, tick_pos - tick_box.y / 2, slideable_region.GetCenter().x + tick_box.x / 2,
@ -890,8 +892,10 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) {
if (ImGui::IsMouseHoveringRect(tick_hover_box.Min, tick_hover_box.Max))
{
ImGui::RenderFrame(tick_hover_box.Min, tick_hover_box.Max, tick_hover_box_clr, false);
m_tick_value = tick_it->tick;
m_tick_rect = ImVec4(tick_hover_box.Min.x, tick_hover_box.Min.y, tick_hover_box.Max.x, tick_hover_box.Max.y);
if (context.IO.MouseClicked[0]) {
m_tick_value = tick_it->tick;
m_tick_rect = ImVec4(tick_hover_box.Min.x, tick_hover_box.Min.y, tick_hover_box.Max.x, tick_hover_box.Max.y);
}
}
++tick_it;
}
@ -899,7 +903,7 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) {
tick_it = m_ticks.ticks.begin();
while (tick_it != m_ticks.ticks.end())
{
tick_pos = get_tick_pos(tick_it->tick);
float tick_pos = get_tick_pos(tick_it->tick);
//draw ticks
ImRect tick_left = ImRect(slideable_region.GetCenter().x - tick_offset.x, tick_pos - tick_width, slideable_region.GetCenter().x - tick_offset.y, tick_pos);
@ -908,17 +912,36 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) {
ImGui::RenderFrame(tick_right.Min, tick_right.Max, tick_clr, false);
//draw pause icon
ImGui::PushID(tick_it->tick);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
if (tick_it->type == PausePrint) {
std::wstring pause_icon_name = ImGui::GcodePauseIcon + boost::nowide::widen(std::string(""));
button_with_pos(into_u8(pause_icon_name).c_str(), icon_size, ImVec2(slideable_region.GetCenter().x + icon_offset.x, tick_pos - icon_offset.y));
ImTextureID pause_icon_id = m_pause_icon_id;
ImVec2 icon_pos = ImVec2(slideable_region.GetCenter().x + icon_offset.x, tick_pos - icon_offset.y);
button_with_pos(pause_icon_id, icon_size, icon_pos);
if (ImGui::IsMouseHoveringRect(icon_pos, icon_pos + icon_size)) {
if(context.IO.MouseClicked[0])
int a = 0;
}
}
ImGui::PopStyleColor(1);
ImGui::PopID();
++tick_it;
}
tick_it = GetSelection() == ssHigher ? m_ticks.ticks.find(TickCode{this->GetHigherValue()}) :
GetSelection() == ssLower ? m_ticks.ticks.find(TickCode{this->GetLowerValue()}) :
m_ticks.ticks.end();
if (tick_it != m_ticks.ticks.end()) {
// draw delete icon
ImTextureID delete_icon_id = m_delete_icon_id;
ImVec2 icon_pos = ImVec2(slideable_region.GetCenter().x + icon_offset.x, get_tick_pos(tick_it->tick) - icon_offset.y);
button_with_pos(m_delete_icon_id, icon_size, icon_pos);
if (ImGui::IsMouseHoveringRect(icon_pos, icon_pos + icon_size)) {
if (context.IO.MouseClicked[0]) {
// delete tick
Type type = tick_it->type;
m_ticks.ticks.erase(tick_it);
post_ticks_changed_event(type);
}
}
}
}
bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower_value, std::string& higher_label, std::string& lower_label,int v_min, int v_max, const ImVec2& pos,const ImVec2& size, SelectedSlider& selection, bool one_layer_flag, float scale)
@ -989,8 +1012,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
ImRect one_handle = ImRect(higher_handle.Min - ImVec2(one_handle_offset, 0), higher_handle.Max - ImVec2(one_handle_offset, 0));
static bool become_del_handle = false;
static bool pressed_in_del = false;
//static bool become_del_handle = false;
bool value_changed = false;
if (!one_layer_flag)
{
@ -999,14 +1021,10 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
if (ImGui::ItemHoverable(higher_handle, id) && context.IO.MouseClicked[0]) {
selection = ssHigher;
h_selected = true;
m_tick_value = -1;
m_tick_rect = ImVec4();
}
if (ImGui::ItemHoverable(lower_handle, id) && context.IO.MouseClicked[0]) {
selection = ssLower;
h_selected = false;
m_tick_value = -1;
m_tick_rect = ImVec4();
}
// update handle position and value
@ -1015,31 +1033,11 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
value_changed = slider_behavior(id, higher_slideable_region, v_min, v_max,
higher_value, &higher_handle, ImGuiSliderFlags_Vertical,
m_tick_value, m_tick_rect);
auto it = m_ticks.ticks.find(TickCode{ *higher_value });
if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type))
{
become_del_handle = true;
}
else {
become_del_handle = false;
pressed_in_del = false;
}
}
if (!h_selected) {
value_changed = slider_behavior(id, lower_slideable_region, v_min, v_max,
lower_value, &lower_handle, ImGuiSliderFlags_Vertical,
m_tick_value, m_tick_rect);
auto it = m_ticks.ticks.find(TickCode{ *lower_value });
if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type))
{
become_del_handle = true;
}
else {
become_del_handle = false;
pressed_in_del = false;
}
}
ImVec2 higher_handle_center = higher_handle.GetCenter();
@ -1095,37 +1093,6 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
window->DrawList->AddLine(lower_handle_center + ImVec2(0.0f, -line_offset), lower_handle_center + ImVec2(0.0f, line_offset), white_bg, line_width);
}
if (become_del_handle) {
if (context.IO.MouseDown[0] &&
(ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id)))
{
pressed_in_del = true;
}
if (pressed_in_del && context.IO.MouseReleased[0] && ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id)) {
pressed_in_del = false;
//delete tick
auto it = m_ticks.ticks.find(TickCode{ h_selected ? *higher_value : *lower_value });
if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type))
{
Type type = it->type;
m_ticks.ticks.erase(it);
post_ticks_changed_event(type);
m_tick_value = -1;
m_tick_rect = ImVec4();
}
}
if (h_selected) {
window->DrawList->AddCircleFilled(higher_handle_center, handle_radius - handle_border, delete_btn_clr);
window->DrawList->AddLine(higher_handle_center + ImVec2(-line_offset, 0.0f), higher_handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width);
}
if (!h_selected) {
window->DrawList->AddCircleFilled(lower_handle_center, handle_radius - handle_border, delete_btn_clr);
window->DrawList->AddLine(lower_handle_center + ImVec2(-line_offset, 0.0f), lower_handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width);
}
}
// draw higher label
auto text_utf8 = into_u8(higher_label);
text_content_size = ImGui::CalcTextSize(text_utf8.c_str());
@ -1157,15 +1124,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
value_changed = slider_behavior(id, one_slideable_region, v_min, v_max,
higher_value, &one_handle, ImGuiSliderFlags_Vertical,
m_tick_value, m_tick_rect);
auto it = m_ticks.ticks.find(TickCode{ *higher_value });
if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type))
{
become_del_handle = true;
}
else {
become_del_handle = false;
pressed_in_del;
}
ImVec2 handle_center = one_handle.GetCenter();
// judge whether to open menu
@ -1190,28 +1149,6 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
window->DrawList->AddCircleFilled(handle_center, handle_radius - handle_border, handle_clr);
window->DrawList->AddLine(handle_center + ImVec2(-line_offset, 0.0f), handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width);
window->DrawList->AddLine(handle_center + ImVec2(0.0f, -line_offset), handle_center + ImVec2(0.0f, line_offset), white_bg, line_width);
if (become_del_handle) {
if (context.IO.MouseDown[0] &&
(ImGui::ItemHoverable(one_handle, id)))
{
pressed_in_del = true;
}
if (pressed_in_del && context.IO.MouseReleased[0] && ImGui::ItemHoverable(one_handle, id)) {
pressed_in_del = false;
//delete tick
auto it = m_ticks.ticks.find(TickCode{ *higher_value });
if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type))
{
Type type = it->type;
m_ticks.ticks.erase(it);
post_ticks_changed_event(type);
m_tick_value = -1;
m_tick_rect = ImVec4();
}
}
window->DrawList->AddCircleFilled(handle_center, handle_radius - handle_border, delete_btn_clr);
window->DrawList->AddLine(handle_center + ImVec2(-line_offset, 0.0f), handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width);
}
// draw label
auto text_utf8 = into_u8(higher_label);
@ -1222,6 +1159,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
ImGui::RenderFrame(text_rect.Min, text_rect.Max, white_bg, false, rounding);
ImGui::RenderText(text_start + text_padding, higher_label.c_str());
}
return value_changed;
}
@ -1294,6 +1232,7 @@ bool IMSlider::render(int canvas_width, int canvas_height)
ImGui::PopStyleVar(3);
ImGui::PopStyleColor(2);
return result;
}

View file

@ -343,6 +343,8 @@ private:
void *m_one_layer_arrow_id;
void *m_one_layer_off_id;
void *m_one_layer_off_hover_id;
void *m_pause_icon_id;
void *m_delete_icon_id;
DrawMode m_draw_mode = dmRegular;
Mode m_mode = SingleExtruder;

View file

@ -64,8 +64,7 @@ static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::FragmentFilterIcon , "fragment_filter" },
{ImGui::FoldButtonIcon , "im_fold" },
{ImGui::UnfoldButtonIcon , "im_unfold" },
{ImGui::GcodePauseIcon , "im_gcode_pause" },
{ImGui::SphereButtonIcon , "toolbar_modifier_sphere" },
{ImGui::SphereButtonIcon , "toolbar_modifier_sphere" },
};
static const std::map<const wchar_t, std::string> font_icons_large = {
@ -257,30 +256,37 @@ bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const
return value_changed;
}
bool button_with_pos(const char* label, const ImVec2& size, const ImVec2& pos, ImGuiButtonFlags flags/* = 0*/) {
bool button_with_pos(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &pos, const ImVec2 &uv0, const ImVec2 &uv1, int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col, const ImVec2 &margin)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext &g = *GImGui;
ImGuiWindow * window = g.CurrentWindow;
if (window->SkipItems) return false;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
// Default to using texture ID as ID. User can still push string/integer prefixes.
ImGui::PushID((void *) (intptr_t) user_texture_id);
const ImGuiID id = window->GetID("#image");
ImGui::PopID();
const ImRect bb(pos, pos + size);
const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float) frame_padding, (float) frame_padding) : g.Style.FramePadding;
const ImRect bb(pos, pos + size + padding * 2 + margin * 2);
bool hovered, held;
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags);
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held);
// Render
const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
ImGui::RenderNavHighlight(bb, id);
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
if (g.LogEnabled)
ImGui::LogSetNextTextDecoration("[", "]");
ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
const float border_size = g.Style.FrameBorderSize;
if (border_size > 0.0f) {
window->DrawList->AddRect(bb.Min + ImVec2(1, 1), bb.Max + ImVec2(1, 1), col, g.Style.FrameRounding, 0, border_size);
window->DrawList->AddRect(bb.Min, bb.Max, col, g.Style.FrameRounding, 0, border_size);
}
if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, ImGui::GetColorU32(bg_col));
window->DrawList->AddImage(user_texture_id, bb.Min + padding + margin, bb.Max - padding - margin, uv0, uv1, ImGui::GetColorU32(tint_col));
return pressed;
}

View file

@ -28,7 +28,15 @@ namespace GUI {
bool get_data_from_svg(const std::string &filename, unsigned int max_size_px, ThumbnailData &thumbnail_data);
bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const ImS32 v_max, ImS32* out_value, ImRect* out_handle, ImGuiSliderFlags flags = 0, const int fixed_value = -1, const ImVec4& fixed_rect = ImVec4());
bool button_with_pos(const char* label, const ImVec2& size, const ImVec2& pos, ImGuiButtonFlags flags = 0);
bool button_with_pos(ImTextureID user_texture_id,
const ImVec2 &size,
const ImVec2 &pos,
const ImVec2 &uv0 = ImVec2(0, 0),
const ImVec2 &uv1 = ImVec2(1, 1),
int frame_padding = -1,
const ImVec4 &bg_col = ImVec4(0, 0, 0, 0),
const ImVec4 &tint_col = ImVec4(1, 1, 1, 1),
const ImVec2 &margin = ImVec2(0, 0));
bool menu_item_with_icon(const char* label, const char* shortcut, ImU32 icon_color, bool selected, bool enabled = true);

View file

@ -99,9 +99,11 @@ void BindJob::process()
} else if (stage == BBL::BindJobStage::LoginStageFinished) {
curr_percent = 100;
msg = _L("Logging in");
} else {
msg = _L("Logging in");
}
if (code != 0) {
msg = login_failed_str + wxString::Format("(code=%d,info=%s)", code, info);
msg = _L("Login failed") + wxString::Format("(code=%d,info=%s)", code, info);
}
update_status(curr_percent, msg);
}

View file

@ -51,6 +51,49 @@ void PrintJob::on_success(std::function<void()> success)
m_success_fun = success;
}
wxString PrintJob::get_http_error_msg(unsigned int status, std::string body)
{
int code = 0;
std::string error;
std::string message;
wxString result;
if (status >= 400 && status < 500)
try {
json j = json::parse(body);
if (j.contains("code")) {
if (!j["code"].is_null())
code = j["code"].get<int>();
}
if (j.contains("error")) {
if (!j["error"].is_null())
error = j["error"].get<std::string>();
}
if (j.contains("message")) {
if (!j["message"].is_null())
message = j["message"].get<std::string>();
}
switch (status) {
;
}
}
catch (...) {
;
}
else if (status == 503) {
return _L("Service Unavailable");
}
else {
wxString unkown_text = _L("Unkown Error.");
unkown_text += wxString::Format("status=%u, body=%s", status, body);
return unkown_text;
}
BOOST_LOG_TRIVIAL(error) << "http_error: status=" << status << ", code=" << code << ", error=" << error;
result = wxString::Format("code=%u, error=%s", code, from_u8(error));
return result;
}
void PrintJob::process()
{
/* display info */
@ -114,8 +157,10 @@ void PrintJob::process()
params.dev_ip = m_dev_ip;
params.username = "bblp";
params.password = m_access_code;
wxString error_text;
wxString msg_text;
auto update_fn = [this, &msg, &curr_percent](int stage, int code, std::string info) {
auto update_fn = [this, &msg, &curr_percent, &error_text](int stage, int code, std::string info) {
if (stage == BBL::SendingPrintJobStage::PrintingStageCreate) {
if (this->connection_type == "lan") {
msg = _L("Sending print job over LAN");
@ -157,7 +202,7 @@ void PrintJob::process()
}
else if (stage == BBL::SendingPrintJobStage::PrintingStageFinished) {
curr_percent = 100;
msg = wxString::Format(_L("Successfully sent.Will automatically jump to the device page in %s s"), info);
msg = wxString::Format(_L("Successfully sent. Will automatically jump to the device page in %s s"), info);
} else {
if (this->connection_type == "lan") {
msg = _L("Sending print job over LAN");
@ -165,6 +210,10 @@ void PrintJob::process()
msg = _L("Sending print job through cloud service");
}
}
if (code != 0) {
error_text = this->get_http_error_msg(code, info);
msg += wxString::Format("[%s]", error_text);
}
this->update_status(curr_percent, msg);
};
@ -193,19 +242,6 @@ void PrintJob::process()
BOOST_LOG_TRIVIAL(info) << "print_job: send with cloud";
this->update_status(curr_percent, _L("Sending print job through cloud service"));
result = m_agent->start_print(params, update_fn, cancel_fn);
if (result < 0) {
if (!params.password.empty() && !params.dev_ip.empty()) {
//try to send with local only
if (this->has_sdcard) {
this->update_status(curr_percent, _L("Sending print job over LAN"));
result = m_agent->start_local_print(params, update_fn, cancel_fn);
} else {
this->update_status(curr_percent, _L("Failed to connect to the cloud server connection. Please insert an SD card and resend the print job, which will transfer the print file via LAN. "));
BOOST_LOG_TRIVIAL(error) << "print_job: failed, need sdcard";
return;
}
}
}
}
} else {
if (this->has_sdcard) {
@ -224,26 +260,29 @@ void PrintJob::process()
if (result < 0) {
if (result == BAMBU_NETWORK_ERR_FTP_LOGIN_DENIED) {
update_status(curr_percent, upload_failed_str);
msg_text = upload_failed_str;
} if (result == BAMBU_NETWORK_ERR_FILE_NOT_EXIST) {
update_status(curr_percent, file_is_not_exists_str);
msg_text = file_is_not_exists_str;
} else if (result == BAMBU_NETWORK_ERR_FILE_OVER_SIZE) {
update_status(curr_percent, file_over_size_str);
msg_text = file_over_size_str;
} else if (result == BAMBU_NETWORK_ERR_CHECK_MD5_FAILED) {
update_status(curr_percent, failed_in_cloud_service_str);
msg_text = failed_in_cloud_service_str;
} else if (result == BAMBU_NETWORK_ERR_INVALID_PARAMS) {
update_status(curr_percent, upload_failed_str);
msg_text = upload_failed_str;
} else if (result == BAMBU_NETWORK_ERR_CANCELED) {
update_status(curr_percent, print_canceled_str);
msg_text = print_canceled_str;
} else if (result == BAMBU_NETWORK_ERR_TIMEOUT) {
update_status(curr_percent, timeout_to_upload_str);
msg_text = timeout_to_upload_str;
} else if (result == BAMBU_NETWORK_ERR_INVALID_RESULT) {
update_status(curr_percent, upload_failed_str);
msg_text = upload_failed_str;
} else if (result == BAMBU_NETWORK_ERR_FTP_UPLOAD_FAILED) {
update_status(curr_percent, upload_failed_str);
msg_text = upload_failed_str;
} else {
update_status(curr_percent, failed_in_cloud_service_str);
}
if (!error_text.IsEmpty())
msg_text += wxString::Format("[%s]", error_text);
update_status(curr_percent, msg_text);
BOOST_LOG_TRIVIAL(error) << "print_job: failed, result = " << result;
} else {
BOOST_LOG_TRIVIAL(error) << "print_job: send ok.";

View file

@ -70,6 +70,7 @@ public:
void set_print_job_finished_event(int event_id) { m_print_job_completed_id = event_id; }
void on_success(std::function<void()> success);
wxString get_http_error_msg(unsigned int status, std::string body);
void process() override;
void finalize() override;
};

View file

@ -0,0 +1,136 @@
#include "UpgradeNetworkJob.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/Utils/Http.hpp"
namespace Slic3r {
namespace GUI {
wxDEFINE_EVENT(EVT_UPGRADE_UPDATE_MESSAGE, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPGRADE_NETWORK_SUCCESS, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPGRADE_NETWORK_FAILED, wxCommandEvent);
UpgradeNetworkJob::UpgradeNetworkJob(std::shared_ptr<ProgressIndicator> pri)
: Job{std::move(pri)}
{
;
}
void UpgradeNetworkJob::on_exception(const std::exception_ptr &eptr)
{
try {
if (eptr)
std::rethrow_exception(eptr);
} catch (std::exception &e) {
UpgradeNetworkJob::on_exception(eptr);
}
}
void UpgradeNetworkJob::on_success(std::function<void()> success)
{
m_success_fun = success;
}
void UpgradeNetworkJob::update_status(int st, const wxString &msg)
{
GUI::Job::update_status(st, msg);
wxCommandEvent event(EVT_UPGRADE_UPDATE_MESSAGE);
event.SetString(msg);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
}
void UpgradeNetworkJob::process()
{
// downloading
int result = 0;
AppConfig* app_config = wxGetApp().app_config;
if (!app_config)
return;
BOOST_LOG_TRIVIAL(info) << "[download_plugin]: enter";
// get temp path
fs::path target_file_path = (fs::temp_directory_path() / "network_plugin.zip");
fs::path tmp_path = target_file_path;
auto path_str = tmp_path.string() + wxString::Format(".%d%s", get_current_pid(), ".tmp").ToStdString();
tmp_path = fs::path(path_str);
auto cancel_fn = [this]() {
return was_canceled();
};
int curr_percent = 0;
result = wxGetApp().download_plugin(
[this, &curr_percent](int state, int percent, bool &cancel) {
if (state == InstallStatusNormal) {
update_status(percent, _L("Downloading"));
} else if (state == InstallStatusDownloadFailed) {
update_status(percent, _L("Download failed"));
} else {
update_status(percent, _L("Downloading"));
}
curr_percent = percent;
}, cancel_fn);
if (was_canceled()) {
update_status(0, _L("Cancelled"));
wxCommandEvent event(wxEVT_CLOSE_WINDOW);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
return;
}
if (result < 0) {
update_status(curr_percent, _L("Download failed"));
wxCommandEvent event(EVT_UPGRADE_NETWORK_FAILED);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
return;
}
result = wxGetApp().install_plugin([this](int state, int percent, bool&cancel) {
if (state == InstallStatusInstallCompleted) {
update_status(percent, _L("Finish"));
} else {
update_status(percent, _L("Installing"));
}
}, cancel_fn);
if (was_canceled()) {
update_status(0, _L("Cancelled"));
wxCommandEvent event(wxEVT_CLOSE_WINDOW);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
return;
}
if (result != 0) {
update_status(curr_percent, _L("Install failed"));
wxCommandEvent event(EVT_UPGRADE_NETWORK_FAILED);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
return;
}
wxCommandEvent event(EVT_UPGRADE_NETWORK_SUCCESS);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
return;
}
void UpgradeNetworkJob::finalize()
{
if (was_canceled()) return;
Job::finalize();
}
void UpgradeNetworkJob::set_event_handle(wxWindow *hanle)
{
m_event_handle = hanle;
}
}} // namespace Slic3r::GUI

View file

@ -0,0 +1,56 @@
#ifndef __UpgradeNetworkJob_HPP__
#define __UpgradeNetworkJob_HPP__
#include <functional>
#include "Job.hpp"
namespace fs = boost::filesystem;
namespace Slic3r {
namespace GUI {
enum PluginInstallStatus {
InstallStatusNormal = 0,
InstallStatusDownloadFailed = 1,
InstallStatusDownloadCompleted = 2,
InstallStatusUnzipFailed = 3,
InstallStatusInstallCompleted = 4,
};
typedef std::function<void(int status, int percent, bool& cancel)> InstallProgressFn;
class UpgradeNetworkJob : public Job
{
wxWindow * m_event_handle{nullptr};
std::function<void()> m_success_fun{nullptr};
bool m_job_finished{ false };
int m_print_job_completed_id = 0;
InstallProgressFn pro_fn { nullptr };
protected:
void on_exception(const std::exception_ptr &) override;
public:
UpgradeNetworkJob(std::shared_ptr<ProgressIndicator> pri);
int status_range() const override
{
return 100;
}
bool is_finished() { return m_job_finished; }
void on_success(std::function<void()> success);
void update_status(int st, const wxString &msg);
void process() override;
void finalize() override;
void set_event_handle(wxWindow* hanle);
};
wxDECLARE_EVENT(EVT_UPGRADE_UPDATE_MESSAGE, wxCommandEvent);
wxDECLARE_EVENT(EVT_UPGRADE_NETWORK_SUCCESS, wxCommandEvent);
wxDECLARE_EVENT(EVT_UPGRADE_NETWORK_FAILED, wxCommandEvent);
}} // namespace Slic3r::GUI
#endif // ARRANGEJOB_HPP

View file

@ -157,7 +157,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
#ifdef __WXOSX__
set_miniaturizable(GetHandle());
#endif
//reset developer_mode to false and user_mode to comAdvanced
wxGetApp().app_config->set_bool("developer_mode", false);
if (wxGetApp().app_config->get("user_mode") == "develop") {
@ -178,17 +178,17 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
// Fonts were created by the DPIFrame constructor for the monitor, on which the window opened.
wxGetApp().update_fonts(this);
#ifdef __WINDOWS__
m_topbar = new BBLTopbar(this);
#else
#ifdef __WINDOWS__
m_topbar = new BBLTopbar(this);
#else
auto panel_topbar = new wxPanel(this, wxID_ANY);
panel_topbar->SetBackgroundColour(wxColour(38, 46, 48));
auto sizer_tobar = new wxBoxSizer(wxVERTICAL);
m_topbar = new BBLTopbar(panel_topbar, this);
m_topbar = new BBLTopbar(this);
sizer_tobar->Add(m_topbar, 0, wxEXPAND);
panel_topbar->SetSizer(sizer_tobar);
panel_topbar->Layout();
#endif
#endif
@ -326,11 +326,11 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
// initialize layout
m_main_sizer = new wxBoxSizer(wxVERTICAL);
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
#ifdef __WINDOWS__
#ifdef __WINDOWS__
sizer->Add(m_topbar, 0, wxEXPAND);
#else
#else
sizer->Add(panel_topbar, 0, wxEXPAND);
#endif // __WINDOWS__
#endif // __WINDOWS__
sizer->Add(m_main_sizer, 1, wxEXPAND);
@ -357,14 +357,10 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
Fit();
const wxSize min_size = wxGetApp().get_min_size(); //wxSize(76*wxGetApp().em_unit(), 49*wxGetApp().em_unit());
#ifdef __APPLE__
// Using SetMinSize() on Mac messes up the window position in some cases
// cf. https://groups.google.com/forum/#!topic/wx-users/yUKPBBfXWO0
SetSize(min_size/*wxSize(760, 490)*/);
#else
SetMinSize(min_size/*wxSize(760, 490)*/);
SetSize(wxSize(FromDIP(1200), FromDIP(800)));
#endif
Layout();
update_title();
@ -747,6 +743,29 @@ void MainFrame::init_tabpanel()
m_tabpanel->Hide();
m_settings_dialog.set_tabpanel(m_tabpanel);
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, [this](wxBookCtrlEvent& e) {
int old_sel = e.GetOldSelection();
int new_sel = e.GetSelection();
if (new_sel == tpMonitor) {
if (!wxGetApp().getAgent()) {
e.Veto();
BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2%, lack of network plugins")%old_sel %new_sel;
if (m_plater) {
wxCommandEvent *evt = new wxCommandEvent(EVT_INSTALL_PLUGIN_HINT);
wxQueueEvent(m_plater, evt);
}
}
}
else if (new_sel == tp3DEditor) {
if (m_plater && (m_plater->only_gcode_mode() || (m_plater->using_exported_file()))) {
e.Veto();
BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2% in preview mode")%old_sel %new_sel;
wxCommandEvent *evt = new wxCommandEvent(EVT_PREVIEW_ONLY_MODE_HINT);
wxQueueEvent(m_plater, evt);
}
}
});
#ifdef __WXMSW__
m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent& e) {
#else
@ -758,12 +777,11 @@ void MainFrame::init_tabpanel()
//wxString page_text = m_tabpanel->GetPageText(sel);
m_last_selected_tab = m_tabpanel->GetSelection();
if (panel == m_plater) {
if (m_with_3dEditor && (sel == tp3DEditor)) {
if (sel == tp3DEditor) {
wxPostEvent(m_plater, SimpleEvent(EVT_GLVIEWTOOLBAR_3D));
m_param_panel->OnActivate();
}
else if ((m_with_3dEditor&&(sel == tpPreview))
|| (!m_with_3dEditor&&(sel == tp3DEditor))){
else if (sel == tpPreview) {
wxPostEvent(m_plater, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW));
m_param_panel->OnActivate();
}
@ -774,7 +792,7 @@ void MainFrame::init_tabpanel()
//monitor
}
if (m_with_3dEditor && (sel == tp3DEditor)) {
if (sel == tp3DEditor) {
m_topbar->EnableUndoRedoItems();
}
else {
@ -1672,10 +1690,13 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(export_menu, wxID_ANY, _L("Export all objects as STL") + dots, _L("Export all objects as STL"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "menu_export_stl", nullptr,
[this](){return can_export_model(); }, this);
// BBS export Gcode
wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _L("Export Sliced File") + dots/* + "\tCtrl+G"*/, _L("Export current Sliced file"),
// BBS export .gcode.3mf
append_menu_item(export_menu, wxID_ANY, _L("Export Sliced File") + dots/* + "\tCtrl+G"*/, _L("Export current Sliced file"),
[this](wxCommandEvent&) { if (m_plater) wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); }, "menu_export_sliced_file", nullptr,
[this](){return can_export_gcode(); }, this);
append_menu_item(export_menu, wxID_ANY, _L("Export G-code") + dots/* + "\tCtrl+G"*/, _L("Export current plate as G-code"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(false); }, "menu_export_gcode", nullptr,
[this]() {return can_export_gcode(); }, this);
append_submenu(fileMenu, export_menu, wxID_ANY, _L("Export"), "");
@ -1788,20 +1809,20 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(editMenu, wxID_ANY, _L("Deselect all") + "\tEsc",
_L("Deselects all objects"), [this](wxCommandEvent&) { m_plater->deselect_all(); },
"", nullptr, [this](){return can_deselect(); }, this);
editMenu->AppendSeparator();
append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Mesh(TODO)"),
_L("Display triangles of models"), [this](wxCommandEvent& evt) {
wxGetApp().app_config->set_bool("show_model_mesh", evt.GetInt() == 1);
}, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_mesh").compare("true") == 0; }, this);
append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Shadow(TODO)"), _L("Display shadow of objects"),
[this](wxCommandEvent& evt) {
wxGetApp().app_config->set_bool("show_model_shadow", evt.GetInt() == 1);
}, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_shadow").compare("true") == 0; }, this);
editMenu->AppendSeparator();
append_menu_check_item(editMenu, wxID_ANY, _L("Show Printable Box(TODO)"), _L("Display printable box"),
[this](wxCommandEvent& evt) {
wxGetApp().app_config->set_bool("show_printable_box", evt.GetInt() == 1);
}, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_printable_box").compare("true") == 0; }, this);
//editMenu->AppendSeparator();
//append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Mesh(TODO)"),
// _L("Display triangles of models"), [this](wxCommandEvent& evt) {
// wxGetApp().app_config->set_bool("show_model_mesh", evt.GetInt() == 1);
// }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_mesh").compare("true") == 0; }, this);
//append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Shadow(TODO)"), _L("Display shadow of objects"),
// [this](wxCommandEvent& evt) {
// wxGetApp().app_config->set_bool("show_model_shadow", evt.GetInt() == 1);
// }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_shadow").compare("true") == 0; }, this);
//editMenu->AppendSeparator();
//append_menu_check_item(editMenu, wxID_ANY, _L("Show Printable Box(TODO)"), _L("Display printable box"),
// [this](wxCommandEvent& evt) {
// wxGetApp().app_config->set_bool("show_printable_box", evt.GetInt() == 1);
// }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_printable_box").compare("true") == 0; }, this);
}
// BBS
@ -2234,7 +2255,7 @@ void MainFrame::select_tab(wxPanel* panel)
//BBS
void MainFrame::jump_to_monitor(std::string dev_id)
{
m_tabpanel->SetSelection(m_with_3dEditor? tpMonitor:(tpMonitor-1));
m_tabpanel->SetSelection(tpMonitor);
((MonitorPanel*)m_monitor)->select_machine(dev_id);
}
@ -2273,42 +2294,10 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
select(false);
}
void MainFrame::enable_tab(size_t tab, bool enabled)
{
if (tab != tp3DEditor)
//currently only support 3dEditor
return;
if ((enabled && m_with_3dEditor) || (!enabled && !m_with_3dEditor))
//already done
return;
Freeze();
if (enabled) {
int sel = m_tabpanel->GetSelection();
m_tabpanel->InsertPage(tab, m_plater, _L("Prepare"), std::string("tab_3d_active"), std::string("tab_3d_active"));
if (sel >= tab)
m_tabpanel->SetSelection(sel + 1);
}
else {
int sel = m_tabpanel->GetSelection();
m_tabpanel->RemovePage(tab);
if (sel >= tab)
m_tabpanel->SetSelection(sel - 1);
}
m_with_3dEditor = enabled;
m_plater->Show();
m_tabpanel->Show();
Thaw();
}
void MainFrame::request_select_tab(TabPosition pos)
{
int position = pos;
if ((!m_with_3dEditor)&&(pos >= tpPreview))
position = (int)pos -1;
wxCommandEvent* evt = new wxCommandEvent(EVT_SELECT_TAB);
evt->SetInt(position);
evt->SetInt(pos);
wxQueueEvent(this, evt);
}
@ -2487,6 +2476,12 @@ void MainFrame::load_url(wxString url)
wxQueueEvent(this, evt);
}
void MainFrame::refresh_plugin_tips()
{
if (m_webview != nullptr)
m_webview->ShowNetpluginTip();
}
void MainFrame::RunScript(wxString js)
{
if (m_webview != nullptr)
@ -2538,7 +2533,7 @@ void MainFrame::on_select_default_preset(SimpleEvent& evt)
{
MessageDialog dialog(this,
_L("Do you want to synchronize your personal data from Bambu Cloud? \n"
"Contains the following information:\n"
"It contains the following information:\n"
"1. The Process presets\n"
"2. The Filament presets\n"
"3. The Printer presets\n"),

View file

@ -83,7 +83,6 @@ protected:
class MainFrame : public DPIFrame
{
bool m_loaded {false};
bool m_with_3dEditor { true };
wxString m_qs_last_input_file = wxEmptyString;
wxString m_qs_last_output_file = wxEmptyString;
@ -278,7 +277,6 @@ public:
// Select tab in m_tabpanel
// When tab == -1, will be selected last selected tab
//BBS: GUI refactor
void enable_tab(size_t tab, bool enabled = true);
void select_tab(wxPanel* panel);
void select_tab(size_t tab = size_t(-1));
void request_select_tab(TabPosition pos);
@ -301,6 +299,7 @@ public:
//BBS
void load_url(wxString url);
void refresh_plugin_tips();
void RunScript(wxString js);
// BBS. Replace title bar and menu bar with top bar.

View file

@ -108,19 +108,23 @@ bool MarkdownTip::ShowTip(wxPoint pos, std::string const &tip, std::string const
return false;
if (pos.x) {
_hide = true;
BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: hide soon on empty tip.";
this->Hide();
}
else if (!_hide) {
_hide = true;
BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: start hide timer (300)...";
_timer->StartOnce(300);
}
return false;
}
if (_lastTip != tip) {
bool tipChanged = _lastTip != tip;
if (tipChanged) {
auto content = LoadTip(tip, tooltip);
if (content.empty()) {
_hide = true;
this->Hide();
BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: hide soon on empty content.";
return false;
}
auto script = "window.showMarkdown('" + url_encode(content) + "', true);";
@ -140,8 +144,11 @@ bool MarkdownTip::ShowTip(wxPoint pos, std::string const &tip, std::string const
if (pos.y + this->GetSize().y > size.y)
pos.y = size.y - this->GetSize().y;
this->SetPosition(pos);
_hide = false;
_timer->StartOnce(500);
if (tipChanged || _hide) {
_hide = false;
BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: start show timer (500)...";
_timer->StartOnce(500);
}
}
return true;
}
@ -264,11 +271,14 @@ void MarkdownTip::OnTimer(wxTimerEvent& event)
if (_hide) {
wxPoint pos = ScreenToClient(wxGetMousePosition());
if (GetClientRect().Contains(pos)) {
BOOST_LOG_TRIVIAL(info) << "MarkdownTip::OnTimer: restart hide timer...";
_timer->StartOnce();
return;
}
BOOST_LOG_TRIVIAL(info) << "MarkdownTip::OnTimer: hide.";
this->Hide();
} else {
BOOST_LOG_TRIVIAL(info) << "MarkdownTip::OnTimer: show.";
this->Show();
}
}

View file

@ -163,7 +163,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj)
auto fs = m_image_grid->GetFileSystem();
if (fs) {
m_image_grid->SetFileSystem(nullptr);
fs->Unbind(EVT_MODE_CHANGED, &MediaFilePanel::fileChanged, this);
fs->Unbind(EVT_MODE_CHANGED, &MediaFilePanel::modeChanged, this);
fs->Stop(true);
}
if (m_machine.empty()) {
@ -171,7 +171,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj)
} else {
boost::shared_ptr<PrinterFileSystem> fs(new PrinterFileSystem);
m_image_grid->SetFileSystem(fs);
fs->Bind(EVT_MODE_CHANGED, &MediaFilePanel::fileChanged, this);
fs->Bind(EVT_MODE_CHANGED, &MediaFilePanel::modeChanged, this);
fs->Bind(EVT_STATUS_CHANGED, [this, wfs = boost::weak_ptr(fs)](auto &e) {
boost::shared_ptr fs(wfs.lock());
if (m_image_grid->GetFileSystem() != fs) // canceled
@ -183,6 +183,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj)
case PrinterFileSystem::Connecting: icon = m_bmp_loading.bmp(); msg = _L("Connecting..."); break;
case PrinterFileSystem::Failed: icon = m_bmp_failed.bmp(); msg = _L("Connect failed [%d]!"); break;
case PrinterFileSystem::ListSyncing: icon = m_bmp_loading.bmp(); msg = _L("Loading file list..."); break;
case PrinterFileSystem::ListReady: icon = m_bmp_empty.bmp(); msg = _L("No files"); break;
}
if (fs->GetCount() == 0)
m_image_grid->SetStatus(icon, msg);
@ -192,7 +193,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj)
if (IsShown()) fs->Start();
}
wxCommandEvent e(EVT_MODE_CHANGED);
fileChanged(e);
modeChanged(e);
}
void MediaFilePanel::Rescale()
@ -218,12 +219,10 @@ void MediaFilePanel::Rescale()
m_image_grid->Rescale();
}
void MediaFilePanel::fileChanged(wxCommandEvent& e1)
void MediaFilePanel::modeChanged(wxCommandEvent& e1)
{
e1.Skip();
auto fs = m_image_grid->GetFileSystem();
if (fs)
m_image_grid->SetStatus(m_bmp_empty.bmp(), fs->GetCount() ? L"" : _L("No files"));
auto mode = fs ? fs->GetGroupMode() : 0;
if (m_last_mode == mode)
return;
@ -247,7 +246,7 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs)
BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: camera_url: " << url;
CallAfter([this, url, wfs] {
boost::shared_ptr fs(wfs.lock());
if (fs != m_image_grid->GetFileSystem()) return;
if (!fs || fs != m_image_grid->GetFileSystem()) return;
fs->SetUrl(url);
});
});

View file

@ -38,7 +38,7 @@ public:
void Rescale();
private:
void fileChanged(wxCommandEvent & e);
void modeChanged(wxCommandEvent & e);
void fetchUrl(boost::weak_ptr<PrinterFileSystem> fs);

View file

@ -111,7 +111,7 @@ void MediaPlayCtrl::Stop()
m_media_ctrl->InvalidateBestSize();
m_button_play->SetIcon("media_play");
boost::unique_lock lock(m_mutex);
m_tasks.push_back("");
m_tasks.push_back("<stop>");
m_cond.notify_all();
}
m_last_state = MEDIASTATE_IDLE;
@ -132,6 +132,11 @@ void MediaPlayCtrl::SetStatus(wxString const& msg2)
{
auto msg = wxString::Format(msg2, m_failed_code);
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::SetStatus: " << msg.ToUTF8().data();
#ifdef __WXMSW__
OutputDebugStringA("MediaPlayCtrl::SetStatus: ");
OutputDebugStringA(msg.ToUTF8().data());
OutputDebugStringA("\n");
#endif // __WXMSW__
m_label_status->SetLabel(msg);
//m_label_status->SetForegroundColour(!msg.EndsWith("!") ? 0x42AE00 : 0x3B65E9);
Layout();
@ -147,11 +152,17 @@ void MediaPlayCtrl::media_proc()
wxString url = m_tasks.front();
lock.unlock();
if (url.IsEmpty()) {
break;
}
else if (url == "<stop>") {
m_media_ctrl->Stop();
}
else if (url == "<exit>") {
break;
}
else if (url == "<play>") {
m_media_ctrl->Play();
}
else {
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: start load";
m_media_ctrl->Load(wxURI(url));
@ -193,10 +204,11 @@ void MediaPlayCtrl::onStateChanged(wxMediaEvent& event)
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::onStateChanged: size: " << size.x << "x" << size.y;
m_failed_code = m_media_ctrl->GetLastError();
if (size.GetWidth() > 1000) {
m_media_ctrl->Play();
SetStatus(_L("Playing..."));
m_failed_retry = 0;
m_last_state = m_media_ctrl->GetState();
boost::unique_lock lock(m_mutex);
m_tasks.push_back("<play>");
m_cond.notify_all();
}
else if (event.GetId()) {
Stop();

View file

@ -335,7 +335,7 @@ void MonitorPanel::on_size(wxSizeEvent &event)
// update wifi signal image
int wifi_signal_val = 0;
if (!obj->is_connected()) {
if (!obj->is_connected() || obj->is_connecting()) {
m_side_tools->set_current_printer_signal(WifiSignal::NONE);
} else {
if (!obj->wifi_signal.empty() && boost::ends_with(obj->wifi_signal, "dBm")) {
@ -381,6 +381,7 @@ void MonitorPanel::update_all()
}
if (obj) {
wxGetApp().reset_to_active();
if (obj->connection_type() != last_conn_type) {
last_conn_type = obj->connection_type();
}
@ -404,7 +405,10 @@ void MonitorPanel::update_all()
return;
}
if (!obj->is_connected()) {
if (obj->is_connecting()) {
show_status(MONITOR_CONNECTING);
return;
} else if (!obj->is_connected()) {
int server_status = 0;
// only disconnected server in cloud mode
if (obj->connection_type() != "lan") {
@ -413,7 +417,6 @@ void MonitorPanel::update_all()
}
}
show_status((int) MONITOR_DISCONNECTED + server_status);
m_status_info_panel->show_unload_ctrl();
return;
}
@ -457,15 +460,9 @@ bool MonitorPanel::Show(bool show)
obj->reset_update_time();
}
}
if (m_agent)
m_agent->start_subscribe("monitor");
}
else {
} else {
m_refresh_timer->Stop();
m_status_info_panel->m_media_play_ctrl->SetMachineObject(nullptr);
if (m_agent)
m_agent->stop_subscribe("monitor");
}
return wxPanel::Show(show);
}
@ -503,8 +500,15 @@ void MonitorPanel::show_status(int status)
else
m_connection_info->SetLabel(_L("Failed to connect to the printer"));
m_connection_info->Show();
}else if ((status & (int) MonitorStatus::MONITOR_NORMAL) != 0) {
m_connection_info->SetBackgroundColor(wxColour(255, 111, 0));
m_connection_info->SetBorderColor(wxColour(255, 111, 0));
} else if ((status & (int) MonitorStatus::MONITOR_NORMAL) != 0) {
m_connection_info->Hide();
} else if ((status & (int) MonitorStatus::MONITOR_CONNECTING) != 0) {
m_connection_info->SetLabel(_L("Connecting..."));
m_connection_info->SetBackgroundColor(wxColour(0, 174, 66));
m_connection_info->SetBorderColor(wxColour(0, 174, 66));
m_connection_info->Show();
}
Freeze();
@ -515,11 +519,14 @@ void MonitorPanel::show_status(int status)
m_status_info_panel->show_status(status);
m_tabpanel->Refresh();
m_tabpanel->Layout();
} else if (((status & (int)MonitorStatus::MONITOR_NORMAL) != 0) ||
((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0) ||
((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)
} else if (((status & (int)MonitorStatus::MONITOR_NORMAL) != 0)
|| ((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0)
|| ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)
|| ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0)
) {
if (((status & (int) MonitorStatus::MONITOR_DISCONNECTED) != 0) || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)) {
if (((status & (int) MonitorStatus::MONITOR_DISCONNECTED) != 0)
|| ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)
|| ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0)) {
m_side_tools->set_current_printer_signal(WifiSignal::NONE);
set_default();
}

View file

@ -390,5 +390,4 @@ void DownloadDialog::SetExtendedMessage(const wxString &extendedMessage)
Fit();
}
}
}
}} // namespace Slic3r::GUI

View file

@ -13,6 +13,8 @@
#include <wx/textctrl.h>
#include <wx/statline.h>
#include "Widgets/Button.hpp"
#include "BBLStatusBar.hpp"
#include "BBLStatusBarSend.hpp"
class wxBoxSizer;
class wxCheckBox;
@ -364,7 +366,6 @@ private:
wxString msg;
};
}
}

Some files were not shown because too many files have changed in this diff Show more