Merge remote-tracking branch 'upstream/main' into dev/h2d

# Conflicts:
#	resources/profiles/BBL.json
#	src/slic3r/GUI/AmsMappingPopup.cpp
#	src/slic3r/GUI/MediaFilePanel.cpp
#	src/slic3r/GUI/Plater.cpp
#	src/slic3r/GUI/StatusPanel.cpp
This commit is contained in:
Noisyfox
2025-09-16 14:46:40 +08:00
6267 changed files with 210559 additions and 178855 deletions
+233 -190
View File
@@ -21,6 +21,197 @@
namespace Slic3r {
// Calculate infill rotation angle (in radians) for a given layer from a rotation template.
// Grammar subset handled (rotation only):
// [±]α[*Z or !][joint][-][N|B|T][length][* or !]
// [±]α* sets an initial angle only (no layer processed)
// Where:
// - α: angle in degrees. Without a sign it's absolute; with +/− it's relative. α% means a percentage of 360°.
// - Runtime: *Z repeats the instruction Z times; bare * is a no-op used for initialization; ! runs once globally and then stops.
// - Solid signs (D,S,O,M,R) are not processed here; if present they are treated as invalid/non-rotation characters.
// - Joint signs (shape of the turn across a range):
// / linear;
// N,n vertical sinus (n = lazy/half amplitude);
// Z,z horizontal sinus (z = lazy/half amplitude);
// $ arcsin; L quarter circle H→V; l quarter circle V→H;
// U,u squared; Q,q cubic; ~ random; ^ pseudorandom; | middle step; # vertical step at end.
// - Counting / range length:
// After the joint (or after α) a count determines duration of the turn:
// N = layer count, B = bottom_shell_layers, T = top_shell_layers.
// Prefix '-' flips the joint (swap initial/final orientation).
// - Length modifiers convert the count to a Z range instead of a pure layer count:
// mm, cm, m, ' (feet), " (inches), # (standard height of N layers), % (percent of model height).
//
// Behavior:
// - The template string is tokenized by commas/whitespace and evaluated cyclically with one or more "ranges" per token.
// - Absolute α resets the accumulated angle at the start of its range; relative α accumulates.
// - *Z and ! control repetition and one-time execution of tokens across layers.
// - If the template contains no metalanguage symbols, it is treated as a simple comma-separated list of angles repeated by modulo.
// - Returns angle in radians for the requested layer_id. 0° aligns with +X; fillers may internally rotate as needed.
double calculate_infill_rotation_angle(const PrintObject* object,
size_t layer_id,
const double& fixed_infill_angle,
const std::string& template_string)
{
if (template_string.empty()) {
return Geometry::deg2rad(fixed_infill_angle);
}
double angle = 0.0;
ConfigOptionFloats rotate_angles;
const std::string search_string = "/NnZz$LlUuQq~^|#";
if (regex_search(template_string, std::regex("[+\\-%*@\'\"cm" + search_string + "]"))) { // template metalanguage of rotating infill
std::regex del("[\\s,]+");
std::sregex_token_iterator it(template_string.begin(), template_string.end(), del, -1);
std::vector<std::string> tk;
std::sregex_token_iterator end;
while (it != end) {
tk.push_back(*it++);
}
int t = 0;
int repeats = 0;
double angle_add = 0;
double angle_steps = 1;
double angle_start = 0;
double limit_fill_z = object->get_layer(0)->bottom_z();
double start_fill_z = limit_fill_z;
bool _noop = false;
auto fill_form = std::string::npos;
bool _absolute = false;
bool _negative = false;
std::vector<bool> stop(tk.size(), false);
for (int i = 0; i <= layer_id; i++) {
double fill_z = object->get_layer(i)->bottom_z();
if (limit_fill_z < object->get_layer(i)->slice_z) {
if (repeats) { // if repeats >0 then restore parameters for new iteration
limit_fill_z += limit_fill_z - start_fill_z;
start_fill_z = fill_z;
repeats--;
} else {
start_fill_z = fill_z;
limit_fill_z = object->get_layer(i)->print_z;
// Solid handling removed: this function only computes rotation.
fill_form = std::string::npos;
do {
if (!stop[t]) {
_noop = false;
_absolute = false;
_negative = false;
angle_start += angle_add;
angle_add = 0;
angle_steps = 1;
repeats = 1;
if (tk[t].find('!') != std::string::npos) // this is an one-time instruction
stop[t] = true;
char* cs = &tk[t][0];
if ((cs[0] >= '0' && cs[0] <= '9') && !(cs[0] == '+' || cs[0] == '-')) // absolute/relative
_absolute = true;
angle_add = strtod(cs, &cs); // read angle parameter
if (cs[0] == '%') { // percentage of angles
angle_add *= 3.6;
cs = &cs[1];
}
int tit = tk[t].find('*');
if (tit != std::string::npos) // overall angle_cycles
repeats = strtol(&tk[t][tit + 1], &cs, 0);
if (repeats) { // run if overall cycles greater than 0
// Solid signs (D,S,O,M,R) are not handled here; if present they behave as invalid characters.
if (cs[0] == 'B') {
angle_steps = object->print()->default_region_config().bottom_shell_layers.value;
} else if (cs[0] == 'T') {
angle_steps = object->print()->default_region_config().top_shell_layers.value;
} else {
fill_form = search_string.find(cs[0]);
if (fill_form != std::string::npos)
cs = &cs[1];
_negative = (cs[0] == '-'); // negative parameter
angle_steps = abs(strtod(cs, &cs));
if (angle_steps && cs[0] != '\0' && cs[0] != '!') {
if (cs[0] == '%') // value in the percents of fill_z
limit_fill_z = angle_steps * object->height() * 1e-8;
else if (cs[0] == '#') // value in the feet
limit_fill_z = angle_steps * object->config().layer_height;
else if (cs[0] == '\'') // value in the feet
limit_fill_z = angle_steps * 12 * 25.4;
else if (cs[0] == '\"') // value in the inches
limit_fill_z = angle_steps * 25.4;
else if (cs[0] == 'c') // value in centimeters
limit_fill_z = angle_steps * 10.;
else if (cs[0] == 'm') {
if (cs[1] == 'm') { // value in the millimeters
limit_fill_z = angle_steps * 1.;
} else{
limit_fill_z = angle_steps * 1000.;
}
}
limit_fill_z += fill_z;
angle_steps = 0; // limit_fill_z has already count
}
}
if (angle_steps) { // if limit_fill_z does not setting by lenght method. Get count the layer id above model height
if (fill_form == std::string::npos && !_absolute)
angle_add *= (int) angle_steps;
int idx = i + std::max(angle_steps - 1, 0.);
int sdx = std::max(0, idx - (int) object->layers().size());
idx = std::min(idx, (int) object->layers().size() - 1);
limit_fill_z = object->get_layer(idx)->print_z + sdx * object->config().layer_height;
}
repeats = std::max(--repeats, 0);
} else
_noop = true; // set the dumb cycle
if (_absolute) { // is absolute
angle_start = angle_add;
angle_add = 0;
}
}
if (++t >= tk.size())
t = 0;
} while (std::all_of(stop.begin(), stop.end(), [](bool v) { return v; }) ?
false :
(t ? _noop : false) || stop[t]); // if this is a dumb instruction which never reaprated twice
}
}
double top_z = object->get_layer(i)->print_z;
double negvalue = (_negative ? limit_fill_z - top_z : top_z - start_fill_z) / (limit_fill_z - start_fill_z);
switch (fill_form) {
case 0: break; // /-joint, linear
case 1: negvalue -= sin(negvalue * PI * 2.) / (PI * 2.); break; // N-joint, sinus, vertical start
case 2: negvalue -= sin(negvalue * PI * 2.) / (PI * 4.); break; // n-joint, sinus, vertical start, lazy
case 3: negvalue += sin(negvalue * PI * 2.) / (PI * 2.); break; // Z-joint, sinus, horizontal start
case 4: negvalue += sin(negvalue * PI * 2.) / (PI * 4.); break; // z-joint, sinus, horizontal start, lazy
case 5: negvalue = asin(negvalue * 2. - 1.) / PI + 0.5; break; // $-joint, arcsin
case 6: negvalue = sin(negvalue * PI / 2.); break; // L-joint, quarter of circle, horizontal start
case 7: negvalue = 1. - cos(negvalue * PI / 2.); break; // l-joint, quarter of circle, vertical start
case 8: negvalue = 1. - pow(1. - negvalue, 2); break; // U-joint, squared, x2
case 9: negvalue = pow(1 - negvalue, 2); break; // u-joint, squared, x2 inverse
case 10: negvalue = 1. - pow(1. - negvalue, 3); break; // Q-joint, cubic, x3
case 11: negvalue = pow(1. - negvalue, 3); break; // q-joint, cubic, x3 inverse
case 12: negvalue = (double) rand() / RAND_MAX; break; // ~-joint, random, fill the whole angle
case 13: negvalue += (double) rand() / RAND_MAX - 0.5; break; // ^-joint, pseudorandom, disperse at middle line
case 14: negvalue = 0.5; break; // |-joint, like #-joint but placed at middle angle
case 15: negvalue = _negative ? 0. : 1.; break; // #-joint, vertical at the end angle
}
angle = Geometry::deg2rad(angle_start + angle_add * negvalue);
}
} else {
rotate_angles.deserialize(template_string);
auto rotate_angle_idx = layer_id % rotate_angles.size();
angle = Geometry::deg2rad(rotate_angles.values[rotate_angle_idx]);
}
return angle;
}
struct SurfaceFillParams
{
// Zero based extruder ID.
@@ -35,6 +226,8 @@ struct SurfaceFillParams
coordf_t overlap = 0.;
// Angle as provided by the region config, in radians.
float angle = 0.f;
// Orca: is_using_template_angle
bool is_using_template_angle = false;
// Is bridging used for this fill? Bridging parameters may be used even if this->flow.bridge() is not set.
bool bridge;
// Non-negative for a bridge.
@@ -90,6 +283,7 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(spacing);
RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(is_using_template_angle);
RETURN_COMPARE_NON_EQUAL(density);
RETURN_COMPARE_NON_EQUAL(multiline);
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
@@ -118,6 +312,7 @@ struct SurfaceFillParams
this->spacing == rhs.spacing &&
this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->is_using_template_angle == rhs.is_using_template_angle &&
this->bridge == rhs.bridge &&
this->bridge_angle == rhs.bridge_angle &&
this->density == rhs.density &&
@@ -627,7 +822,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
flow_params.insert({flow, {exp}});
else
it->second.push_back(exp);
it++;
};
auto append_density_param = [](std::map<float, ExPolygons> &density_params, float density, const ExPolygon &exp) {
@@ -636,7 +830,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
density_params.insert({density, {exp}});
else
it->second.push_back(exp);
it++;
};
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
@@ -652,11 +845,9 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
params.extruder = layerm.region().extruder(extrusion_role);
params.pattern = region_config.sparse_infill_pattern.value;
params.density = float(region_config.sparse_infill_density);
params.multiline = int(region_config.fill_multiline);
params.lateral_lattice_angle_1 = region_config.lateral_lattice_angle_1;
params.lateral_lattice_angle_2 = region_config.lateral_lattice_angle_2;
params.infill_overhang_angle = region_config.infill_overhang_angle;
params.angle = 0.;
if (params.pattern == ipLockedZag) {
params.infill_lock_depth = scale_(region_config.infill_lock_depth);
params.skin_infill_depth = scale_(region_config.skin_infill_depth);
@@ -704,17 +895,24 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
params.extrusion_role = erSolidInfill;
}
}
// Orca: apply fill multiline only for sparse infill
params.multiline = params.extrusion_role == erInternalInfill ? int(region_config.fill_multiline) : 1;
if (params.extrusion_role == erInternalInfill) {
params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.infill_direction.value,
region_config.sparse_infill_rotate_template.value);
params.is_using_template_angle = !region_config.sparse_infill_rotate_template.value.empty();
} else {
params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.solid_infill_direction.value,
region_config.solid_infill_rotate_template.value);
params.is_using_template_angle = !region_config.solid_infill_rotate_template.value.empty();
}
params.bridge_angle = float(surface.bridge_angle);
if (region_config.align_infill_direction_to_model) {
auto m = layer.object()->trafo().matrix();
params.angle += atan2((float) m(1, 0), (float) m(0, 0));
}
if (params.extrusion_role == erInternalInfill) {
params.angle += float(Geometry::deg2rad(region_config.infill_direction.value));
} else {
params.angle += float(Geometry::deg2rad(region_config.solid_infill_direction.value));
}
// Calculate the actual flow we'll be using for this infill.
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
@@ -892,8 +1090,12 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
params.pattern = ipRectilinear;
params.density = 100.f;
params.extrusion_role = erSolidInfill;
params.angle = float(Geometry::deg2rad(layerm.region().config().solid_infill_direction.value));
// calculate the actual flow we'll be using for this infill
const PrintRegionConfig &region_config = layerm.region().config();
params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.solid_infill_direction.value,
region_config.solid_infill_rotate_template.value);
params.is_using_template_angle = !region_config.solid_infill_rotate_template.value.empty();
// calculate the actual flow we'll be using for this infill
params.flow = layerm.flow(frSolidInfill);
params.spacing = params.flow.spacing();
surface_fills.emplace_back(params);
@@ -996,6 +1198,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
f->layer_id = this->id();
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->is_using_template_angle = surface_fill.params.is_using_template_angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
@@ -1054,184 +1257,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.config = &region_config;
params.pattern = surface_fill.params.pattern;
ConfigOptionFloats rotate_angles;
const std::string search_string = "/NnZz$LlUuQq~^|#";
std::string v(params.extrusion_role == erInternalInfill ? region_config.sparse_infill_rotate_template.value :
region_config.solid_infill_rotate_template.value);
if (regex_search(v, std::regex("[+\\-%*@\'\"cmSODMR" + search_string + "]"))) { // template metalanguage of rotating infill
std::regex del("[\\s,]+");
std::sregex_token_iterator it(v.begin(), v.end(), del, -1);
std::vector<std::string> tk;
std::sregex_token_iterator end;
while (it != end) {
tk.push_back(*it++);
}
int t = 0;
int repeats = 0;
double angle = 0;
double angle_add = 0;
double angle_steps = 1;
double angle_start = 0;
double limit_fill_z = this->object()->get_layer(0)->bottom_z();
double start_fill_z = limit_fill_z;
bool _noop = false;
auto solid = std::string::npos; // -1 - sparse, 0 - native (D), 1 - internal solid (S), 2 - concentric (O), 3 - monotonic (M), 4 - rectilinear (R)
auto fill_form = std::string::npos;
bool _absolute = false;
bool _negative = false;
std::vector<bool> stop(tk.size(), false);
for (int i = 0; i <= this->id(); i++) {
double fill_z = this->object()->get_layer(i)->bottom_z();
if (limit_fill_z < this->object()->get_layer(i)->slice_z) {
if (repeats) { // if repeats >0 then restore parameters for new iteration
limit_fill_z += limit_fill_z - start_fill_z;
start_fill_z = fill_z;
repeats--;
} else {
start_fill_z = fill_z;
limit_fill_z = this->object()->get_layer(i)->print_z;
solid = std::string::npos;
fill_form = std::string::npos;
do {
if (!stop[t]) {
_noop = false;
_absolute = false;
_negative = false;
angle_start += angle_add;
angle_add = 0;
angle_steps = 1;
repeats = 1;
if (tk[t].find('!') != std::string::npos) // this is an one-time instruction
stop[t] = true;
char* cs = &tk[t][0];
if ((cs[0] >= '0' && cs[0] <= '9') && !(cs[0] == '+' || cs[0] == '-')) // absolute/relative
_absolute = true;
angle_add = strtod(cs, &cs); // read angle parameter
if (cs[0] == '%') { // percentage of angles
angle_add *= 3.6;
cs = &cs[1];
}
int tit = tk[t].find('*');
if (tit != std::string::npos) // overall angle_cycles
repeats = strtol(&tk[t][tit + 1], &cs, 0);
if (repeats) { // run if overall cycles greater than 0
solid = std::string("DSOMR").find(cs[0]); // solid infill
if (solid != std::string::npos)
cs = &cs[1];
if (cs[0] == 'B') {
angle_steps = this->object()->print()->default_region_config().bottom_shell_layers.value;
} else if (cs[0] == 'T') {
angle_steps = this->object()->print()->default_region_config().top_shell_layers.value;
} else {
fill_form = search_string.find(cs[0]);
if (fill_form != std::string::npos)
cs = &cs[1];
_negative = (cs[0] == '-'); // negative parameter
angle_steps = abs(strtod(cs, &cs));
if (angle_steps && cs[0] != '\0' && cs[0] != '!') {
if (cs[0] == '%') // value in the percents of fill_z
limit_fill_z = angle_steps * this->object()->height() * 1e-8;
else if (cs[0] == '#') // value in the feet
limit_fill_z = angle_steps * this->object()->config().layer_height;
else if (cs[0] == '\'') // value in the feet
limit_fill_z = angle_steps * 12 * 25.4;
else if (cs[0] == '\"') // value in the inches
limit_fill_z = angle_steps * 25.4;
else if (cs[0] == 'c') // value in centimeters
limit_fill_z = angle_steps * 10.;
else if (cs[0] == 'm')
if (cs[1] == 'm') { // value in the millimeters
limit_fill_z = angle_steps * 1.;
} else // value in the meters
limit_fill_z = angle_steps * 1000.;
limit_fill_z += fill_z;
angle_steps = 0; // limit_fill_z has already count
}
}
if (angle_steps) { // if limit_fill_z does not setting by lenght method. Get count the layer id above model height
if (fill_form == std::string::npos && !_absolute)
angle_add *= (int) angle_steps;
int idx = i + std::max(angle_steps - 1, 0.);
int sdx = std::max(0, idx - (int) this->object()->layers().size());
idx = std::min(idx, (int) this->object()->layers().size() - 1);
limit_fill_z = this->object()->get_layer(idx)->print_z + sdx * this->object()->config().layer_height;
}
repeats = std::max(--repeats, 0);
} else
_noop = true; // set the dumb cycle
if (_absolute) { // is absolute
angle_start = angle_add;
angle_add = 0;
}
}
if (++t >= tk.size())
t = 0;
} while (std::all_of(stop.begin(), stop.end(), [](bool v) { return v; }) ? false :
(t ? _noop : false) || stop[t]); // if this is a dumb instruction which never reaprated twice
}
}
double top_z = this->object()->get_layer(i)->print_z;
double negvalue = (_negative ? limit_fill_z - top_z : top_z - start_fill_z) / (limit_fill_z - start_fill_z);
switch (fill_form) {
case 0: break; // /-joint, linear
case 1: negvalue -= sin(negvalue * PI * 2.) / (PI * 2.); break; // N-joint, sinus, vertical start
case 2: negvalue -= sin(negvalue * PI * 2.) / (PI * 4.); break; // n-joint, sinus, vertical start, lazy
case 3: negvalue += sin(negvalue * PI * 2.) / (PI * 2.); break; // Z-joint, sinus, horizontal start
case 4: negvalue += sin(negvalue * PI * 2.) / (PI * 4.); break; // z-joint, sinus, horizontal start, lazy
case 5: negvalue = asin(negvalue * 2. - 1.) / PI + 0.5; break; // $-joint, arcsin
case 6: negvalue = sin(negvalue * PI / 2.); break; // L-joint, quarter of circle, horizontal start
case 7: negvalue = 1. - cos(negvalue * PI / 2.); break; // l-joint, quarter of circle, vertical start
case 8: negvalue = 1. - pow(1. - negvalue, 2); break; // U-joint, squared, x2
case 9: negvalue = pow(1 - negvalue, 2); break; // u-joint, squared, x2 inverse
case 10: negvalue = 1. - pow(1. - negvalue, 3); break; // Q-joint, cubic, x3
case 11: negvalue = pow(1. - negvalue, 3); break; // q-joint, cubic, x3 inverse
case 12: negvalue = (double) rand() / RAND_MAX; break; // ~-joint, random, fill the whole angle
case 13: negvalue += (double) rand() / RAND_MAX - 0.5; break; // ^-joint, pseudorandom, disperse at middle line
case 14: negvalue = 0.5; break; // |-joint, like #-joint but placed at middle angle
case 15: negvalue = _negative ? 0. : 1.; break; // #-joint, vertical at the end angle
}
angle = angle_start + angle_add * negvalue;
}
if (solid != std::string::npos) {
switch (solid) {
case 1: params.pattern = region_config.internal_solid_infill_pattern.value; break; // selected solid pattern
case 2: params.pattern = ipConcentric; break; // concentric pattern
case 3: params.pattern = ipMonotonic; break; // monotonic pattern
case 4: params.pattern = ipRectilinear; // rectilinear pattern
} // or else use native pattern
params.extrusion_role = erSolidInfill;
params.density = 1.;
surface_fill.params.pattern = params.pattern;
f = std::unique_ptr<Fill>(Fill::new_from_type(params.pattern)); // reinitialize surface
f->set_bounding_box(bbox);
f->layer_id = this->id();
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
params.use_arachne = surface_fill.params.pattern == ipConcentric || surface_fill.params.pattern == ipConcentricInternal;
}
f->rotate_angle = Geometry::deg2rad(angle);
} else {
rotate_angles.deserialize(v);
auto rotate_angle_idx = f->layer_id % rotate_angles.size();
f->rotate_angle = Geometry::deg2rad(rotate_angles.values[rotate_angle_idx]);
}
if( surface_fill.params.pattern == ipLockedZag ) {
if( surface_fill.params.pattern == ipLockedZag ) {
params.locked_zag = true;
params.infill_lock_depth = surface_fill.params.infill_lock_depth;
params.skin_infill_depth = surface_fill.params.skin_infill_depth;
@@ -1293,7 +1319,23 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != nullptr);
#endif
}
/**
* Generate sparse-infill polylines for anchoring/analysis purposes.
*
* This produces the geometric polylines of internal sparse infill for the current
* layer (using the same infill pattern, angle, rotation template, and spacing that
* normal slicing would use), but it does not create extrusion entities.
*
* The returned polylines are consumed by internal-bridge detection on the next
* layer to derive anchor lines and compute the bridge direction over sparse infill.
*
* Notes:
* - Only `stInternal` surfaces are considered.
* - Rotation templates (e.g. `sparse_infill_rotate_template`) are applied so the
* anchors reflect the actual infill orientation.
* - For lightning/adaptive patterns, the respective generators are wired so their
* polylines match the final infill layout.
*/
Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator) const
{
LockRegionParam skin_inner_param;
@@ -1346,6 +1388,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
f->layer_id = this->id() - this->object()->get_layer(0)->id(); // We need to subtract raft layers.
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->is_using_template_angle = surface_fill.params.is_using_template_angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
+3 -2
View File
@@ -15,8 +15,9 @@ public:
Fill* clone() const override { return new Fill3DHoneycomb(*this); };
~Fill3DHoneycomb() override {}
// require bridge flow since most of this pattern hangs in air
bool use_bridge_flow() const override { return true; }
// note: updated 3D Honeycomb doesn't need bridge flow because the
// pattern is placed on top of previous layers
bool use_bridge_flow() const override { return false; }
bool is_self_crossing() override { return false; }
protected:
+3 -1
View File
@@ -306,7 +306,9 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
out_angle = float(surface->bridge_angle);
} else if (this->layer_id != size_t(-1)) {
// alternate fill direction
out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
//Orca: if template angle is not empty, don't apply layer angle
if(!is_using_template_angle)
out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
} else {
// printf("Layer_ID undefined!\n");
}
+3 -4
View File
@@ -119,8 +119,8 @@ public:
coordf_t overlap;
// in radians, ccw, 0 = East
float angle;
// Orca: enable angle shifting for layer change
float rotate_angle{ M_PI/180.0 };
// Orca: is_using_template_angle
bool is_using_template_angle{false};
// In scaled coordinates. Maximum lenght of a perimeter segment connecting two infill lines.
// Used by the FillRectilinear2, FillGrid2, FillTriangles, FillStars and FillCubic.
// If left to zero, the links will not be limited.
@@ -182,7 +182,6 @@ protected:
overlap(0.),
// Initial angle is undefined.
angle(FLT_MAX),
rotate_angle(M_PI/180.0),
link_max_length(0),
loop_clipping(0),
// The initial bounding box is empty, therefore undefined.
@@ -204,7 +203,7 @@ protected:
ExPolygon expolygon,
ThickPolylines& thick_polylines_out) {}
virtual float _layer_angle(size_t idx) const { return rotate_angle; }
virtual float _layer_angle(size_t idx) const { return is_using_template_angle ? 0.f : (idx & 1) ? float(M_PI/2.) : 0.f; }
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
+1 -1
View File
@@ -3044,7 +3044,7 @@ Polylines FillRectilinear::fill_surface(const Surface *surface, const FillParams
{
Polylines polylines_out;
// Orca Todo: fow now don't use fill_surface_by_multilines for zipzag infill
if (params.full_infill() || params.pattern == ipCrossZag || params.pattern == ipZigZag || params.pattern == ipLockedZag) {
if (params.full_infill() || params.multiline == 1 || params.pattern == ipCrossZag || params.pattern == ipZigZag || params.pattern == ipLockedZag) {
if (!fill_surface_by_lines(surface, params, 0.f, 0.f, polylines_out))
BOOST_LOG_TRIVIAL(error) << "FillRectilinear::fill_surface() fill_surface_by_lines() failed to fill a region.";
} else {
+26 -115
View File
@@ -7,7 +7,6 @@
#include <unordered_set>
#include <utility>
#include <tbb/parallel_for.h>
#include <mutex>
namespace Slic3r {
@@ -157,8 +156,8 @@ vector<double> getGridValues(int i, int j, vector<vector<double>>& data)
values.push_back(data[i][j]);
return values;
}
bool needContour(double value, double contourValue) { return value >= contourValue; }
Point interpolate(std::vector<std::vector<MarchingSquares::Point>>& posxy,
static bool needContour(double value, double contourValue) { return value >= contourValue; }
static Point interpolate(std::vector<std::vector<MarchingSquares::Point>>& posxy,
std::vector<int> p1ij,
std::vector<int> p2ij,
double v1,
@@ -186,7 +185,7 @@ Point interpolate(std::vector<std::vector<MarchingSquares::Point>>& posxy,
return p;
}
void process_block(int i,
static void process_block(int i,
int j,
vector<vector<double>>& data,
double contourValue,
@@ -288,43 +287,7 @@ void process_block(int i,
}
}
// --- Chaikin Smooth ---
static Polyline chaikin_smooth(Polyline poly, int iterations , double weight )
{
if (poly.points.size() < 3) return poly;
const double w1 = 1.0 - weight;
decltype(poly.points) buffer;
buffer.reserve(poly.points.size() * 2);
for (int it = 0; it < iterations; ++it) {
buffer.clear();
buffer.push_back(poly.points.front());
for (size_t i = 0; i < poly.points.size() - 1; ++i) {
const auto &p0 = poly.points[i];
const auto &p1 = poly.points[i + 1];
buffer.emplace_back(
p0.x() * w1 + p1.x() * weight,
p0.y() * w1 + p1.y() * weight
);
buffer.emplace_back(
p0.x() * weight + p1.x() * w1,
p0.y() * weight + p1.y() * w1
);
}
buffer.push_back(poly.points.back());
poly.points.swap(buffer);
}
return poly;
}
void drawContour(double contourValue,
static void drawContour(double contourValue,
int gridSize_w,
int gridSize_h,
vector<vector<double>>& data,
@@ -382,62 +345,18 @@ void drawContour(double contourValue,
for (myPoint& pt : p) {
repltmp.points.push_back(Slic3r::Point(pt.x, pt.y));
}
// symplify tolerance based on density
const float min_tolerance = 0.005f;
const float max_tolerance = 0.2f;
float simplify_tolerance = (0.005f / params.density);
simplify_tolerance = std::clamp(simplify_tolerance, min_tolerance, max_tolerance);
repltmp.simplify(scale_(simplify_tolerance));
repltmp = chaikin_smooth(repltmp, 2, 0.25);
repls.push_back(repltmp);
}
}
} // namespace MarchingSquares
static float sin_table[360];
static float cos_table[360];
static std::once_flag trig_tables_once_flag;
#define PIratio 57.29577951308232 // 180/PI
static void initialize_lookup_tables()
{
for (int i = 0; i < 360; ++i) {
float angle = i * (M_PI / 180.0);
sin_table[i] = std::sin(angle);
cos_table[i] = std::cos(angle);
}
}
inline static void ensure_trig_tables_initialized()
{
std::call_once(trig_tables_once_flag, initialize_lookup_tables);
}
inline static float get_sin(float angle)
{
angle = angle * PIratio;
int index = static_cast<int>(std::fmod(angle, 360) + 360) % 360;
return sin_table[index];
}
inline static float get_cos(float angle)
{
angle = angle * PIratio;
int index = static_cast<int>(std::fmod(angle, 360) + 360) % 360;
return cos_table[index];
}
void FillTpmsFK::_fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
Polylines& polylines_out)
{
ensure_trig_tables_initialized();
auto infill_angle = float(this->angle + (CorrectionAngle * 2 * M_PI) / 360.);
if(std::abs(infill_angle) >= EPSILON)
expolygon.rotate(-infill_angle);
@@ -452,40 +371,29 @@ void FillTpmsFK::_fill_surface_single(const FillParams& params,
float xlen = boxsize.x();
float ylen = boxsize.y();
const float delta = 0.5f; // mesh step (adjust for quality/performance)
const float delta = 0.4f; // mesh step (adjust for quality/performance)
float myperiod = 2 * PI / vari_T;
float c_z = myperiod * this->z; // z height
// scalar field Fischer-Koch
auto scalar_field = [&](float x, float y) {
float a_x = myperiod * x;
float b_y = myperiod * y;
auto scalar_field = [&](float x, float y) -> float {
const float a_x = myperiod * x;
const float b_y = myperiod * y;
// Fischer - Koch S equation:
// cos(2x)sin(y)cos(z) + cos(2y)sin(z)cos(x) + cos(2z)sin(x)cos(y) = 0
const float cos2ax = get_cos(2*a_x);
const float cos2by = get_cos(2*b_y);
const float cos2cz = get_cos(2*c_z);
const float sinby = get_sin(b_y);
const float cosax = get_cos(a_x);
const float sinax = get_sin(a_x);
const float cosby = get_cos(b_y);
const float sincz = get_sin(c_z);
const float coscz = get_cos(c_z);
return cos2ax * sinby * coscz
+ cos2by * sincz * cosax
+ cos2cz * sinax * cosby;
return cosf(2 * a_x) * sinf(b_y) * cosf(c_z)
+ cosf(2 * b_y) * sinf(c_z) * cosf(a_x)
+ cosf(2 * c_z) * sinf(a_x) * cosf(b_y);
};
// Mesh generation
std::vector<std::vector<MarchingSquares::Point>> posxy;
int i = 0, j = 0;
for (float y = -(ylen) / 2.0f - 2; y < (ylen) / 2.0f + 2; y = y + delta, i++) {
for (float y = -(ylen) / 2.0f - 0.5f; y < (ylen) / 2.0f + 0.5f; y = y + delta, i++) {
j = 0;
std::vector<MarchingSquares::Point> colposxy;
for (float x = -(xlen) / 2.0f - 2; x < (xlen) / 2.0f + 2; x = x + delta, j++) {
for (float x = -(xlen) / 2.0f - 0.5f; x < (xlen) / 2.0f + 0.5f; x = x + delta, j++) {
MarchingSquares::Point pt;
pt.x = cenpos.x() + x;
pt.y = cenpos.y() + y;
@@ -510,33 +418,36 @@ void FillTpmsFK::_fill_surface_single(const FillParams& params,
Polylines polylines;
const double contour_value = 0.075; // offset from zero to avoid numerical issues
const double contour_value = 0; // offset from theoretical surface
MarchingSquares::drawContour(contour_value, width , height , data, posxy, polylines, params);
if (!polylines.empty()) {
// Apply multiline offset if needed
multiline_fill(polylines, params, spacing);
// Apply multiline offset if needed
multiline_fill(polylines, params, spacing);
polylines = intersection_pl(polylines, expolygon);
polylines = intersection_pl(polylines, expolygon);
// Remove very small bits, but be careful to not remove infill lines connecting thin walls!
if (! polylines.empty()) {
// Remove very small bits, but be careful to not remove infill lines connecting thin walls!
// The infill perimeter lines should be separated by around a single infill line width.
const double minlength = scale_(0.8 * this->spacing);
polylines.erase(
std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl) { return pl.length() < minlength; }),
polylines.end());
}
if (! polylines.empty()) {
// connect lines
size_t polylines_out_first_idx = polylines_out.size();
chain_or_connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
//chain_or_connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
//chain_infill not situable for this pattern due to internal "islands", this also affect performance a lot.
connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
// new paths must be rotated back
if (std::abs(infill_angle) >= EPSILON) {
for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it)
it->rotate(infill_angle);
}
}
}
+2 -2
View File
@@ -1129,7 +1129,7 @@ void PerimeterGenerator::process_classic()
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
coord_t ext_perimeter_spacing2;
// Orca: ignore precise_outer_wall if wall_sequence is not InnerOuter
if(config->precise_outer_wall)
if(config->precise_outer_wall && config->wall_sequence == WallSequence::InnerOuter)
ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.width() + this->perimeter_flow.width()));
else
ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
@@ -2124,7 +2124,7 @@ void PerimeterGenerator::process_arachne()
if (is_topmost_layer && loop_number > 0 && config->only_one_wall_top)
loop_number = 0;
auto apply_precise_outer_wall = config->precise_outer_wall;
auto apply_precise_outer_wall = config->precise_outer_wall && config->wall_sequence == WallSequence::InnerOuter;
// Orca: properly adjust offset for the outer wall if precise_outer_wall is enabled.
ExPolygons last = offset_ex(surface.expolygon.simplify_p(surface_simplify_resolution),
apply_precise_outer_wall? -float(ext_perimeter_width - ext_perimeter_spacing )
+1 -1
View File
@@ -788,7 +788,7 @@ static std::vector<std::string> s_Preset_print_options {
"extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold","overhang_reverse_internal_only", "wall_direction",
"seam_position", "staggered_inner_seams", "wall_sequence", "is_infill_first", "sparse_infill_density","fill_multiline", "sparse_infill_pattern", "lateral_lattice_angle_1", "lateral_lattice_angle_2", "infill_overhang_angle", "top_surface_pattern", "bottom_surface_pattern",
"infill_direction", "solid_infill_direction", "counterbore_hole_bridging","infill_shift_step", "sparse_infill_rotate_template", "solid_infill_rotate_template", "symmetric_infill_y_axis","skeleton_infill_density", "infill_lock_depth", "skin_infill_depth", "skin_infill_density",
"align_infill_direction_to_model",
"align_infill_direction_to_model", "extra_solid_infills",
"minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target",
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset",
"support_ironing", "support_ironing_pattern", "support_ironing_flow", "support_ironing_spacing",
+6
View File
@@ -1627,6 +1627,12 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
// }
// }
// check wall sequence and precise outer wall
if (m_default_region_config.precise_outer_wall && m_default_region_config.wall_sequence != WallSequence::InnerOuter) {
warning->string = L("The precise wall option will be ignored for outer-inner or inner-outer-inner wall sequences.");
warning->opt_key = "precise_outer_wall";
}
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(warning) << "Orca: validate motion ability failed: " << e.what() << std::endl;
}
+84 -73
View File
@@ -679,7 +679,7 @@ void PrintConfigDef::init_common_params()
def = this->add("preferred_orientation", coFloat);
def->label = L("Preferred orientation");
def->tooltip = L("Automatically orient stls on the Z-axis upon initial import.");
def->tooltip = L("Automatically orient stls on the Z axis upon initial import.");
def->sidetext = "°"; // degrees, don't need translation
def->max = 360;
def->min = -360;
@@ -1203,9 +1203,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("precise_outer_wall",coBool);
def->label = L("Precise wall");
def->category = L("Quality");
def->tooltip = L("Improve shell precision by adjusting outer wall spacing. This also improves layer consistency.");
def->set_default_value(new ConfigOptionBool{false});
def->tooltip = L("Improve shell precision by adjusting outer wall spacing. This also improves layer consistency. NOTE: This option "
"will be ignored for outer-inner or inner-outer-inner wall sequences.");
def->set_default_value(new ConfigOptionBool{true});
def = this->add("only_one_wall_top", coBool);
def->label = L("Only one wall on top surfaces");
def->category = L("Quality");
@@ -1454,9 +1455,9 @@ void PrintConfigDef::init_fff_params()
def = this->add("brim_ears_detection_length", coFloat);
def->label = L("Brim ear detection radius");
def->category = L("Support");
def->tooltip = L("The geometry will be decimated before detecting sharp angles. This parameter indicates the "
"minimum length of the deviation for the decimation. "
"\n0 to deactivate.");
def->tooltip = L("The geometry will be decimated before detecting sharp angles. "
"This parameter indicates the minimum length of the deviation for the decimation.\n"
"0 to deactivate.");
def->sidetext = "mm"; // milimeters, don't need translation
def->min = 0;
def->mode = comAdvanced;
@@ -2114,8 +2115,8 @@ void PrintConfigDef::init_fff_params()
def = this->add("default_filament_colour", coStrings);
def->label = L("Default color");
def->tooltip = L("Default filament color"
"\nRight click to reset value to system default.");
def->tooltip = L("Default filament color.\n"
"Right click to reset value to system default.");
def->gui_type = ConfigOptionDef::GUIType::color;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionStrings{""});
@@ -2567,6 +2568,13 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("extra_solid_infills", coString);
def->label = L("Insert solid layers");
def->category = L("Strength");
def->tooltip = L("Insert solid infill at specific layers. Use N to insert every Nth layer, N#K to insert K consecutive solid layers every N layers (K is optional, e.g. '5#' equals '5#1'), or a comma-separated list (e.g. 1,7,9) to insert at explicit layers. Layers are 1-based.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString());
// Infill multiline
def = this->add("fill_multiline", coInt);
@@ -2816,7 +2824,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("default_junction_deviation", coFloat);
def->label = L("Junction Deviation");
def->tooltip = L("Marlin Firmware Junction Deviation (replaces the traditional XY Jerk setting)");
def->tooltip = L("Marlin Firmware Junction Deviation (replaces the traditional XY Jerk setting).");
def->sidetext = "mm"; // milimeters, don't need translation
def->min = 0;
def->mode = comAdvanced;
@@ -3044,7 +3052,7 @@ void PrintConfigDef::init_fff_params()
"This is the fast and straight algorithm without unnecessary nozzle shake that gives a smooth pattern. "
"But it is more useful for forming loose walls in the entire they array.\n"
"Combined: Joint mode [Displacement] + [Extrusion]. The appearance of the walls is similar to [Displacement] Mode, but it leaves no pores between the perimeters.\n\n"
"Attention! The [Extrusion] and [Combined] modes works only the fuzzy_skin_thickness parameter not more than the thickness of printed loop."
"Attention! The [Extrusion] and [Combined] modes works only the fuzzy_skin_thickness parameter not more than the thickness of printed loop. "
"At the same time, the width of the extrusion for a particular layer should also not be below a certain level. "
"It is usually equal 15-25%% of a layer height. Therefore, the maximum fuzzy skin thickness with a perimeter width of 0.4 mm and a layer height of 0.2 mm will be 0.4-(0.2*0.25)=±0.35mm! "
"If you enter a higher parameter than this, the error Flow::spacing() will displayed, and the model will not be sliced. You can choose this number until this error is repeated." );
@@ -3366,35 +3374,37 @@ void PrintConfigDef::init_fff_params()
//Orca
def = this->add("sparse_infill_rotate_template", coString);
def->label = L("Sparse infill rotatation template");
def->label = L("Sparse infill rotation template");
def->category = L("Strength");
def->tooltip = L("This parameter adds a rotation of sparse infill direction to each layer according to the specified template. "
"The template is a comma-separated list of angles in degrees, e.g. '0,90'. "
"The first angle is applied to the first layer, the second angle to the second layer, and so on. "
"If there are more layers than angles, the angles will be repeated. Note that not all sparse infill patterns support rotation.");
def->tooltip = L("Rotate the sparse infill direction per layer using a template of angles. "
"Enter comma-separated degrees (e.g., '0,30,60,90'). "
"Angles are applied in order by layer and repeat when the list ends. "
"Advanced syntax is supported: '+5' rotates +5° every layer; '+5#5' rotates +5° every 5 layers. See the Wiki for details. "
"When a template is set, the standard infill direction setting is ignored. "
"Note: some infill patterns (e.g., Gyroid) control rotation themselves; use with care.");
def->sidetext = L("°");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString("0,90"));
def->set_default_value(new ConfigOptionString(""));
//Orca
def = this->add("solid_infill_rotate_template", coString);
def->label = L("Solid infill rotatation template");
def->label = L("Solid infill rotation template");
def->category = L("Strength");
def->tooltip = L("This parameter adds a rotation of solid infill direction to each layer according to the specified template. "
"The template is a comma-separated list of angles in degrees, e.g. '0,90'. "
"The first angle is applied to the first layer, the second angle to the second layer, and so on. "
"If there are more layers than angles, the angles will be repeated. Note that not all solid infill patterns support rotation.");
def->sidetext = L("°");
def->sidetext = "°"; // degrees, don't need translation
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString("0,90"));
def->set_default_value(new ConfigOptionString(""));
def = this->add("skeleton_infill_density", coPercent);
def->label = L("Skeleton infill density");
def->category = L("Strength");
def->tooltip = L("The remaining part of the model contour after removing a certain depth from the surface is called the skeleton. This parameter is used to adjust the density of this section."
"When two regions have the same sparse infill settings but different skeleton densities, their skeleton areas will develop overlapping sections."
"default is as same as infill density.");
def->tooltip = L("The remaining part of the model contour after removing a certain depth from the surface is called the skeleton. "
"This parameter is used to adjust the density of this section. "
"When two regions have the same sparse infill settings but different skeleton densities, their skeleton areas will develop overlapping sections. "
"Default is as same as infill density.");
def->sidetext = "%";
def->min = 0;
def->max = 100;
@@ -3404,9 +3414,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("skin_infill_density", coPercent);
def->label = L("Skin infill density");
def->category = L("Strength");
def->tooltip = L("The portion of the model's outer surface within a certain depth range is called the skin. This parameter is used to adjust the density of this section."
"When two regions have the same sparse infill settings but different skin densities, This area will not be split into two separate regions."
"default is as same as infill density.");
def->tooltip = L("The portion of the model's outer surface within a certain depth range is called the skin. "
"This parameter is used to adjust the density of this section. "
"When two regions have the same sparse infill settings but different skin densities, this area will not be split into two separate regions. "
"Default is as same as infill density.");
def->sidetext = "%";
def->min = 0;
def->max = 100;
@@ -3454,9 +3465,9 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloatOrPercent(100, true));
def = this->add("symmetric_infill_y_axis", coBool);
def->label = L("Symmetric infill y axis");
def->label = L("Symmetric infill Y axis");
def->category = L("Strength");
def->tooltip = L("If the model has two parts that are symmetric about the y-axis,"
def->tooltip = L("If the model has two parts that are symmetric about the Y axis,"
" and you want these parts to have symmetric textures, please click this option on one of the parts.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
@@ -3693,7 +3704,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("ironing_speed", coFloat);
def->label = L("Ironing speed");
def->category = L("Quality");
def->tooltip = L("Print speed of ironing lines");
def->tooltip = L("Print speed of ironing lines.");
def->sidetext = "mm/s"; // milimeters per second, don't need translation
def->min = 1;
def->mode = comAdvanced;
@@ -3858,7 +3869,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("machine_max_junction_deviation", coFloats);
def->full_label = L("Maximum Junction Deviation");
def->category = L("Machine limits");
def->tooltip = L("Maximum junction deviation (M205 J, only apply if JD > 0 for Marlin Firmware)");
def->tooltip = L("Maximum junction deviation (M205 J, only apply if JD > 0 for Marlin Firmware)");
def->sidetext = "mm"; // milimeters, don't need translation
def->min = 0;
def->mode = comAdvanced;
@@ -4044,7 +4055,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("nozzle_diameter", coFloats);
def->label = L("Nozzle diameter");
def->tooltip = L("Diameter of nozzle");
def->tooltip = L("The diameter of nozzle.");
def->sidetext = "mm"; // milimeters, don't need translation
def->mode = comAdvanced;
def->max = 100;
@@ -4218,7 +4229,7 @@ void PrintConfigDef::init_fff_params()
def->gui_type = ConfigOptionDef::GUIType::i_enum_open;
def->label = L("Walls");
def->category = L("Extruders");
def->tooltip = L("Filament to print walls");
def->tooltip = L("Filament to print walls.");
def->min = 1;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(1));
@@ -4277,7 +4288,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("printer_model", coString);
def->label = L("Printer type");
def->tooltip = L("Type of the printer");
def->tooltip = L("Type of the printer.");
def->set_default_value(new ConfigOptionString());
def->cli = ConfigOptionDef::nocli;
@@ -4812,10 +4823,10 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(80,true));
def = this->add("skirt_distance", coFloat);
def->label = L("Skirt distance");
def->tooltip = L("Distance from skirt to brim or object");
def->tooltip = L("The distance from the skirt to the brim or the object.");
def->sidetext = "mm"; // milimeters, don't need translation
def->min = 0;
def->max = 60;
@@ -4924,7 +4935,7 @@ void PrintConfigDef::init_fff_params()
def->gui_type = ConfigOptionDef::GUIType::i_enum_open;
def->label = L("Solid infill");
def->category = L("Extruders");
def->tooltip = L("Filament to print solid infill");
def->tooltip = L("Filament to print solid infill.");
def->min = 1;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(1));
@@ -5089,7 +5100,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("enable_filament_ramming", coBool);
def->label = L("Enable filament ramming");
def->tooltip = L("Enable filament ramming.");
def->tooltip = L("Enable filament ramming");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
@@ -5940,7 +5951,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("wipe_tower_rotation_angle", coFloat);
def->label = L("Wipe tower rotation angle");
def->tooltip = L("Wipe tower rotation angle with respect to x-axis.");
def->tooltip = L("Wipe tower rotation angle with respect to X axis.");
def->sidetext = "°"; // degrees, don't need translation
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.));
@@ -5994,7 +6005,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("wipe_tower_extra_rib_length", coFloat);
def->label = L("Extra rib length");
def->tooltip = L("Positive values can increase the size of the rib wall, while negative values can reduce the size."
def->tooltip = L("Positive values can increase the size of the rib wall, while negative values can reduce the size. "
"However, the size of the rib wall can not be smaller than that determined by the cleaning volume.");
def->sidetext = "mm"; // milimeters, don't need translation
def->max = 300;
@@ -6003,7 +6014,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("wipe_tower_rib_width", coFloat);
def->label = L("Rib width");
def->tooltip = L("Rib width");
def->tooltip = L("Rib width.");
def->sidetext = "mm"; // milimeters, don't need translation
def->mode = comAdvanced;
def->min = 0;
@@ -9345,7 +9356,7 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def->set_default_value(new ConfigOptionString());
def = this->add("load_filament_ids", coInts);
def->label = L("Load filament ids");
def->label = L("Load filament IDs");
def->tooltip = L("Load filament IDs for each object.");
def->cli_params = "\"1,2,3,1\"";
def->set_default_value(new ConfigOptionInts());
@@ -9373,25 +9384,25 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def = this->add("makerlab_name", coString);
def->label = L("MakerLab name");
def->tooltip = L("MakerLab name to generate this 3mf");
def->tooltip = L("MakerLab name to generate this 3mf.");
def->cli_params = "name";
def->set_default_value(new ConfigOptionString());
def = this->add("makerlab_version", coString);
def->label = L("MakerLab version");
def->tooltip = L("MakerLab version to generate this 3mf");
def->tooltip = L("MakerLab version to generate this 3mf.");
def->cli_params = "version";
def->set_default_value(new ConfigOptionString());
def = this->add("metadata_name", coStrings);
def->label = L("metadata name list");
def->tooltip = L("metadata name list added into 3mf");
def->tooltip = L("metadata name list added into 3mf.");
def->cli_params = "\"name1;name2;...\"";
def->set_default_value(new ConfigOptionStrings());
def = this->add("metadata_value", coStrings);
def->label = L("metadata value list");
def->tooltip = L("metadata value list added into 3mf");
def->tooltip = L("metadata value list added into 3mf.");
def->cli_params = "\"value1;value2;...\"";
def->set_default_value(new ConfigOptionStrings());
@@ -9741,11 +9752,11 @@ CustomGcodeSpecificConfigDef::CustomGcodeSpecificConfigDef()
def->tooltip = L("Index of the current layer. One-based (i.e. first layer is number 1).");
def = this->add("layer_z", coFloat);
def->label = L("Layer z");
def->label = L("Layer Z");
def->tooltip = L("Height of the current layer above the print bed, measured to the top of the layer.");
def = this->add("max_layer_z", coFloat);
def->label = L("Maximal layer z");
def->label = L("Maximal layer Z");
def->tooltip = L("Height of the last layer above the print bed.");
def = this->add("filament_extruder_id", coInt);
@@ -9755,32 +9766,32 @@ CustomGcodeSpecificConfigDef::CustomGcodeSpecificConfigDef()
// change_filament_gcode
new_def("previous_extruder", coInt, "Previous extruder", "Index of the extruder that is being unloaded. The index is zero based (first extruder has index 0).");
new_def("next_extruder", coInt, "Next extruder", "Index of the extruder that is being loaded. The index is zero based (first extruder has index 0).");
new_def("relative_e_axis", coBool, "Relative e-axis", "Indicates if relative positioning is being used");
new_def("toolchange_count", coInt, "Toolchange count", "The number of toolchanges throught the print");
new_def("relative_e_axis", coBool, "Relative e-axis", "Indicates if relative positioning is being used.");
new_def("toolchange_count", coInt, "Toolchange count", "The number of toolchanges throught the print.");
new_def("fan_speed", coNone, "", ""); //Option is no longer used and is zeroed by placeholder parser for compatability
new_def("old_retract_length", coFloat, "Old retract length", "The retraction length of the previous filament");
new_def("new_retract_length", coFloat, "New retract length", "The retraction lenght of the new filament");
new_def("old_retract_length_toolchange", coFloat, "Old retract length toolchange", "The toolchange retraction length of the previous filament");
new_def("new_retract_length_toolchange", coFloat, "New retract length toolchange", "The toolchange retraction length of the new filament");
new_def("old_filament_temp", coInt, "Old filament temp", "The old filament temp");
new_def("new_filament_temp", coInt, "New filament temp", "The new filament temp");
new_def("x_after_toolchange", coFloat, "X after toolchange", "The x pos after toolchange");
new_def("y_after_toolchange", coFloat, "Y after toolchange", "The y pos after toolchange");
new_def("z_after_toolchange", coFloat, "Z after toolchange", "The z pos after toolchange");
new_def("first_flush_volume", coFloat, "First flush volume", "The first flush volume");
new_def("second_flush_volume", coFloat, "Second flush volume", "The second flush volume");
new_def("old_filament_e_feedrate", coInt, "Old filament e feedrate", "The old filament extruder feedrate");
new_def("new_filament_e_feedrate", coInt, "New filament e feedrate", "The new filament extruder feedrate");
new_def("travel_point_1_x", coFloat, "Travel point 1 x", "The travel point 1 x");
new_def("travel_point_1_y", coFloat, "Travel point 1 y", "The travel point 1 y");
new_def("travel_point_2_x", coFloat, "Travel point 2 x", "The travel point 2 x");
new_def("travel_point_2_y", coFloat, "Travel point 2 y", "The travel point 2 y");
new_def("travel_point_3_x", coFloat, "Travel point 3 x", "The travel point 3 x");
new_def("travel_point_3_y", coFloat, "Travel point 3 y", "The travel point 3 y");
new_def("flush_length_1", coFloat, "Flush Length 1", "The first flush length");
new_def("flush_length_2", coFloat, "Flush Length 2", "The second flush length");
new_def("flush_length_3", coFloat, "Flush Length 3", "The third flush length");
new_def("flush_length_4", coFloat, "Flush Length 4", "The fourth flush length");
new_def("old_retract_length", coFloat, "Old retract length", "The retraction length of the previous filament.");
new_def("new_retract_length", coFloat, "New retract length", "The retraction lenght of the new filament.");
new_def("old_retract_length_toolchange", coFloat, "Old retract length toolchange", "The toolchange retraction length of the previous filament.");
new_def("new_retract_length_toolchange", coFloat, "New retract length toolchange", "The toolchange retraction length of the new filament.");
new_def("old_filament_temp", coInt, "Old filament temp", "The old filament temp.");
new_def("new_filament_temp", coInt, "New filament temp", "The new filament temp.");
new_def("x_after_toolchange", coFloat, "X after toolchange", "The X pos after toolchange.");
new_def("y_after_toolchange", coFloat, "Y after toolchange", "The Y pos after toolchange.");
new_def("z_after_toolchange", coFloat, "Z after toolchange", "The Z pos after toolchange.");
new_def("first_flush_volume", coFloat, "First flush volume", "The first flush volume.");
new_def("second_flush_volume", coFloat, "Second flush volume", "The second flush volume.");
new_def("old_filament_e_feedrate", coInt, "Old filament e feedrate", "The old filament extruder feedrate.");
new_def("new_filament_e_feedrate", coInt, "New filament e feedrate", "The new filament extruder feedrate.");
new_def("travel_point_1_x", coFloat, "Travel point 1 X", "The travel point 1 X.");
new_def("travel_point_1_y", coFloat, "Travel point 1 Y", "The travel point 1 Y.");
new_def("travel_point_2_x", coFloat, "Travel point 2 X", "The travel point 2 X.");
new_def("travel_point_2_y", coFloat, "Travel point 2 Y", "The travel point 2 Y.");
new_def("travel_point_3_x", coFloat, "Travel point 3 X", "The travel point 3 X.");
new_def("travel_point_3_y", coFloat, "Travel point 3 Y", "The travel point 3 Y.");
new_def("flush_length_1", coFloat, "Flush Length 1", "The first flush length.");
new_def("flush_length_2", coFloat, "Flush Length 2", "The second flush length.");
new_def("flush_length_3", coFloat, "Flush Length 3", "The third flush length.");
new_def("flush_length_4", coFloat, "Flush Length 4", "The fourth flush length.");
// change_extrusion_role_gcode
std::string extrusion_role_types = "Possible Values:\n[\"Perimeter\", \"ExternalPerimeter\", "
+1
View File
@@ -1044,6 +1044,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, lateral_lattice_angle_2))
((ConfigOptionFloat, infill_overhang_angle))
((ConfigOptionBool, align_infill_direction_to_model))
((ConfigOptionString, extra_solid_infills))
((ConfigOptionEnum<FuzzySkinType>, fuzzy_skin))
((ConfigOptionFloat, fuzzy_skin_thickness))
((ConfigOptionFloat, fuzzy_skin_point_distance))
+7 -9
View File
@@ -1203,6 +1203,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "infill_direction"
|| opt_key == "solid_infill_direction"
|| opt_key == "align_infill_direction_to_model"
|| opt_key == "extra_solid_infills"
|| opt_key == "ensure_vertical_shell_thickness"
|| opt_key == "bridge_angle"
|| opt_key == "internal_bridge_angle" // ORCA: Internal bridge angle override
@@ -1268,7 +1269,6 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "overhang_reverse_internal_only"
|| opt_key == "overhang_reverse_threshold"
|| opt_key == "wall_direction"
//BBS
|| opt_key == "enable_overhang_speed"
|| opt_key == "detect_thin_wall"
|| opt_key == "precise_outer_wall") {
@@ -3613,16 +3613,14 @@ void PrintObject::discover_horizontal_shells()
Layer *layer = m_layers[i];
LayerRegion *layerm = layer->regions()[region_id];
const PrintRegionConfig &region_config = layerm->region().config();
#if 0
if (region_config.solid_infill_every_layers.value > 0 && region_config.sparse_infill_density.value > 0 &&
(i % region_config.solid_infill_every_layers) == 0) {
// Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge.
SurfaceType type = (region_config.sparse_infill_density == 100 || region_config.solid_infill_every_layers == 1) ? stInternalSolid : stInternalBridge;
for (Surface &surface : layerm->fill_surfaces.surfaces)
if (!region_config.extra_solid_infills.value.empty() &&
check_layer_id_pattern(region_config.extra_solid_infills.value, i)) {
// Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid.
for (Surface& surface : layerm->fill_surfaces.surfaces)
if (surface.surface_type == stInternal)
surface.surface_type = type;
surface.surface_type = stInternalSolid;
}
#endif
// If ensure_vertical_shell_thickness, then the rest has already been performed by discover_vertical_shells().
if (region_config.ensure_vertical_shell_thickness.value == evstAll)
+2
View File
@@ -695,6 +695,8 @@ void copy_directory_recursively(const boost::filesystem::path &source, const boo
void save_string_file(const boost::filesystem::path& p, const std::string& str);
void load_string_file(const boost::filesystem::path& p, std::string& str);
bool check_layer_id_pattern(const std::string& pattern, int layer_id);
} // namespace Slic3r
#if WIN32
+87
View File
@@ -1578,4 +1578,91 @@ void load_string_file(const boost::filesystem::path& p, std::string& str)
file.read(&str[0], sz);
}
// pattern string supprt these pattern: "
// 1. 5#1, insert 1 solid layer every 5 layers. this can be simplified to 5
// 2."1,7,9", explicitly insert solid layer at layer 1, 7, 9
bool check_layer_id_pattern(const std::string& pattern, int layer_id){
if (pattern.empty() || layer_id < 0)
return false;
// layer_id is 0-based, so we need to add 1 to make it 1-based
layer_id++;
// Remove whitespace and surrounding quotes.
std::string p; p.reserve(pattern.size());
for (char c : pattern) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
p.push_back(c);
}
if (!p.empty() && (p.front() == '"' || p.front() == '\''))
p.erase(p.begin());
if (!p.empty() && (p.back() == '"' || p.back() == '\''))
p.pop_back();
if (p.empty())
return false;
// Explicit list form: "1,7,9" or with counts per entry: "5,9#2,18"
if (p.find(',') != std::string::npos) {
size_t start = 0;
while (start < p.size()) {
size_t end = p.find(',', start);
std::string token = p.substr(start, (end == std::string::npos) ? std::string::npos : end - start);
if (!token.empty()) {
try {
size_t hash_pos_token = token.find('#');
if (hash_pos_token == std::string::npos) {
int value = std::stoi(token);
if (value == layer_id)
return true;
} else {
int base_layer = std::stoi(token.substr(0, hash_pos_token));
std::string count_str = token.substr(hash_pos_token + 1);
int local_count = 1;
if (!count_str.empty())
local_count = std::stoi(count_str);
if (base_layer > 0 && local_count > 0) {
if (layer_id >= base_layer && layer_id < base_layer + local_count)
return true;
}
}
} catch (...) {
// Ignore invalid tokens
}
}
if (end == std::string::npos)
break;
start = end + 1;
}
return false;
}
// Interval form: "N#K" or simplified "N" (equals to N#1)
int interval = 0;
int count = 1;
size_t hash_pos = p.find('#');
try {
if (hash_pos == std::string::npos) {
interval = std::stoi(p);
} else {
interval = std::stoi(p.substr(0, hash_pos));
std::string count_str = p.substr(hash_pos + 1);
if (!count_str.empty())
count = std::stoi(count_str);
}
} catch (...) {
return false;
}
if (interval <= 0 || count <= 0)
return false;
// Layers are 1-based. Match layers interval, interval+1, ..., interval+count-1, then repeat every interval.
if (layer_id < interval)
return false;
int mod = layer_id % interval; // For multiples, mod == 0
return mod >= 0 && mod < count;
}
}; // namespace Slic3r
+3 -6
View File
@@ -230,20 +230,17 @@ void Bed3D::Axes::render()
shader->start_using();
//shader->set_uniform("emission_factor", 0.0f);
// ORCA show axes on current plate
Vec3d plate_origin = wxGetApp().plater()->get_partplate_list().get_selected_plate()->get_origin();
// x axis
m_arrow.set_color(AXIS_X_COLOR);
render_axis(shader, Geometry::assemble_transform(plate_origin, { 0.0, 0.5 * M_PI, 0.0 }));
render_axis(shader, Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }));
// y axis
m_arrow.set_color(AXIS_Y_COLOR);
render_axis(shader, Geometry::assemble_transform(plate_origin, { -0.5 * M_PI, 0.0, 0.0 }));
render_axis(shader, Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }));
// z axis
m_arrow.set_color(AXIS_Z_COLOR);
render_axis(shader, Geometry::assemble_transform(plate_origin));
render_axis(shader, Geometry::assemble_transform(m_origin));
shader->stop_using();
+9 -20
View File
@@ -131,7 +131,7 @@ void ConfigManipulation::check_filament_max_volumetric_speed(DynamicPrintConfig
float max_volumetric_speed = config->has("filament_max_volumetric_speed") ? config->opt_float("filament_max_volumetric_speed", (float) 0.5) : 0.5;
// BBS: limite the min max_volumetric_speed
if (max_volumetric_speed < 0.5) {
const wxString msg_text = _(L("Too small max volumetric speed.\nReset to 0.5"));
const wxString msg_text = _(L("Too small max volumetric speed.\nReset to 0.5."));
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -188,7 +188,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
auto gpreset = GUI::wxGetApp().preset_bundle->printers.get_edited_preset();
if (layer_height < EPSILON)
{
const wxString msg_text = _(L("Too small layer height.\nReset to 0.2"));
const wxString msg_text = _(L("Too small layer height.\nReset to 0.2."));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -202,7 +202,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
auto max_lh = gpreset.config.opt_float("max_layer_height",0);
if (max_lh > 0.2 && layer_height > max_lh+ EPSILON)
{
const wxString msg_text = wxString::Format(L"Too large layer height.\nReset to %0.3f", max_lh);
const wxString msg_text = wxString::Format(L"Too large layer height.\nReset to %0.3f.", max_lh);
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -215,7 +215,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
//BBS: ironing_spacing shouldn't be too small or equal to zero
if (config->opt_float("ironing_spacing") < 0.05)
{
const wxString msg_text = _(L("Too small ironing spacing.\nReset to 0.1"));
const wxString msg_text = _(L("Too small ironing spacing.\nReset to 0.1."));
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -226,7 +226,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
}
if (config->opt_float("support_ironing_spacing") < 0.05)
{
const wxString msg_text = _(L("Too small ironing spacing.\nReset to 0.1"));
const wxString msg_text = _(L("Too small ironing spacing.\nReset to 0.1."));
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -477,7 +477,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
// layer_height shouldn't be equal to zero
float skin_depth = config->opt_float("skin_infill_depth");
if (config->opt_float("infill_lock_depth") > skin_depth) {
const wxString msg_text = _(L("lock depth should smaller than skin depth.\nReset to 50% of skin depth"));
const wxString msg_text = _(L("Lock depth should smaller than skin depth.\nReset to 50% of skin depth."));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -883,20 +883,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "lateral_lattice_angle_1", "lateral_lattice_angle_2"})
toggle_line(el, lattice_options);
//Orca: hide rotate template for solid infill if not support
const auto _sparse_infill_pattern = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
bool show_sparse_infill_rotate_template = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
_sparse_infill_pattern == ipLockedZag;
toggle_line("sparse_infill_rotate_template", show_sparse_infill_rotate_template);
//Orca: hide rotate template for solid infill if not support
const auto _solid_infill_pattern = config->option<ConfigOptionEnum<InfillPattern>>("internal_solid_infill_pattern")->value;
bool show_solid_infill_rotate_template = _solid_infill_pattern == ipRectilinear || _solid_infill_pattern == ipMonotonic ||
_solid_infill_pattern == ipMonotonicLine || _solid_infill_pattern == ipAlignedRectilinear;
toggle_line("solid_infill_rotate_template", show_solid_infill_rotate_template);
//Orca: disable infill_direction/solid_infill_direction if sparse_infill_rotate_template/solid_infill_rotate_template is not empty value
toggle_field("infill_direction", config->opt_string("sparse_infill_rotate_template") == "");
toggle_field("solid_infill_direction", config->opt_string("solid_infill_rotate_template") == "");
toggle_line("infill_overhang_angle", config->opt_enum<InfillPattern>("sparse_infill_pattern") == InfillPattern::ipLateralHoneycomb);
+1 -1
View File
@@ -3547,7 +3547,7 @@ std::string ExportConfigsDialog::initial_file_name(const wxString &path, const s
}
catch(...) {
MessageDialog dlg(this,
wxString::Format(_L("The file: %s \nmay have been opened by another program. \nPlease close it and try again."),
wxString::Format(_L("The file: %s\nmay have been opened by another program.\nPlease close it and try again."),
encode_path(printer_export_path.string().c_str())),
wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE);
dlg.ShowModal();
+16 -8
View File
@@ -437,15 +437,9 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
string v;
std::smatch match;
string ps = (m_opt.opt_key == "sparse_infill_rotate_template") ?
u8"[SODMR]?[BT][!]?|[SODMR]?[#][\\d]+[!]?|[+\\-]?[\\d.]+[%]?[*]?[\\d]*[SODMR]?[/NnZz$LlUuQq~^|#]?[+\\-]?[\\d.]*[%#\'\"cm]?[m]?[BT]?[!*]?" :
u8"[BT][!]?|[#][\\d]+[!]?|[+\\-]?[\\d.]+[%]?[*]?[\\d]*[/NnZz$LlUuQq~^|#]?[+\\-]?[\\d.]*[%#\'\"cm]?[m]?[BT]?[!*]?" :
u8"[#][\\d]+[!]?|[+\\-]?[\\d.]+[%]?[*]?[\\d]*[/NnZz$LlUuQq~^|#]?[+\\-]?[\\d.]*[%#\'\"cm]?[m]?[!*]?";
//if (m_opt.opt_key == "sparse_infill_rotate_template") {
//string ps = u8"[#][\\d]+[!]?|[+\\-]?[\\d.]+[%]?[*]?[\\d]*[SODMR]?[/NnZz$LlUuQq~^|#]?[+\\-]?[\\d.]*[%#\'\"cm]?[m]?[";
//if (m_opt.opt_key == "sparse_infill_rotate_template") {
// ps = u8"[BT][!]?|" + ps ;
//}
//ps += u8"BT]?[!*]?";
while (std::regex_search(ustr, match, std::regex(ps))) {
for (auto x : match) v += x.str() + ", ";
ustr = match.suffix().str();
@@ -458,13 +452,27 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
show_error(m_parent, format_wxstr(_L("This parameter expects a valid template.")));
wxString old_value(boost::any_cast<std::string>(m_value));
this->set_value(old_value, true); // Revert to previous value
throw;
}
} else {
// Valid string, so update m_value with the new string from the control.
m_value = into_u8(str);
}
break;
} else if (m_opt.opt_key == "extra_solid_infills") {
string ustr(str.utf8_string());
// New rule: accept either interval form (N or N#K) or explicit list (e.g. 1,7,9), with optional quotes.
const std::regex rx_interval(u8R"(^\s*['"]?\s*\d+\s*(?:#\s*\d*)?\s*['"]?\s*$)");
// List entries may be plain numbers or number with optional #K count, e.g., 5, 9#2, 18
const std::regex rx_list(u8R"(^\s*['"]?\s*\d+(?:\s*#\s*\d*)?(?:\s*,\s*\d+(?:\s*#\s*\d*)?)*\s*['"]?\s*$)");
bool is_valid = ustr.empty() || std::regex_match(ustr, rx_interval) || std::regex_match(ustr, rx_list);
if (!is_valid) {
show_error(m_parent, format_wxstr(_L("Invalid pattern. Use N, N#K, or a comma-separated list with optional #K per entry. Examples: 5, 5#2, 1,7,9, 5,9#2,18.")));
wxString old_value(boost::any_cast<std::string>(m_value));
this->set_value(old_value, true); // Revert to previous value
}
// Valid string or empty, so update m_value with the new string from the control.
m_value = into_u8(str);
break;
}
m_value = into_u8(str);
+23 -22
View File
@@ -4676,6 +4676,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
const ColorRGBA& color,
const std::vector<std::pair<std::string, float>>& columns_offsets,
bool checkbox = true,
float checkbox_pos = 0.f, // ORCA use calculated value for eye icon. Aligned to "Display" header or end of combo box
bool visible = true,
std::function<void()> callback = nullptr)
{
@@ -4728,14 +4729,14 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
if (b_menu_item)
callback();
if (checkbox) {
//ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::CalcTextSize(_u8L("Display").c_str()).x / 2 - ImGui::GetFrameHeight() / 2 - 2 * window_padding);
//ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0, 0.0));
//ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
//ImGui::Checkbox(("##" + columns_offsets[0].first).c_str(), &visible);
//ImGui::PopStyleVar(1);
// ORCA replace checkboxes with eye icon
ImGui::SameLine(ImGui::GetWindowWidth() - (16.f + 6.f) * m_scale - window_padding * 2 - (ImGui::GetScrollMaxY() > 0.0f ? ImGui::GetStyle().ScrollbarSize : 0));
// Use calculated position from argument. this method has predictable result compared to alingning button using window width
// fixes slowly resizing window and endlessly expanding window when there is a miscalculation on position
ImGui::SameLine(checkbox_pos);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0, 0.0)); // ensure no padding active
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0, 0.0)); // ensure no item spacing active
ImGui::Text(into_u8(visible ? ImGui::VisibleIcon : ImGui::HiddenIcon).c_str(), ImVec2(16 * m_scale, 16 * m_scale));
ImGui::PopStyleVar(2);
}
}
@@ -4785,7 +4786,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
for (size_t i = 0; i < title_offsets.size(); i++) {
if (title_offsets[i].first == _u8L("Display")) { // ORCA Hide Display header
ImGui::SameLine(title_offsets[i].second);
ImGui::Dummy({16.f * m_scale, 1}); // 16(icon)
ImGui::Dummy({16.f * m_scale, 1}); // 16(icon_size)
continue;
}
ImGui::SameLine(title_offsets[i].second);
@@ -4809,16 +4810,11 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
const ImGuiStyle& style = ImGui::GetStyle();
std::vector<float> offsets;
// ORCA increase spacing for more readable format. Using direct number requires much less code change in here. GetTextLineHeight for additional spacing for icon_size
offsets.push_back(max_width(title_columns[0].second, title_columns[0].first, extra_size) + 12.f * m_scale + ImGui::GetTextLineHeight());
for (size_t i = 1; i < title_columns.size() - 1; i++)
offsets.push_back(offsets.back() + max_width(title_columns[i].second, title_columns[i].first) + 12.f * m_scale); // ORCA increase spacing for more readable format. Using direct number requires much less code change in here
if (title_columns.back().first == _u8L("Display")) {
//const auto preferred_offset = ImGui::GetWindowWidth() - ImGui::CalcTextSize(_u8L("Display").c_str()).x - ImGui::GetFrameHeight() / 2 - 2 * window_padding - ImGui::GetStyle().ScrollbarSize;
const auto preferred_offset = ImGui::GetWindowWidth() - (16.f - 6.f) * m_scale - ImGui::GetFrameHeight() / 2 - 2 * window_padding - (ImGui::GetScrollMaxY() > 0.0f ? ImGui::GetStyle().ScrollbarSize : 0);
if (preferred_offset > offsets.back()) {
offsets.back() = preferred_offset;
}
}
offsets.push_back(max_width(title_columns[0].second, title_columns[0].first, extra_size) + 12.f * m_scale + ImGui::GetTextLineHeight());
for (size_t i = 1; i < title_columns.size() - 1; i++) // ORCA dont add extra spacing after icon / "Display" header
offsets.push_back(offsets.back() + max_width(title_columns[i].second, title_columns[i].first) + ((title_columns[i].first == _u8L("Display") ? 0 : 12.f) * m_scale));
if (title_columns.back().first == _u8L("Display") && title_columns.size() > 2)
offsets[title_columns.size() - 2] -= 3.f; // ORCA reduce spacing after previous header
float average_col_width = ImGui::GetWindowWidth() / static_cast<float>(title_columns.size());
std::vector<float> ret;
@@ -4985,6 +4981,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
}
pop_combo_style();
ImGui::SameLine(0, window_padding); // ORCA Without (0,window_padding) it adds unnecessary item spacing after combo box
// ORCA predictable_icon_pos helpful when window size determined by combo box.
float predictable_icon_pos = ImGui::GetCursorPosX() - icon_size - window_padding - ImGui::GetStyle().ItemSpacing.x - 1.f * m_scale; // 1 for border
ImGui::Dummy({ window_padding, window_padding });
ImGui::Dummy({ window_padding, window_padding }); // ORCA Matches top-bottom window paddings
float window_width = ImGui::GetWindowWidth(); // ORCA Store window width
@@ -5192,6 +5190,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
if ((displayed_columns & ~ColumnData::Model) > 0) {
title_columns.push_back({ _u8L("Total"), total_filaments });
}
title_columns.push_back({ _u8L("Display"), {""}}); // ORCA Add spacing for eye icon. used as color_print_offsets[_u8L("Display")]
auto offsets_ = calculate_offsets(title_columns, icon_size);
std::vector<std::pair<std::string, float>> title_offsets;
for (int i = 0; i < offsets_.size(); i++) {
@@ -5207,7 +5206,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
auto append_option_item = [this, append_item](EMoveType type, std::vector<float> offsets) {
auto append_option_item_with_type = [this, offsets, append_item](EMoveType type, const ColorRGBA& color, const std::string& label, bool visible) {
append_item(EItemType::Rect, color, {{ label , offsets[0] }}, true, visible, [this, type, visible]() {
append_item(EItemType::Rect, color, {{ label , offsets[0] }}, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, type, visible]() {
m_buffers[buffer_id(type)].visible = !m_buffers[buffer_id(type)].visible;
// update buffers' render paths
refresh_render_paths(false, false);
@@ -5249,7 +5248,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
columns_offsets.push_back({used_filaments_length[i], offsets[3]});
columns_offsets.push_back({used_filaments_weight[i], offsets[4]});
append_item(EItemType::Rect, Extrusion_Role_Colors[static_cast<unsigned int>(role)], columns_offsets,
true, visible, [this, role, visible]() {
true, offsets.back(), visible, [this, role, visible]() {
m_extrusions.role_visibility_flags = visible ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role);
// update buffers' render paths
refresh_render_paths(false, false);
@@ -5268,7 +5267,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
columns_offsets.push_back({ _u8L("Travel"), offsets[0] });
columns_offsets.push_back({ travel_time, offsets[1] });
columns_offsets.push_back({ travel_percent, offsets[2] });
append_item(EItemType::Rect, Travel_Colors[0], columns_offsets, true, visible, [this, item, visible]() {
append_item(EItemType::Rect, Travel_Colors[0], columns_offsets, true, offsets.back()/*ORCA checkbox_pos*/, visible, [this, item, visible]() {
m_buffers[buffer_id(item)].visible = !m_buffers[buffer_id(item)].visible;
// update buffers' render paths
refresh_render_paths(false, false);
@@ -5290,7 +5289,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
const bool travel_visible = m_buffers[buffer_id(EMoveType::Travel)].visible;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
append_item(EItemType::None, Travel_Colors[0], { {_u8L("travel"), offsets[0] }}, true, travel_visible, [this, travel_visible]() {
append_item(EItemType::None, Travel_Colors[0], { {_u8L("travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
m_buffers[buffer_id(EMoveType::Travel)].visible = !m_buffers[buffer_id(EMoveType::Travel)].visible;
// update buffers' render paths, and update m_tools.m_tool_colors and m_extrusions.ranges
refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result));
@@ -5398,7 +5397,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
columns_offsets.push_back({ buf, color_print_offsets[_u8L("Total")] });
}
append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_idx], columns_offsets, false, filament_visible, [this, extruder_idx]() {
float checkbox_pos = std::max(predictable_icon_pos, color_print_offsets[_u8L("Display")]); // ORCA prefer predictable_icon_pos when header not reacing end
append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_idx], columns_offsets, true, checkbox_pos/*ORCA*/, filament_visible, [this, extruder_idx]() {
m_tools.m_tool_visibles[extruder_idx] = !m_tools.m_tool_visibles[extruder_idx];
// update buffers' render paths
refresh_render_paths(false, false);
@@ -5993,6 +5993,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
ImGui::Dummy({ window_padding, window_padding });
ImGui::SameLine();
offsets = calculate_offsets({ { _u8L("Options"), { ""}}, { _u8L("Display"), {""}} }, icon_size);
offsets[1] = std::max(predictable_icon_pos, color_print_offsets[_u8L("Display")]); // ORCA prefer predictable_icon_pos when header not reacing end
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
for (auto item : options_items)
append_option_item(item, offsets);
+9 -8
View File
@@ -328,10 +328,10 @@ void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanv
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + canvas.m_main_toolbar.get_height();
std::map<wxString, wxString> captions_texts = {
{_L("Left mouse button:") ,_L("Add detail")},
{_L("Right mouse button:"), _L("Remove detail")},
{_L("Shift + Left mouse button:"),_L("Reset to base")},
{_L("Shift + Right mouse button:"), _L("Smoothing")},
{_L("Left mouse button") + ":" , _L("Add detail")},
{_L("Right mouse button") + ":", _L("Remove detail")},
{_L("Shift+") + _L("Left mouse button") + ":", _L("Reset to base")},
{_L("Shift+") + _L("Right mouse button") + ":", _L("Smoothing")},
{_L("Mouse wheel:"), _L("Increase/decrease edit area")}
};
show_tooltip_information(canvas, captions_texts, x, get_cur_y);
@@ -1196,8 +1196,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
m_assembly_view_desc["object_selection_caption"] = _L("Left mouse button");
m_assembly_view_desc["object_selection"] = _L("object selection");
m_assembly_view_desc["part_selection_caption"] = "Alt +" + _L("Left mouse button");
m_assembly_view_desc["part_selection"] = _L("part selectiont");
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button");
m_assembly_view_desc["part_selection"] = _L("part selection");
m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys");
m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects");
}
@@ -6679,7 +6680,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "orient";
item.icon_filename = m_is_dark ? "toolbar_orient_dark.svg" : "toolbar_orient.svg";
item.tooltip = _utf8(L("Auto orient all/selected objects")) + " [Q]\n" + _utf8(L("Auto orient all objects on current plate")) + " [Shift+Q]";
item.tooltip = _utf8(L("Auto orient all/selected objects")) + " [Q]\n" + _utf8(L("Auto orient all objects on current plate")) + " [" + _utf8(L("Shift+")) + "Q]";
item.sprite_id++;
item.left.render_callback = nullptr;
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
@@ -6701,7 +6702,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "arrange";
item.icon_filename = m_is_dark ? "toolbar_arrange_dark.svg" : "toolbar_arrange.svg";
item.tooltip = _utf8(L("Arrange all objects")) + " [A]\n" + _utf8(L("Arrange objects on selected plates")) + " [Shift+A]";
item.tooltip = _utf8(L("Arrange all objects")) + " [A]\n" + _utf8(L("Arrange objects on selected plates")) + " [" + _utf8(L("Shift+")) + "A]";
item.sprite_id++;
item.left.action_callback = []() {};
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
+3 -3
View File
@@ -82,7 +82,7 @@ const std::string& shortkey_ctrl_prefix()
{
static const std::string str =
#ifdef __APPLE__
"⌘+"
u8"\u2318+" // "⌘+" (Mac Command+)
#else
_u8L("Ctrl+")
#endif
@@ -94,9 +94,9 @@ const std::string& shortkey_alt_prefix()
{
static const std::string str =
#ifdef __APPLE__
"⌥+"
u8"\u2325+" // "⌥+" (Mac Option+)
#else
"Alt+"
_u8L("Alt+")
#endif
;
return str;
+3 -1
View File
@@ -108,6 +108,7 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::PART_CAT
{"bottom_shell_layers", L("Bottom Solid Layers"),1}, {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"),1},{"bottom_surface_density", L("Bottom Surface Density"),1},
{"sparse_infill_density", "",1},{"sparse_infill_pattern", "",1},{"lateral_lattice_angle_1", "",1},{"lateral_lattice_angle_2", "",1},{"infill_overhang_angle", "",1},{"infill_anchor", "",1},{"infill_anchor_max", "",1},{"top_surface_pattern", "",1},{"bottom_surface_pattern", "",1}, {"internal_solid_infill_pattern", "",1},
{"align_infill_direction_to_model", "", 1},
{"extra_solid_infills", "", 1},
{"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1}
}},
{ L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5},
@@ -488,7 +489,7 @@ void MenuFactory::append_menu_item_delete(wxMenu* menu)
[](wxCommandEvent&) { plater()->remove_selected(); }, "menu_delete", nullptr,
[]() { return plater()->can_delete(); }, m_parent);
#else
append_menu_item(menu, wxID_ANY, _L("Delete") + "\tBackSpace", _L("Delete the selected object"),
append_menu_item(menu, wxID_ANY, _L("Delete") + "\t" + _L("Backspace"), _L("Delete the selected object"),
[](wxCommandEvent&) { plater()->remove_selected(); }, "", nullptr,
[]() { return plater()->can_delete(); }, m_parent);
#endif
@@ -1838,6 +1839,7 @@ void MenuFactory::append_menu_item_clone(wxMenu* menu)
#ifdef __APPLE__
static const wxString ctrl = ("Ctrl+");
#else
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
static const wxString ctrl = _L("Ctrl+");
#endif
append_menu_item(menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "",
+1 -1
View File
@@ -357,7 +357,7 @@ bool GLGizmoAdvancedCut::on_init()
// initiate info shortcuts
const wxString ctrl = GUI::shortkey_ctrl_prefix();
const wxString alt = GUI::shortkey_alt_prefix();
const wxString shift = "Shift+";
const wxString shift = _L("Shift+");
m_shortcuts.push_back(std::make_pair(_L("Left click"), _L("Add connector")));
m_shortcuts.push_back(std::make_pair(_L("Right click"), _L("Remove connector")));
+7 -3
View File
@@ -40,11 +40,15 @@ GLGizmoBrimEars::GLGizmoBrimEars(GLCanvas3D &parent, const std::string &icon_fil
bool GLGizmoBrimEars::on_init()
{
m_new_point_head_diameter = get_brim_default_radius();
m_shortcut_key = WXK_CONTROL_E;
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
const wxString ctrl = _L("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
const wxString alt = _L("Alt+");
m_desc["head_diameter"] = _L("Head diameter");
m_desc["max_angle"] = _L("Max angle");
m_desc["detection_radius"] = _L("Detection radius");
@@ -57,9 +61,9 @@ bool GLGizmoBrimEars::on_init()
m_desc["left_click"] = _L("Add a brim ear");
m_desc["right_click_caption"] = _L("Right click");
m_desc["right_click"] = _L("Delete a brim ear");
m_desc["ctrl_mouse_wheel_caption"] = _L("Ctrl+Mouse wheel");
m_desc["ctrl_mouse_wheel_caption"] = ctrl + _L("Mouse wheel");
m_desc["ctrl_mouse_wheel"] = _L("Adjust head diameter");
m_desc["alt_mouse_wheel_caption"] = _L("Alt + Mouse wheel");
m_desc["alt_mouse_wheel_caption"] = alt + _L("Mouse wheel");
m_desc["alt_mouse_wheel"] = _L("Adjust section view");
return true;
+1 -1
View File
@@ -1183,7 +1183,7 @@ bool GLGizmoCut3D::on_init()
// initiate info shortcuts
const wxString ctrl = GUI::shortkey_ctrl_prefix();
const wxString alt = GUI::shortkey_alt_prefix();
const wxString shift = "Shift+";
const wxString shift = _L("Shift+");
m_shortcuts_cut.push_back(std::make_pair(shift + _L("Drag"), _L("Draw cut line")));
+11 -5
View File
@@ -79,25 +79,31 @@ bool GLGizmoFdmSupports::on_init()
// BBS
m_shortcut_key = WXK_CONTROL_L;
m_desc["clipping_of_view_caption"] = _L("Alt + Mouse wheel");
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
const wxString ctrl = _L("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
const wxString alt = _L("Alt+");
const wxString shift = _L("Shift+");
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
m_desc["clipping_of_view"] = _L("Section view");
m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size_caption"] = _L("Ctrl + Mouse wheel");
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
m_desc["cursor_size"] = _L("Pen size");
m_desc["enforce_caption"] = _L("Left mouse button");
m_desc["enforce"] = _L("Enforce supports");
m_desc["block_caption"] = _L("Right mouse button");
m_desc["block"] = _L("Block supports");
m_desc["remove_caption"] = _L("Shift + Left mouse button");
m_desc["remove_caption"] = shift + _L("Left mouse button");
m_desc["remove"] = _L("Erase");
m_desc["remove_all"] = _L("Erase all painting");
m_desc["highlight_by_angle"] = _L("Highlight overhang areas");
m_desc["gap_fill"] = _L("Gap fill");
m_desc["perform"] = _L("Perform");
m_desc["gap_area_caption"] = _L("Ctrl + Mouse wheel");
m_desc["gap_area_caption"] = ctrl + _L("Mouse wheel");
m_desc["gap_area"] = _L("Gap area");
m_desc["tool_type"] = _L("Tool type");
m_desc["smart_fill_angle_caption"] = _L("Ctrl + Mouse wheel");
m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel");
m_desc["smart_fill_angle"] = _L("Smart fill angle");
m_desc["on_overhangs_only"] = _L("On overhangs only");
+10 -4
View File
@@ -31,15 +31,21 @@ bool GLGizmoFuzzySkin::on_init()
{
m_shortcut_key = WXK_CONTROL_H;
m_desc["clipping_of_view_caption"] = _L("Alt + Mouse wheel");
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
const wxString ctrl = _L("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
const wxString alt = _L("Alt+");
const wxString shift = _L("Shift+");
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
m_desc["clipping_of_view"] = _L("Section view");
m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size_caption"] = _L("Ctrl + Mouse wheel");
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
m_desc["cursor_size"] = _L("Brush size");
m_desc["cursor_type"] = _L("Brush shape") ;
m_desc["add_fuzzy_skin_caption"] = _L("Left mouse button");
m_desc["add_fuzzy_skin"] = _L("Add fuzzy skin");
m_desc["remove_fuzzy_skin_caption"] = _L("Shift + Left mouse button");
m_desc["remove_fuzzy_skin_caption"] = shift + _L("Left mouse button");
m_desc["remove_fuzzy_skin"] = _L("Remove fuzzy skin");
m_desc["remove_all"] = _L("Erase all painting");
m_desc["circle"] = _L("Circle");
@@ -48,7 +54,7 @@ bool GLGizmoFuzzySkin::on_init()
m_desc["tool_type"] = _L("Tool type");
m_desc["tool_brush"] = _L("Brush");
m_desc["tool_smart_fill"] = _L("Smart fill");
m_desc["smart_fill_angle_caption"] = _L("Ctrl + Mouse wheel");
m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel");
m_desc["smart_fill_angle"] = _L("Smart fill angle");
return true;
+3 -1
View File
@@ -444,8 +444,10 @@ bool GLGizmoMeasure::on_init()
{
m_shortcut_key = WXK_CONTROL_U;
const wxString shift = _L("Shift+");
m_desc["feature_selection"] = _L("Select feature");
m_desc["point_selection_caption"] = _L("Shift + Left mouse button");
m_desc["point_selection_caption"] = shift + _L("Left mouse button");
m_desc["point_selection"] = _L("Select point");
m_desc["reset_caption"] = _L("Delete");
m_desc["reset"] = _L("Restart selection");
@@ -88,21 +88,27 @@ bool GLGizmoMmuSegmentation::on_init()
// BBS
m_shortcut_key = WXK_CONTROL_N;
m_desc["clipping_of_view_caption"] = _L("Alt + Mouse wheel");
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
const wxString ctrl = _L("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
const wxString alt = _L("Alt+");
const wxString shift = _L("Shift+");
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
m_desc["clipping_of_view"] = _L("Section view");
m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size_caption"] = _L("Ctrl + Mouse wheel");
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
m_desc["cursor_size"] = _L("Pen size");
m_desc["cursor_type"] = _L("Pen shape");
m_desc["paint_caption"] = _L("Left mouse button");
m_desc["paint"] = _L("Paint");
m_desc["erase_caption"] = _L("Shift + Left mouse button");
m_desc["erase_caption"] = shift + _L("Left mouse button");
m_desc["erase"] = _L("Erase");
m_desc["shortcut_key_caption"] = _L("Key 1~9");
m_desc["shortcut_key"] = _L("Choose filament");
m_desc["edge_detection"] = _L("Edge detection");
m_desc["gap_area_caption"] = _L("Ctrl + Mouse wheel");
m_desc["gap_area_caption"] = ctrl + _L("Mouse wheel");
m_desc["gap_area"] = _L("Gap area");
m_desc["perform"] = _L("Perform");
@@ -117,14 +123,14 @@ bool GLGizmoMmuSegmentation::on_init()
m_desc["tool_smart_fill"] = _L("Smart fill");
m_desc["tool_bucket_fill"] = _L("Bucket fill");
m_desc["smart_fill_angle_caption"] = _L("Ctrl + Mouse wheel");
m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel");
m_desc["smart_fill_angle"] = _L("Smart fill angle");
m_desc["height_range_caption"] = _L("Ctrl + Mouse wheel");
m_desc["height_range_caption"] = ctrl + _L("Mouse wheel");
m_desc["height_range"] = _L("Height range");
//add toggle wire frame hint
m_desc["toggle_wireframe_caption"] = _L("Alt + Shift + Enter");
m_desc["toggle_wireframe_caption"] = alt + shift + _L("Enter");
m_desc["toggle_wireframe"] = _L("Toggle Wireframe");
// Filament remapping descriptions
+9 -3
View File
@@ -29,17 +29,23 @@ bool GLGizmoSeam::on_init()
{
m_shortcut_key = WXK_CONTROL_P;
m_desc["clipping_of_view_caption"] = _L("Alt + Mouse wheel");
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
const wxString ctrl = _L("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
const wxString alt = _L("Alt+");
const wxString shift = _L("Shift+");
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
m_desc["clipping_of_view"] = _L("Section view");
m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size_caption"] = _L("Ctrl + Mouse wheel");
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
m_desc["cursor_size"] = _L("Brush size");
m_desc["cursor_type"] = _L("Brush shape");
m_desc["enforce_caption"] = _L("Left mouse button");
m_desc["enforce"] = _L("Enforce seam");
m_desc["block_caption"] = _L("Right mouse button");
m_desc["block"] = _L("Block seam");
m_desc["remove_caption"] = _L("Shift + Left mouse button");
m_desc["remove_caption"] = shift + _L("Left mouse button");
m_desc["remove"] = _L("Erase");
m_desc["remove_all"] = _L("Erase all painting");
m_desc["circle"] = _L("Circle");
+6 -5
View File
@@ -1175,9 +1175,10 @@ SlaGizmoHelpDialog::SlaGizmoHelpDialog()
: wxDialog(nullptr, wxID_ANY, _L("SLA gizmo keyboard shortcuts"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
const wxString ctrl = GUI::shortkey_ctrl_prefix();
const wxString alt = GUI::shortkey_alt_prefix();
const wxString shift = _L("Shift+");
// fonts
const wxFont& font = wxGetApp().small_font();
@@ -1206,14 +1207,14 @@ SlaGizmoHelpDialog::SlaGizmoHelpDialog()
shortcuts.push_back(std::make_pair(_L("Drag"), _L("Move point")));
shortcuts.push_back(std::make_pair(ctrl+_L("Left click"), _L("Add point to selection")));
shortcuts.push_back(std::make_pair(alt+_L("Left click"), _L("Remove point from selection")));
shortcuts.push_back(std::make_pair(wxString("Shift+")+_L("Drag"), _L("Select by rectangle")));
shortcuts.push_back(std::make_pair(shift+_L("Drag"), _L("Select by rectangle")));
shortcuts.push_back(std::make_pair(alt+_(L("Drag")), _L("Deselect by rectangle")));
shortcuts.push_back(std::make_pair(ctrl+"A", _L("Select all points")));
shortcuts.push_back(std::make_pair("Delete", _L("Remove selected points")));
shortcuts.push_back(std::make_pair(_L"Del", _L("Remove selected points")));
shortcuts.push_back(std::make_pair(ctrl+_L("Mouse wheel"), _L("Move clipping plane")));
shortcuts.push_back(std::make_pair("R", _L("Reset clipping plane")));
shortcuts.push_back(std::make_pair("Enter", _L("Apply changes")));
shortcuts.push_back(std::make_pair("Esc", _L("Discard changes")));
shortcuts.push_back(std::make_pair(_L("Enter"), _L("Apply changes")));
shortcuts.push_back(std::make_pair(_L("Esc"), _L("Discard changes")));
shortcuts.push_back(std::make_pair("M", _L("Switch to editing mode")));
shortcuts.push_back(std::make_pair("A", _L("Auto-generate points")));
+1 -1
View File
@@ -278,7 +278,7 @@ bool GLGizmoText::on_init()
m_desc["surface"] = _L("Surface");
m_desc["horizontal_text"] = _L("Horizontal text");
m_desc["rotate_text_caption"] = _L("Shift + Mouse move up or down");
m_desc["rotate_text_caption"] = _L("Shift+") + _L("Mouse move up or down");
m_desc["rotate_text"] = _L("Rotate text");
return true;
@@ -55,9 +55,10 @@ GizmoObjectManipulation::GizmoObjectManipulation(GLCanvas3D& glcanvas)
m_imperial_units = wxGetApp().app_config->get("use_inches") == "1";
m_new_unit_string = m_imperial_units ? L("in") : L("mm");
const wxString shift = "Shift+";
const wxString shift = _L("Shift+");
const wxString alt = GUI::shortkey_alt_prefix();
const wxString ctrl = GUI::shortkey_ctrl_prefix();
m_desc_move["part_selection_caption"] = alt + _L("Left mouse button");
m_desc_move["part_selection"] = _L("Part selection");
m_desc_move["snap_step_caption"] = shift + _L("Left mouse button");
+24 -45
View File
@@ -163,8 +163,9 @@ void KBShortcutsDialog::on_dpi_changed(const wxRect& suggested_rect)
void KBShortcutsDialog::fill_shortcuts()
{
const std::string& ctrl = GUI::shortkey_ctrl_prefix();
const std::string& alt = GUI::shortkey_alt_prefix();
const std::string ctrl = GUI::shortkey_ctrl_prefix();
const std::string alt = GUI::shortkey_alt_prefix();
const std::string shift = L("Shift+");
if (wxGetApp().is_editor()) {
Shortcuts global_shortcuts = {
@@ -172,7 +173,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ ctrl + "N", L("New Project") },
{ ctrl + "O", L("Open Project") },
{ ctrl + "S", L("Save Project") },
{ ctrl + "Shift+S", L("Save Project as")},
{ ctrl + shift + "S", L("Save Project as")},
// File>Import
{ ctrl + "I", L("Import geometry data from STL/STEP/3MF/OBJ/AMF files") },
// File>Export
@@ -180,12 +181,7 @@ void KBShortcutsDialog::fill_shortcuts()
// Slice plate
{ ctrl + "R", L("Slice plate")},
// Send to Print
#ifdef __APPLE__
{ L("⌘+Shift+G"), L("Print plate")},
#else
{ L("Ctrl+Shift+G"), L("Print plate")},
#endif // __APPLE
{ ctrl + shift + "G", L("Print plate")},
// Edit
{ ctrl + "X", L("Cut") },
{ ctrl + "C", L("Copy to clipboard") },
@@ -194,13 +190,13 @@ void KBShortcutsDialog::fill_shortcuts()
{ ctrl + "P", L("Preferences") },
//3D control
#ifdef __APPLE__
{ ctrl + "Shift+M", L("Show/Hide 3Dconnexion devices settings dialog") },
{ ctrl + shift + "M", L("Show/Hide 3Dconnexion devices settings dialog") },
#else
{ ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") },
#endif // __APPLE
// Switch table page
{ ctrl + "Tab", L("Switch table page")},
{ ctrl + L("Tab"), L("Switch table page")},
//DEL
#ifdef __APPLE__
{"fn+⌫", L("Delete selected")},
@@ -217,28 +213,21 @@ void KBShortcutsDialog::fill_shortcuts()
{ L("Right mouse button"), L("Pan View") },
{ L("Mouse wheel"), L("Zoom View") },
{ "A", L("Arrange all objects") },
{ L("Shift+A"), L("Arrange objects on selected plates") },
{ shift + "A", L("Arrange objects on selected plates") },
{ "Q", L("Auto orients selected objects or all objects. If there are selected objects, it just orients the selected ones. Otherwise, it will orient all objects in the current project.") },
{L("Shift+Q"), L("Auto orients all objects on the active plate.")},
{ shift + "Q", L("Auto orients all objects on the active plate.") },
{L("Shift+Tab"), L("Collapse/Expand the sidebar")},
#ifdef __APPLE__
{L("⌘+Any arrow"), L("Movement in camera space")},
{L("⌥+Left mouse button"), L("Select a part")},
{L("⌘+Left mouse button"), L("Select multiple objects")},
#else
{L("Ctrl+Any arrow"), L("Movement in camera space")},
{L("Alt+Left mouse button"), L("Select a part")},
{L("Ctrl+Left mouse button"), L("Select multiple objects")},
#endif
{L("Shift+Left mouse button"), L("Select objects by rectangle")},
{shift + L("Tab"), L("Collapse/Expand the sidebar")},
{ctrl + L("Any arrow"), L("Movement in camera space")},
{alt + L("Left mouse button"), L("Select a part")},
{ctrl + L("Left mouse button"), L("Select multiple objects")},
{shift + L("Left mouse button"), L("Select objects by rectangle")},
{L("Arrow Up"), L("Move selection 10 mm in positive Y direction")},
{L("Arrow Down"), L("Move selection 10 mm in negative Y direction")},
{L("Arrow Left"), L("Move selection 10 mm in negative X direction")},
{L("Arrow Right"), L("Move selection 10 mm in positive X direction")},
{L("Shift+Any arrow"), L("Movement step set to 1 mm")},
{shift + L("Any arrow"), L("Movement step set to 1 mm")},
{L("Esc"), L("Deselect all")},
{"1-9", L("keyboard 1-9: set filament for object/part")},
{ctrl + "0", L("Camera view - Default")},
@@ -268,21 +257,16 @@ void KBShortcutsDialog::fill_shortcuts()
{ "E", L("Gizmo brim ears") },
{ "I", L("Zoom in") },
{ "O", L("Zoom out") },
{ "Tab", L("Switch between Prepare/Preview") },
{ L("Tab"), L("Switch between Prepare/Preview") },
};
m_full_shortcuts.push_back({ { _L("Plater"), "" }, plater_shortcuts });
Shortcuts gizmos_shortcuts = {
{L("Esc"), L("Deselect all")},
{L("Shift+"), L("Move: press to snap by 1mm")},
#ifdef __APPLE__
{L("⌘+Mouse wheel"), L("Support/Color Painting: adjust pen radius")},
{L("⌥+Mouse wheel"), L("Support/Color Painting: adjust section position")},
#else
{L("Ctrl+Mouse wheel"), L("Support/Color Painting: adjust pen radius")},
{L("Alt+Mouse wheel"), L("Support/Color Painting: adjust section position")},
#endif
{shift, L("Move: press to snap by 1mm")},
{ctrl + L("Mouse wheel"), L("Support/Color Painting: adjust pen radius")},
{alt + L("Mouse wheel"), L("Support/Color Painting: adjust section position")},
};
m_full_shortcuts.push_back({{_L("Gizmo"), ""}, gizmos_shortcuts});
@@ -310,16 +294,11 @@ void KBShortcutsDialog::fill_shortcuts()
{ L("Arrow Right"), L("Horizontal slider - Move active thumb Right")},
{ "L", L("On/Off one layer mode of the vertical slider")},
{ "C", L("On/Off G-code window")},
{ "Tab", L("Switch between Prepare/Preview") },
{L("Shift+Any arrow"), L("Move slider 5x faster")},
{L("Shift+Mouse wheel"), L("Move slider 5x faster")},
#ifdef __APPLE__
{L("⌘+Any arrow"), L("Move slider 5x faster")},
{L("⌘+Mouse wheel"), L("Move slider 5x faster")},
#else
{L("Ctrl+Any arrow"), L("Move slider 5x faster")},
{L("Ctrl+Mouse wheel"), L("Move slider 5x faster")},
#endif
{ L("Tab"), L("Switch between Prepare/Preview")},
{shift + L("Any arrow"), L("Move slider 5x faster")},
{shift + L("Mouse wheel"), L("Move slider 5x faster")},
{ctrl + L("Any arrow"), L("Move slider 5x faster")},
{ctrl + L("Mouse wheel"), L("Move slider 5x faster")},
{ L("Home"), L("Horizontal slider - Move to start position")},
{ L("End"), L("Horizontal slider - Move to last position")},
};
+18 -22
View File
@@ -169,11 +169,14 @@ wxDEFINE_EVENT(EVT_SYNC_CLOUD_PRESET, SimpleEvent);
#ifdef __APPLE__
static const wxString ctrl = ("Ctrl+");
static const std::string ctrl_t = "⌘";
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
static const std::string ctrl_t = u8"\u2318+"; // "⌘" (Mac Command)
#else
static const wxString ctrl = _L("Ctrl+");
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
static const wxString ctrl_t = ctrl;
#endif
static const wxString shift = _L("Shift+");
MainFrame::MainFrame() :
DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_STYLE, "mainframe")
@@ -2402,13 +2405,12 @@ void MainFrame::init_menubar_as_editor()
[this](){return m_plater != nullptr && can_save(); }, this);
#endif
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Save Project as") + dots + "\t" + ctrl + _L("Shift+") + "S", _L("Save current project as"),
append_menu_item(fileMenu, wxID_ANY, _L("Save Project as") + dots + "\t" + ctrl + shift + "S", _L("Save current project as"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(true); }, "menu_save", nullptr,
[this](){return m_plater != nullptr && can_save_as(); }, this);
#else
append_menu_item(fileMenu, wxID_ANY, _L("Save Project as") + dots + "\t" + ctrl + _L("Shift+") + "S", _L("Save current project as"),
append_menu_item(fileMenu, wxID_ANY, _L("Save Project as") + dots + "\t" + ctrl + shift + "S", _L("Save current project as"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(true); }, "", nullptr,
[this](){return m_plater != nullptr && can_save_as(); }, this);
#endif
@@ -2432,7 +2434,7 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(import_menu, wxID_ANY, _L("Import Zip Archive") + dots, _L("Load models contained within a zip archive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->import_zip_archive(); }, "menu_import", nullptr,
[this]() { return can_add_models(); });
append_menu_item(import_menu, wxID_ANY, _L("Import Configs") + dots /*+ "\tCtrl+I"*/, _L("Load configs"),
append_menu_item(import_menu, wxID_ANY, _L("Import Configs") + dots /*+ "\t" + ctrl + "I"*/, _L("Load configs"),
[this](wxCommandEvent&) { load_config_file(); }, "menu_import", nullptr,
[this](){return true; }, this);
@@ -2447,7 +2449,7 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(export_menu, wxID_ANY, _L("Export all objects as STLs") + dots, _L("Export all objects as STLs"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(false, false, true); }, "menu_export_stl", nullptr,
[this](){return can_export_model(); }, this);
append_menu_item(export_menu, wxID_ANY, _L("Export Generic 3MF") + dots/* + "\tCtrl+G"*/, _L("Export 3mf file without using some 3mf-extensions"),
append_menu_item(export_menu, wxID_ANY, _L("Export Generic 3MF") + dots/* + "\t" + ctrl + "G"*/, _L("Export 3mf file without using some 3mf-extensions"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_core_3mf(); }, "menu_export_sliced_file", nullptr,
[this](){return can_export_model(); }, this);
// BBS export .gcode.3mf
@@ -2455,15 +2457,15 @@ void MainFrame::init_menubar_as_editor()
[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 all plate sliced file") + dots/* + "\tCtrl+G"*/, _L("Export all plate sliced file"),
append_menu_item(export_menu, wxID_ANY, _L("Export all plate sliced file") + dots/* + "\t" + ctrl + "G"*/, _L("Export all plate sliced file"),
[this](wxCommandEvent&) { if (m_plater) wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_ALL_SLICED_FILE)); }, "menu_export_sliced_file", nullptr,
[this]() {return can_export_all_gcode(); }, this);
append_menu_item(export_menu, wxID_ANY, _L("Export G-code") + dots/* + "\tCtrl+G"*/, _L("Export current plate as G-code"),
append_menu_item(export_menu, wxID_ANY, _L("Export G-code") + dots/* + "\t" + ctrl + "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_menu_item(
export_menu, wxID_ANY, _L("Export Preset Bundle") + dots /* + "\tCtrl+E"*/, _L("Export current configuration to files"),
export_menu, wxID_ANY, _L("Export Preset Bundle") + dots /* + "\t" + ctrl + "E"*/, _L("Export current configuration to files"),
[this](wxCommandEvent &) { export_config(); },
"menu_export_config", nullptr,
[]() { return true; }, this);
@@ -2486,12 +2488,6 @@ void MainFrame::init_menubar_as_editor()
if (m_plater != nullptr)
{
editMenu = new wxMenu();
#ifdef __APPLE__
// Backspace sign
wxString hotkey_delete = "\u232b";
#else
wxString hotkey_delete = "Del";
#endif
auto handle_key_event = [](wxKeyEvent& evt) {
if (wxGetApp().imgui()->update_key_data(evt)) {
@@ -2532,7 +2528,7 @@ void MainFrame::init_menubar_as_editor()
"menu_remove", nullptr, [this](){return can_delete_all(); }, this);
editMenu->AppendSeparator();
// BBS Clone Selected
append_menu_item(editMenu, wxID_ANY, _L("Clone selected") /*+ "\tCtrl+M"*/,
append_menu_item(editMenu, wxID_ANY, _L("Clone selected") /*+ "\t" + ctrl + "M"*/,
_L("Clone copies of selections"),[this](wxCommandEvent&) {
m_plater->clone_selection();
},
@@ -2608,7 +2604,7 @@ void MainFrame::init_menubar_as_editor()
"", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
#if 0
// BBS Delete selected
append_menu_item(editMenu, wxID_ANY, _L("Delete selected") + "\tBackSpace",
append_menu_item(editMenu, wxID_ANY, _L("Delete selected") + "\t" + _L("Backspace"),
_L("Deletes the current selection"),[this](wxCommandEvent&) {
m_plater->remove_selected();
},
@@ -2663,7 +2659,7 @@ void MainFrame::init_menubar_as_editor()
m_plater->select_all(); },
"", nullptr, [this](){return can_select(); }, this);
// BBS Deslect All
append_menu_item(editMenu, wxID_ANY, _L("Deselect all") + sep + "Esc",
append_menu_item(editMenu, wxID_ANY, _L("Deselect all") + sep + _L("Esc"),
_L("Deselects all objects"), [this, handle_key_event](wxCommandEvent&) {
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
@@ -2782,7 +2778,7 @@ void MainFrame::init_menubar_as_editor()
[this]() { return wxGetApp().show_outline(); }, this);
/*viewMenu->AppendSeparator();
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Wireframe") + "\tCtrl+Shift+Enter", _L("Show wireframes in 3D scene."),
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Wireframe") + "\t" + ctrl + shift + _L("Enter"), _L("Show wireframes in 3D scene."),
[this](wxCommandEvent&) { m_plater->toggle_show_wireframe(); m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this,
[this]() { return m_plater->is_wireframe_enabled(); }, [this]() { return m_plater->is_show_wireframe(); }, this);*/
@@ -2805,7 +2801,7 @@ void MainFrame::init_menubar_as_editor()
#ifdef __APPLE__
wxWindowID bambu_studio_id_base = wxWindow::NewControlId(int(2));
wxMenu* parent_menu = m_menubar->OSXGetAppleMenu();
//auto preference_item = new wxMenuItem(parent_menu, OrcaSlicerMenuPreferences + bambu_studio_id_base, _L("Preferences") + "\tCtrl+,", "");
//auto preference_item = new wxMenuItem(parent_menu, OrcaSlicerMenuPreferences + bambu_studio_id_base, _L("Preferences") + "\t" + ctrl + ",", "");
#else
wxMenu* parent_menu = m_topbar->GetTopMenu();
auto preference_item = new wxMenuItem(parent_menu, ConfigMenuPreferences + config_id_base, _L("Preferences") + "\t" + ctrl + "P", "");
@@ -3248,11 +3244,11 @@ void MainFrame::init_menubar_as_gcodeviewer()
#if 0
wxMenu* fileMenu = new wxMenu;
{
append_menu_item(fileMenu, wxID_ANY, _L("&Open G-code") + dots + "\tCtrl+O", _L("Open a G-code file"),
append_menu_item(fileMenu, wxID_ANY, _L("&Open G-code") + dots + "\t" + ctrl + "O", _L("Open a G-code file"),
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->load_gcode(); }, "open", nullptr,
[this]() {return m_plater != nullptr; }, this);
#ifdef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from Disk") + dots + "\tCtrl+Shift+R",
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from Disk") + dots + "\t" + ctrl + shift + "R",
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_gcode_from_disk(); },
"", nullptr, [this]() { return !m_plater->get_last_loaded_gcode().empty(); }, this);
#else
+1 -1
View File
@@ -298,7 +298,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj)
switch (status) {
case PrinterFileSystem::Initializing: icon = m_bmp_loading; msg = _L("Initializing..."); break;
case PrinterFileSystem::Connecting: icon = m_bmp_loading; msg = _L("Connecting..."); break;
case PrinterFileSystem::Failed: icon = m_bmp_failed; if (extra != 1) msg = _L("Please check the network and try again, You can restart or update the printer if the issue persists."); break;
case PrinterFileSystem::Failed: icon = m_bmp_failed; if (extra != 1) msg = _L("Please check the network and try again. You can restart or update the printer if the issue persists."); break;
case PrinterFileSystem::ListSyncing: {
icon = m_bmp_loading;
msg = _L("Loading file list...");
+6 -4
View File
@@ -63,11 +63,13 @@ namespace GUI {
m_control_refresh->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCursor(wxCURSOR_ARROW)); });
#ifdef __APPLE__
m_control_back->SetToolTip(_L("Click to return (Command + Left Arrow)"));
m_control_forward->SetToolTip(_L("Click to continue (Command + Right Arrow)"));
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
m_control_back->SetToolTip(_L("Click to return") + "(" + u8"\u2318+" /* u8"⌘+" */ + _L("Left Arrow") + ")");
m_control_forward->SetToolTip(_L("Click to continue") + "(" + u8"\u2318+" /* u8"⌘+" */ + _L("Right Arrow") + ")");
#else
m_control_back->SetToolTip(_L("Click to return (Alt + Left Arrow)"));
m_control_forward->SetToolTip(_L("Click to continue (Alt + Right Arrow)"));
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
m_control_back->SetToolTip(_L("Click to return") + "(" + _L("Alt+") + _L("Left Arrow") + ")");
m_control_forward->SetToolTip(_L("Click to continue") + "(" + _L("Alt+") + _L("Right Arrow") + ")");
#endif
m_control_refresh->SetToolTip(_L("Refresh"));
+1 -1
View File
@@ -300,7 +300,7 @@ ParamsPanel::ParamsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, c
// BBS: new layout
//m_search_btn = new ScalableButton(m_top_panel, wxID_ANY, "search", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true);
//m_search_btn->SetToolTip(format_wxstr(_L("Search in settings [%1%]"), "Ctrl+F"));
//m_search_btn->SetToolTip(format_wxstr(_L("Search in settings [%1%]"), _L("Ctrl+") + "F");
//m_search_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { wxGetApp().plater()->search(false); });
m_compare_btn = new ScalableButton(m_top_panel, wxID_ANY, "compare", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true);
+27 -3
View File
@@ -4611,7 +4611,7 @@ void Plater::priv::collapse_sidebar(bool collapse)
std::string new_tooltip = collapse
? _u8L("Expand sidebar")
: _u8L("Collapse sidebar");
new_tooltip += " [Shift+Tab]";
new_tooltip += " [" + _u8L("Shift+") + _u8L("Tab") + "]";
int id = collapse_toolbar.get_item_id("collapse_sidebar");
collapse_toolbar.set_tooltip(id, new_tooltip);
@@ -4980,8 +4980,32 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// // Is there any modifier or advanced config data?
// for (ModelVolume *model_volume : model_object->volumes) model_volume->config.reset();
// }
// }
else if (load_config && (file_version > app_version)) {
// }
// Orca: check if the project is created with OrcaSlicer 2.3.1-alpha and use the sparse infill rotation template for non-safe infill patterns
else if ((file_version < app_version) && file_version == Semver("2.3.1-alpha")) {
if (!config_loaded.opt_string("sparse_infill_rotate_template").empty()) {
const auto _sparse_infill_pattern =
config_loaded.option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
_sparse_infill_pattern == ipLockedZag;
if (!is_safe_to_rotate) {
wxString msg_text = _(
L("This project was created with an OrcaSlicer 2.3.1-alpha and uses "
"infill rotation template settings that may not work properly with your current infill pattern. "
"This could result in weak support or print quality issues."));
msg_text += "\n\n" +
_(L("Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?"));
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
dialog.SetButtonLabel(wxID_YES, _L("Yes"));
dialog.SetButtonLabel(wxID_NO, _L("No"));
if (dialog.ShowModal() == wxID_YES) {
config_loaded.opt_string("sparse_infill_rotate_template") = "";
}
}
}
} else if (load_config && (file_version > app_version)) {
if (config_substitutions.unrecogized_keys.size() > 0) {
wxString text = wxString::Format(_L("The 3mf's version %s is newer than %s's version %s, found following unrecognized keys:"),
file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string());
+6 -6
View File
@@ -1640,7 +1640,7 @@ wxPanel *StatusBasePanel::create_bed_control(wxWindow *parent)
StateColor z_1_ctrl_bg(std::pair<wxColour, int>(BUTTON_PRESS_COL, StateColor::Pressed), std::pair<wxColour, int>(BUTTON_NORMAL2_COL, StateColor::Normal));
StateColor z_1_ctrl_bd(std::pair<wxColour, int>(BUTTON_HOVER_COL, StateColor::Hovered), std::pair<wxColour, int>(BUTTON_NORMAL2_COL, StateColor::Normal));
m_bpButton_z_10 = new Button(panel, wxString("10"), "monitor_bed_up", 0, FromDIP(15));
m_bpButton_z_10 = new Button(panel, wxString("10"), "monitor_bed_up", 0, 15); // Orca Dont scale icon size
m_bpButton_z_10->SetFont(::Label::Body_12);
m_bpButton_z_10->SetBorderWidth(0);
m_bpButton_z_10->SetBackgroundColor(z_10_ctrl_bg);
@@ -1649,7 +1649,7 @@ wxPanel *StatusBasePanel::create_bed_control(wxWindow *parent)
m_bpButton_z_10->SetMinSize(Z_BUTTON_SIZE);
m_bpButton_z_10->SetMaxSize(Z_BUTTON_SIZE);
m_bpButton_z_10->SetCornerRadius(0);
m_bpButton_z_1 = new Button(panel, wxString(" 1"), "monitor_bed_up", 0, FromDIP(15));
m_bpButton_z_1 = new Button(panel, wxString(" 1"), "monitor_bed_up", 0, 15); // Orca Dont scale icon size
m_bpButton_z_1->SetFont(::Label::Body_12);
m_bpButton_z_1->SetBorderWidth(0);
m_bpButton_z_1->SetBackgroundColor(z_1_ctrl_bg);
@@ -1665,7 +1665,7 @@ wxPanel *StatusBasePanel::create_bed_control(wxWindow *parent)
if (wxGetApp().app_config->get("language") == "de_DE") m_staticText_z_tip->SetFont(::Label::Body_11);
m_staticText_z_tip->Wrap(-1);
m_staticText_z_tip->SetForegroundColour(TEXT_LIGHT_FONT_COL);
m_bpButton_z_down_1 = new Button(panel, wxString(" 1"), "monitor_bed_down", 0, FromDIP(15));
m_bpButton_z_down_1 = new Button(panel, wxString(" 1"), "monitor_bed_down", 0, 15); // Orca Dont scale icon size
m_bpButton_z_down_1->SetFont(::Label::Body_12);
m_bpButton_z_down_1->SetBorderWidth(0);
m_bpButton_z_down_1->SetBackgroundColor(z_1_ctrl_bg);
@@ -1674,7 +1674,7 @@ wxPanel *StatusBasePanel::create_bed_control(wxWindow *parent)
m_bpButton_z_down_1->SetSize(Z_BUTTON_SIZE);
m_bpButton_z_down_1->SetTextColor(StateColor(std::make_pair(DISCONNECT_TEXT_COL, (int) StateColor::Disabled), std::make_pair(NORMAL_TEXT_COL, (int) StateColor::Normal)));
m_bpButton_z_down_10 = new Button(panel, wxString("10"), "monitor_bed_down", 0, FromDIP(15));
m_bpButton_z_down_10 = new Button(panel, wxString("10"), "monitor_bed_down", 0, 15); // Orca Dont scale icon size
m_bpButton_z_down_10->SetFont(::Label::Body_12);
m_bpButton_z_down_10->SetBorderWidth(0);
m_bpButton_z_down_10->SetBackgroundColor(z_10_ctrl_bg);
@@ -1713,7 +1713,7 @@ wxBoxSizer *StatusBasePanel::create_extruder_control(wxWindow *parent)
m_nozzle_btn_panel = new SwitchBoard(panel, _L("Left"), _L("Right"), wxSize(FromDIP(126), FromDIP(26)));
m_nozzle_btn_panel->SetAutoDisableWhenSwitch();
m_bpButton_e_10 = new Button(panel, "", "monitor_extruder_up", 0, FromDIP(22));
m_bpButton_e_10 = new Button(panel, "", "monitor_extruder_up", 0, 22); // Orca Dont scale icon size
m_bpButton_e_10->SetBorderWidth(2);
m_bpButton_e_10->SetBackgroundColor(e_ctrl_bg);
m_bpButton_e_10->SetBorderColor(e_ctrl_bd);
@@ -1729,7 +1729,7 @@ wxBoxSizer *StatusBasePanel::create_extruder_control(wxWindow *parent)
}
m_extruder_book->SetSelection(0);
m_bpButton_e_down_10 = new Button(panel, "", "monitor_extruder_down", 0, FromDIP(22));
m_bpButton_e_down_10 = new Button(panel, "", "monitor_extruder_down", 0, 22); // Orca Dont scale icon size
m_bpButton_e_down_10->SetBorderWidth(2);
m_bpButton_e_down_10->SetBackgroundColor(e_ctrl_bg);
m_bpButton_e_down_10->SetBorderColor(e_ctrl_bd);
+38 -8
View File
@@ -254,7 +254,7 @@ void Tab::create_preset_tab()
"or click this button.")));
add_scaled_button(panel, &m_search_btn, "search");
m_search_btn->SetToolTip(format_wxstr(_L("Search in settings [%1%]"), "Ctrl+F"));*/
m_search_btn->SetToolTip(format_wxstr(_L("Search in settings [%1%]"), _L("Ctrl+") + "F"));*/
// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
add_scaled_bitmap(this, m_bmp_value_lock , "unlock_normal");
@@ -1658,6 +1658,35 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
}
}
if (opt_key == "sparse_infill_rotate_template") {
// Orca: show warning dialog if rotate template for solid infill if not support
const auto _sparse_infill_pattern = m_config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
_sparse_infill_pattern == ipLockedZag;
auto new_value = boost::any_cast<std::string>(value);
is_safe_to_rotate = is_safe_to_rotate || new_value.empty();
if (!is_safe_to_rotate) {
wxString msg_text = _(
L("Infill patterns are typically designed to handle rotation automatically to ensure proper printing and achieve their "
"intended effects (e.g., Gyroid, Cubic). Rotating the current sparse infill pattern may lead to insufficient support. "
"Please proceed with caution and thoroughly check for any potential printing issues."
"Are you sure you want to enable this option?"));
msg_text += "\n\n" + _(L("Are you sure you want to enable this option?"));
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
dialog.SetButtonLabel(wxID_YES, _L("Enable"));
dialog.SetButtonLabel(wxID_NO, _L("Cancel"));
if (dialog.ShowModal() == wxID_NO) {
DynamicPrintConfig new_conf = *m_config;
new_conf.set_key_value("sparse_infill_rotate_template", new ConfigOptionString(""));
m_config_manipulation.apply(m_config, &new_conf);
wxGetApp().plater()->update();
}
}
}
if(opt_key=="layer_height"){
auto min_layer_height_from_nozzle=wxGetApp().preset_bundle->full_config().option<ConfigOptionFloats>("min_layer_height")->values;
auto max_layer_height_from_nozzle=wxGetApp().preset_bundle->full_config().option<ConfigOptionFloats>("max_layer_height")->values;
@@ -2278,7 +2307,7 @@ void TabPrint::build()
optgroup->append_single_option_line("fill_multiline", "strength_settings_infill#fill-multiline");
optgroup->append_single_option_line("sparse_infill_pattern", "strength_settings_infill#sparse-infill-pattern");
optgroup->append_single_option_line("infill_direction", "strength_settings_infill#direction");
optgroup->append_single_option_line("sparse_infill_rotate_template", "strength_settings_infill#rotation");
optgroup->append_single_option_line("sparse_infill_rotate_template", "strength_settings_infill_rotation_template_metalanguage");
optgroup->append_single_option_line("skin_infill_density", "strength_settings_patterns#locked-zag");
optgroup->append_single_option_line("skeleton_infill_density", "strength_settings_patterns#locked-zag");
optgroup->append_single_option_line("infill_lock_depth", "strength_settings_patterns#locked-zag");
@@ -2294,13 +2323,14 @@ void TabPrint::build()
optgroup->append_single_option_line("infill_anchor", "strength_settings_infill#anchor");
optgroup->append_single_option_line("internal_solid_infill_pattern", "strength_settings_infill#internal-solid-infill");
optgroup->append_single_option_line("solid_infill_direction", "strength_settings_infill#direction");
optgroup->append_single_option_line("solid_infill_rotate_template", "strength_settings_infill#rotation");
optgroup->append_single_option_line("solid_infill_rotate_template", "strength_settings_infill_rotation_template_metalanguage");
optgroup->append_single_option_line("gap_fill_target", "strength_settings_infill#apply-gap-fill");
optgroup->append_single_option_line("filter_out_gap_fill", "strength_settings_infill#filter-out-tiny-gaps");
optgroup->append_single_option_line("infill_wall_overlap", "strength_settings_infill#infill-wall-overlap");
optgroup = page->new_optgroup(L("Advanced"), L"param_advanced");
optgroup->append_single_option_line("align_infill_direction_to_model", "strength_settings_advanced#align-infill-direction-to-model");
optgroup->append_single_option_line("extra_solid_infills", "strength_settings_infill#extra-solid-infill");
optgroup->append_single_option_line("bridge_angle", "strength_settings_advanced#bridge-infill-direction");
optgroup->append_single_option_line("internal_bridge_angle", "strength_settings_advanced#bridge-infill-direction"); // ORCA: Internal bridge angle override
optgroup->append_single_option_line("minimum_sparse_infill_area", "strength_settings_advanced#minimum-sparse-infill-threshold");
@@ -3568,13 +3598,13 @@ void TabFilament::build()
optgroup->append_single_option_line("pellet_flow_coefficient", "pellet-flow-coefficient");
optgroup->append_single_option_line("filament_flow_ratio", "", 0);
optgroup->append_single_option_line("enable_pressure_advance");
optgroup->append_single_option_line("pressure_advance");
optgroup->append_single_option_line("enable_pressure_advance", "pressure-advance-calib");
optgroup->append_single_option_line("pressure_advance", "pressure-advance-calib");
// Orca: adaptive pressure advance and calibration model
optgroup->append_single_option_line("adaptive_pressure_advance");
optgroup->append_single_option_line("adaptive_pressure_advance_overhangs");
optgroup->append_single_option_line("adaptive_pressure_advance_bridges");
optgroup->append_single_option_line("adaptive_pressure_advance", "adaptive-pressure-advance-calib");
optgroup->append_single_option_line("adaptive_pressure_advance_overhangs", "adaptive-pressure-advance-calib");
optgroup->append_single_option_line("adaptive_pressure_advance_bridges", "adaptive-pressure-advance-calib");
Option option = optgroup->get_option("adaptive_pressure_advance_model");
option.opt.full_width = true;
+2 -2
View File
@@ -18,8 +18,8 @@ static const std::unordered_map<wxString, wxString> ACCESSORY_DISPLAY_STR = {
{"N3F", "AMS 2 PRO"},
{"N3S", "AMS HT"},
{"O2L_PC", L("Air Pump")},
{"O2L_10B", L("Laser 10w")},
{"O2L_40B", L("Laser 40w")},
{"O2L_10B", L("Laser 10 W")},
{"O2L_40B", L("Laser 40 W")},
{"O2L_PCM", L("Cutting Module")},
{"O2L_ACM", "Active Cutting Module"},
{"O2L_UCM", "Ultrasonic Cutting Module"},