Merge branch 'main' into dev/bbl-network-upd

This commit is contained in:
Noisyfox
2025-06-25 08:49:55 +08:00
committed by GitHub
110 changed files with 4133 additions and 1751 deletions
+3
View File
@@ -178,6 +178,9 @@ void AppConfig::set_defaults()
if (get("camera_navigation_style").empty())
set("camera_navigation_style", "0");
if (get("swap_mouse_buttons").empty())
set_bool("swap_mouse_buttons", false);
if (get("reverse_mouse_wheel_zoom").empty())
set_bool("reverse_mouse_wheel_zoom", false);
+7
View File
@@ -49,6 +49,13 @@ BoundingBox BoundingBox::rotated(double angle, const Point &center) const
return out;
}
BoundingBox BoundingBox::scaled(double factor) const
{
BoundingBox out(*this);
out.scale(factor);
return out;
}
template <class PointType, typename APointsType> void
BoundingBoxBase<PointType, APointsType>::scale(double factor)
{
+3 -1
View File
@@ -222,7 +222,9 @@ public:
BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point, Points>(pmin, pmax) {}
BoundingBox(const Points &points) : BoundingBoxBase<Point, Points>(points) {}
BoundingBox inflated(coordf_t delta) const throw() { BoundingBox out(*this); out.offset(delta); return out; }
BoundingBox inflated(coordf_t delta) const noexcept { BoundingBox out(*this); out.offset(delta); return out; }
BoundingBox scaled(double factor) const;
friend BoundingBox get_extents_rotated(const Points &points, double angle);
};
+12
View File
@@ -657,6 +657,11 @@ public:
{
if (! append)
this->values.clear();
if (str.empty()) {
this->values.push_back(0);
return true;
}
std::istringstream is(str);
std::string item_str;
while (std::getline(is, item_str, ',')) {
@@ -675,6 +680,13 @@ public:
}
return true;
}
static bool validate_string(const std::string &str)
{
// should only have number and commas
return std::all_of(str.begin(), str.end(), [](char c) {
return std::isdigit(c) || c == ','|| std::isspace(c);
});
}
ConfigOptionFloatsTempl& operator=(const ConfigOption *opt)
{
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -56,7 +56,7 @@ public:
bool on_boundary(const Point &point, double eps) const;
// Projection of a point onto the polygon.
Point point_projection(const Point &point) const;
void symmetric_y(const coord_t &y_axis);
// Does this expolygon overlap another expolygon?
// Either the ExPolygons intersect, or one is fully inside the other,
// and it is not inside a hole of the other expolygon.
+151 -58
View File
@@ -34,7 +34,6 @@ struct SurfaceFillParams
coordf_t overlap = 0.;
// Angle as provided by the region config, in radians.
float angle = 0.f;
bool rotate_angle = true;
// 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.
@@ -68,6 +67,9 @@ struct SurfaceFillParams
// Params for lattice infill angles
float lattice_angle_1 = 0.f;
float lattice_angle_2 = 0.f;
float infill_lock_depth = 0;
float skin_infill_depth = 0;
bool symmetric_infill_y_axis = false;
// Params for 2D honeycomb
float infill_overhang_angle = 60.f;
@@ -85,7 +87,6 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(spacing);
RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(rotate_angle);
RETURN_COMPARE_NON_EQUAL(density);
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
RETURN_COMPARE_NON_EQUAL(anchor_length);
@@ -100,33 +101,36 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(solid_infill_speed);
RETURN_COMPARE_NON_EQUAL(lattice_angle_1);
RETURN_COMPARE_NON_EQUAL(lattice_angle_2);
RETURN_COMPARE_NON_EQUAL(infill_overhang_angle);
RETURN_COMPARE_NON_EQUAL(symmetric_infill_y_axis);
RETURN_COMPARE_NON_EQUAL(infill_lock_depth);
RETURN_COMPARE_NON_EQUAL(skin_infill_depth); RETURN_COMPARE_NON_EQUAL(infill_overhang_angle);
return false;
}
bool operator==(const SurfaceFillParams &rhs) const {
return this->extruder == rhs.extruder &&
this->pattern == rhs.pattern &&
this->spacing == rhs.spacing &&
this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->rotate_angle == rhs.rotate_angle &&
this->bridge == rhs.bridge &&
this->bridge_angle == rhs.bridge_angle &&
this->density == rhs.density &&
// this->dont_adjust == rhs.dont_adjust &&
this->anchor_length == rhs.anchor_length &&
this->anchor_length_max == rhs.anchor_length_max &&
this->flow == rhs.flow &&
this->extrusion_role == rhs.extrusion_role &&
this->sparse_infill_speed == rhs.sparse_infill_speed &&
this->top_surface_speed == rhs.top_surface_speed &&
this->solid_infill_speed == rhs.solid_infill_speed &&
this->lattice_angle_1 == rhs.lattice_angle_1 &&
this->lattice_angle_2 == rhs.lattice_angle_2 &&
bool operator==(const SurfaceFillParams &rhs) const {
return this->extruder == rhs.extruder &&
this->pattern == rhs.pattern &&
this->spacing == rhs.spacing &&
this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->bridge == rhs.bridge &&
this->bridge_angle == rhs.bridge_angle &&
this->density == rhs.density &&
// this->dont_adjust == rhs.dont_adjust &&
this->anchor_length == rhs.anchor_length &&
this->anchor_length_max == rhs.anchor_length_max &&
this->flow == rhs.flow &&
this->extrusion_role == rhs.extrusion_role &&
this->sparse_infill_speed == rhs.sparse_infill_speed &&
this->top_surface_speed == rhs.top_surface_speed &&
this->solid_infill_speed == rhs.solid_infill_speed &&
this->lattice_angle_1 == rhs.lattice_angle_1 &&
this->lattice_angle_2 == rhs.lattice_angle_2 &&
this->infill_lock_depth == rhs.infill_lock_depth &&
this->skin_infill_depth == rhs.skin_infill_depth &&
this->infill_overhang_angle == rhs.infill_overhang_angle;
}
}
};
struct SurfaceFill {
@@ -602,16 +606,34 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
#endif
}
std::vector<SurfaceFill> group_fills(const Layer &layer)
std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_param)
{
std::vector<SurfaceFill> surface_fills;
// Fill in a map of a region & surface to SurfaceFillParams.
std::set<SurfaceFillParams> set_surface_params;
std::vector<std::vector<const SurfaceFillParams*>> region_to_surface_params(layer.regions().size(), std::vector<const SurfaceFillParams*>());
SurfaceFillParams params;
bool has_internal_voids = false;
const PrintObjectConfig& object_config = layer.object()->config();
auto append_flow_param = [](std::map<Flow, ExPolygons> &flow_params, Flow flow, const ExPolygon &exp) {
auto it = flow_params.find(flow);
if (it == flow_params.end())
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) {
auto it = density_params.find(density);
if (it == density_params.end())
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) {
const LayerRegion &layerm = *layer.regions()[region_id];
region_to_surface_params[region_id].assign(layerm.fill_surfaces.size(), nullptr);
@@ -628,26 +650,37 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.lattice_angle_1 = region_config.lattice_angle_1;
params.lattice_angle_2 = region_config.lattice_angle_2;
params.infill_overhang_angle = region_config.infill_overhang_angle;
if (params.pattern == ipLockedZag) {
params.infill_lock_depth = scale_(region_config.infill_lock_depth);
params.skin_infill_depth = scale_(region_config.skin_infill_depth);
}
if (params.pattern == ipCrossZag || params.pattern == ipLockedZag) {
params.symmetric_infill_y_axis = region_config.symmetric_infill_y_axis;
} else if (params.pattern == ipZigZag) {
params.symmetric_infill_y_axis = region_config.symmetric_infill_y_axis;
}
if (surface.is_solid()) {
params.density = 100.f;
//FIXME for non-thick bridges, shall we allow a bottom surface pattern?
if (surface.is_solid_infill())
params.pattern = region_config.internal_solid_infill_pattern.value;
else if (surface.is_external() && ! is_bridge) {
if(surface.is_top())
if (surface.is_solid()) {
if (surface.is_external() && !is_bridge) {
if (surface.is_top()) {
params.pattern = region_config.top_surface_pattern.value;
else
params.density = float(region_config.top_surface_density);
} else { // Surface is bottom
params.pattern = region_config.bottom_surface_pattern.value;
}
else {
if(region_config.top_surface_pattern == ipMonotonic || region_config.top_surface_pattern == ipMonotonicLine)
params.density = float(region_config.bottom_surface_density);
}
} else if (surface.is_solid_infill()) {
params.pattern = region_config.internal_solid_infill_pattern.value;
params.density = 100.f;
} else {
if (region_config.top_surface_pattern == ipMonotonic || region_config.top_surface_pattern == ipMonotonicLine)
params.pattern = ipMonotonic;
else
params.pattern = ipRectilinear;
params.density = 100.f;
}
} else if (params.density <= 0)
continue;
} else if (params.density <= 0)
continue;
params.extrusion_role = erInternalInfill;
if (is_bridge) {
@@ -667,10 +700,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.bridge_angle = float(surface.bridge_angle);
if (params.extrusion_role == erInternalInfill) {
params.angle = float(Geometry::deg2rad(region_config.infill_direction.value));
params.rotate_angle = (params.pattern == ipRectilinear || params.pattern == ipLine);
} else {
params.angle = float(Geometry::deg2rad(region_config.solid_infill_direction.value));
params.rotate_angle = region_config.rotate_solid_infill_direction;
}
// Calculate the actual flow we'll be using for this infill.
@@ -709,7 +740,28 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.anchor_length = std::min(params.anchor_length, params.anchor_length_max);
}
auto it_params = set_surface_params.find(params);
//get locked region param
if (params.pattern == ipLockedZag){
const PrintObject *object = layerm.layer()->object();
auto nozzle_diameter = float(object->print()->config().nozzle_diameter.get_at(layerm.region().extruder(extrusion_role) - 1));
Flow skin_flow = params.bridge ? params.flow : Flow::new_from_config_width(extrusion_role, region_config.skin_infill_line_width, nozzle_diameter, float((surface.thickness == -1) ? layer.height : surface.thickness));
//add skin flow
append_flow_param(lock_param.skin_flow_params, skin_flow, surface.expolygon);
Flow skeleton_flow = params.bridge ? params.flow : Flow::new_from_config_width(extrusion_role, region_config.skeleton_infill_line_width, nozzle_diameter, float((surface.thickness == -1) ? layer.height : surface.thickness)) ;
// add skeleton flow
append_flow_param(lock_param.skeleton_flow_params, skeleton_flow, surface.expolygon);
// add skin density
append_density_param(lock_param.skin_density_params, float(0.01 * region_config.skin_infill_density), surface.expolygon);
// add skin density
append_density_param(lock_param.skeleton_density_params, float(0.01 * region_config.skeleton_infill_density), surface.expolygon);
}
auto it_params = set_surface_params.find(params);
if (it_params == set_surface_params.end())
it_params = set_surface_params.insert(it_params, params);
region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()] = &(*it_params);
@@ -829,7 +881,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.density = 100.f;
params.extrusion_role = erSolidInfill;
params.angle = float(Geometry::deg2rad(layerm.region().config().solid_infill_direction.value));
params.rotate_angle = layerm.region().config().rotate_solid_infill_direction;
// calculate the actual flow we'll be using for this infill
params.flow = layerm.flow(frSolidInfill);
params.spacing = params.flow.spacing();
@@ -914,8 +965,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
// this->export_region_fill_surfaces_to_svg_debug("10_fill-initial");
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
std::vector<SurfaceFill> surface_fills = group_fills(*this);
LockRegionParam lock_param;
std::vector<SurfaceFill> surface_fills = group_fills(*this, lock_param);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
const auto resolution = this->object()->print()->config().resolution.value;
@@ -933,14 +984,22 @@ 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->rotate_angle = surface_fill.params.rotate_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();
if (surface_fill.params.pattern == ipLightning)
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
if (surface_fill.params.pattern == ipConcentricInternal) {
FillConcentricInternal *fill_concentric = dynamic_cast<FillConcentricInternal *>(f.get());
assert(fill_concentric != nullptr);
fill_concentric->print_config = &this->object()->print()->config();
fill_concentric->print_object_config = &this->object()->config();
} else if (surface_fill.params.pattern == ipConcentric) {
FillConcentric *fill_concentric = dynamic_cast<FillConcentric *>(f.get());
assert(fill_concentric != nullptr);
fill_concentric->print_config = &this->object()->print()->config();
fill_concentric->print_object_config = &this->object()->config();
} else if (surface_fill.params.pattern == ipLightning)
dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator;
// calculate flow spacing for infill pattern generation
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.bridge;
double link_max_length = 0.;
@@ -970,7 +1029,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.resolution = resolution;
params.use_arachne = surface_fill.params.pattern == ipConcentric || surface_fill.params.pattern == ipConcentricInternal;
params.layer_height = layerm->layer()->height;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_2 = surface_fill.params.lattice_angle_2;
params.infill_overhang_angle = surface_fill.params.infill_overhang_angle;
@@ -979,11 +1038,41 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.extrusion_role = surface_fill.params.extrusion_role;
params.using_internal_flow = using_internal_flow;
params.no_extrusion_overlap = surface_fill.params.overlap;
params.config = &layerm->region().config();
auto &region_config = layerm->region().config();
ConfigOptionFloats rotate_angles;
rotate_angles.deserialize( surface_fill.params.extrusion_role == erInternalInfill ? region_config.sparse_infill_rotate_template.value : region_config.solid_infill_rotate_template.value);
auto rotate_angle_idx = f->layer_id % rotate_angles.size();
f->rotate_angle = Geometry::deg2rad(rotate_angles.values[rotate_angle_idx]);
params.config = &region_config;
params.pattern = surface_fill.params.pattern;
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;
f->set_lock_region_param(lock_param);
}
if (surface_fill.params.pattern == ipCrossZag || surface_fill.params.pattern == ipLockedZag) {
if (f->layer_id % 2 == 0) {
params.horiz_move -= scale_(region_config.infill_shift_step) * (f->layer_id / 2);
} else {
params.horiz_move += scale_(region_config.infill_shift_step) * (f->layer_id / 2);
}
params.symmetric_infill_y_axis = surface_fill.params.symmetric_infill_y_axis;
}
if (surface_fill.params.pattern == ipGrid)
params.can_reverse = false;
for (ExPolygon& expoly : surface_fill.expolygons) {
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes);
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes);
if (params.symmetric_infill_y_axis) {
params.symmetric_y_axis = f->extended_object_bounding_box().center().x();
expoly.symmetric_y(params.symmetric_y_axis);
}
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
f->spacing = surface_fill.params.spacing;
surface_fill.surface.expolygon = std::move(expoly);
@@ -1023,9 +1112,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator) const
{
std::vector<SurfaceFill> surface_fills = group_fills(*this);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
const auto resolution = this->object()->print()->config().resolution.value;
LockRegionParam skin_inner_param;
std::vector<SurfaceFill> surface_fills = group_fills(*this, skin_inner_param);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
const auto resolution = this->object()->print()->config().resolution.value;
Polylines sparse_infill_polylines{};
@@ -1059,7 +1149,10 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
case ipTpmsD:
case ipHilbertCurve:
case ipArchimedeanChords:
case ipOctagramSpiral: break;
case ipOctagramSpiral:
case ipZigZag:
case ipCrossZag:
case ipLockedZag: break;
}
// Create the filler object.
@@ -1103,8 +1196,8 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
params.resolution = resolution;
params.use_arachne = false;
params.layer_height = layerm.layer()->height;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_2 = surface_fill.params.lattice_angle_2;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_2 = surface_fill.params.lattice_angle_2;
params.infill_overhang_angle = surface_fill.params.infill_overhang_angle;
for (ExPolygon &expoly : surface_fill.expolygons) {
+4
View File
@@ -15,6 +15,10 @@ 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; }
bool is_self_crossing() override { return false; }
protected:
void _fill_surface_single(
const FillParams &params,
+1
View File
@@ -71,6 +71,7 @@ protected:
// may not be optimal as the internal infill lines may get extruded before the long infill
// lines to which the short infill lines are supposed to anchor.
bool no_sort() const override { return false; }
bool is_self_crossing() override { return true; }
};
} // namespace FillAdaptive
+43 -28
View File
@@ -67,6 +67,9 @@ Fill* Fill::new_from_type(const InfillPattern type)
// BBS: for bottom and top surface only
// Orca: Replace BBS implementation with Prusa implementation
case ipMonotonicLine: return new FillMonotonicLines();
case ipZigZag: return new FillZigZag();
case ipCrossZag: return new FillCrossZag();
case ipLockedZag: return new FillLockedZag();
default: throw Slic3r::InvalidArgument("unknown type");
}
}
@@ -243,7 +246,7 @@ void Fill::_create_gap_fill(const Surface* surface, const FillParams& params, Ex
// Calculate a new spacing to fill width with possibly integer number of lines,
// the first and last line being centered at the interval ends.
// This function possibly increases the spacing, never decreases,
// This function possibly increases the spacing, never decreases,
// and for a narrow width the increase in spacing may become severe,
// therefore the adjustment is limited to 20% increase.
coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance)
@@ -252,8 +255,8 @@ coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance)
assert(distance > 0);
// floor(width / distance)
const auto number_of_intervals = coord_t((width - EPSILON) / distance);
coord_t distance_new = (number_of_intervals == 0) ?
distance :
coord_t distance_new = (number_of_intervals == 0) ?
distance :
coord_t((width - EPSILON) / number_of_intervals);
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
assert(factor > 1. - 1e-5);
@@ -279,8 +282,8 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
// Bounding box is the bounding box of a perl object Slic3r::Print::Object (c++ object Slic3r::PrintObject)
// The bounding box is only undefined in unit tests.
Point out_shift = empty(this->bounding_box) ?
surface->expolygon.contour.bounding_box().center() :
Point out_shift = empty(this->bounding_box) ?
surface->expolygon.contour.bounding_box().center() :
this->bounding_box.center();
#if 0
@@ -354,10 +357,10 @@ struct ContourIntersectionPoint {
bool could_take_next() const throw() { return ! this->consumed && this->contour_not_taken_length_next > SCALED_EPSILON; }
// Could extrude a complete segment from this to this->prev_on_contour.
bool could_connect_prev() const throw()
bool could_connect_prev() const throw()
{ return ! this->consumed && this->prev_on_contour != this && ! this->prev_on_contour->consumed && ! this->prev_trimmed && ! this->prev_on_contour->next_trimmed; }
// Could extrude a complete segment from this to this->next_on_contour.
bool could_connect_next() const throw()
bool could_connect_next() const throw()
{ return ! this->consumed && this->next_on_contour != this && ! this->next_on_contour->consumed && ! this->next_trimmed && ! this->next_on_contour->prev_trimmed; }
};
@@ -566,7 +569,7 @@ static void take(Polyline &pl1, const Polyline &pl2, const Points &contour, Cont
}
static void take_limited(
Polyline &pl1, const Points &contour, const std::vector<double> &params,
Polyline &pl1, const Points &contour, const std::vector<double> &params,
ContourIntersectionPoint *cp_start, ContourIntersectionPoint *cp_end, bool clockwise, double take_max_length, double line_half_width)
{
#ifndef NDEBUG
@@ -730,8 +733,8 @@ static inline SegmentPoint clip_end_segment_and_point(const Points &polyline, do
// Calculate intersection of a line with a thick segment.
// Returns Eucledian parameters of the line / thick segment overlap.
static inline bool line_rounded_thick_segment_collision(
const Vec2d &line_a, const Vec2d &line_b,
const Vec2d &segment_a, const Vec2d &segment_b, const double offset,
const Vec2d &line_a, const Vec2d &line_b,
const Vec2d &segment_a, const Vec2d &segment_b, const double offset,
std::pair<double, double> &out_interval)
{
const Vec2d line_v0 = line_b - line_a;
@@ -794,8 +797,8 @@ static inline bool line_rounded_thick_segment_collision(
std::pair<double, double> interval;
if (Geometry::liang_barsky_line_clipping_interval(
Vec2d(line_p0.dot(dir_x), line_p0.dot(dir_y)),
Vec2d(line_v0.dot(dir_x), line_v0.dot(dir_y)),
BoundingBoxf(Vec2d(0., - offset), Vec2d(segment_l, offset)),
Vec2d(line_v0.dot(dir_x), line_v0.dot(dir_y)),
BoundingBoxf(Vec2d(0., - offset), Vec2d(segment_l, offset)),
interval))
extend_interval(interval.first, interval.second);
} else
@@ -1155,7 +1158,7 @@ void mark_boundary_segments_touching_infill(
// Clip the infill polyline by the Eucledian distance along the polyline.
SegmentPoint start_point = clip_start_segment_and_point(polyline.points, clip_distance);
SegmentPoint end_point = clip_end_segment_and_point(polyline.points, clip_distance);
if (start_point.valid() && end_point.valid() &&
if (start_point.valid() && end_point.valid() &&
(start_point.idx_segment < end_point.idx_segment || (start_point.idx_segment == end_point.idx_segment && start_point.t < end_point.t))) {
// The clipped polyline is non-empty.
#ifdef INFILL_DEBUG_OUTPUT
@@ -1295,21 +1298,21 @@ struct BoundaryInfillGraph
};
static Direction dir(const Point &p1, const Point &p2) {
return p1.x() == p2.x() ?
return p1.x() == p2.x() ?
(p1.y() < p2.y() ? Up : Down) :
(p1.x() < p2.x() ? Right : Left);
}
const Direction dir_prev(const ContourIntersectionPoint &cp) const {
assert(cp.prev_on_contour);
return cp.could_take_prev() ?
return cp.could_take_prev() ?
dir(this->point(cp), this->point(*cp.prev_on_contour)) :
Taken;
}
const Direction dir_next(const ContourIntersectionPoint &cp) const {
assert(cp.next_on_contour);
return cp.could_take_next() ?
return cp.could_take_next() ?
dir(this->point(cp), this->point(*cp.next_on_contour)) :
Taken;
}
@@ -1367,7 +1370,7 @@ static inline void mark_boundary_segments_overlapping_infill(
assert(interval.first == 0.);
double len_out = closed_contour_distance_ccw(contour_params[cp.point_idx], contour_params[i], contour_params.back()) + interval.second;
if (len_out < cp.contour_not_taken_length_next) {
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// thus at least some of the contour is outside and we will extrude this segment.
inside = false;
break;
@@ -1399,7 +1402,7 @@ static inline void mark_boundary_segments_overlapping_infill(
assert(interval.first == 0.);
double len_out = closed_contour_distance_cw(contour_params[cp.point_idx], contour_params[i], contour_params.back()) + interval.second;
if (len_out < cp.contour_not_taken_length_prev) {
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// thus at least some of the contour is outside and we will extrude this segment.
inside = false;
break;
@@ -1496,7 +1499,7 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
ContourIntersectionPoint *pthis = &out.map_infill_end_point_to_boundary[it->second];
if (pprev) {
pprev->next_on_contour = pthis;
pthis->prev_on_contour = pprev;
pthis->prev_on_contour = pprev;
} else
pfirst = pthis;
contour_intersection_points.emplace_back(pthis);
@@ -1521,7 +1524,7 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
ip->param = contour_params[ip->point_idx];
// and measure distance to the previous and next intersection point.
const double contour_length = contour_params.back();
for (ContourIntersectionPoint *ip : contour_intersection_points)
for (ContourIntersectionPoint *ip : contour_intersection_points)
if (ip->next_on_contour == ip) {
assert(ip->prev_on_contour == ip);
ip->contour_not_taken_length_prev = ip->contour_not_taken_length_next = contour_length;
@@ -1556,6 +1559,18 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
return out;
}
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox Fill::extended_object_bounding_box() const
{
BoundingBox out = bounding_box;
out.merge(Point(out.min.y(), out.min.x()));
out.merge(Point(out.max.y(), out.max.x()));
// The bounding box is scaled by sqrt(2.) to ensure that the bounding box
// covers any possible rotations.
return out.scaled(sqrt(2.));
}
void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams &params)
{
assert(! infill_ordered.empty());
@@ -1927,14 +1942,14 @@ static inline void base_support_extend_infill_lines(Polylines &infill, BoundaryI
// The contour is supposed to enter the "forbidden" zone outside of the (left, right) band at tbegin and also at tend.
static inline void emit_loops_in_band(
// Vertical band, which will trim the contour between tbegin and tend.
coord_t left,
coord_t left,
coord_t right,
// Contour and its parametrization.
const Points &contour,
const std::vector<double> &contour_params,
// Span of the parameters of an arch to trim with the vertical band.
double tbegin,
double tend,
double tend,
// Minimum arch length to put into polylines_out. Shorter arches are not necessary to support a dense support infill.
double min_length,
Polylines &polylines_out)
@@ -1990,13 +2005,13 @@ static inline void emit_loops_in_band(
};
enum InOutBand {
Entering,
Entering,
Leaving,
};
class State {
public:
State(coord_t left, coord_t right, double min_length, Polylines &polylines_out) :
State(coord_t left, coord_t right, double min_length, Polylines &polylines_out) :
m_left(left), m_right(right), m_min_length(min_length), m_polylines_out(polylines_out) {}
void add_inner_point(const Point* p)
@@ -2297,7 +2312,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
#endif // INFILL_DEBUG_OUTPUT
base_support_extend_infill_lines(infill_ordered, graph, spacing, params);
#ifdef INFILL_DEBUG_OUTPUT
export_partial_infill_to_svg(debug_out_path("connect_base_support-extended-%03d.svg", iRun), graph, infill_ordered, polylines_out);
#endif // INFILL_DEBUG_OUTPUT
@@ -2332,7 +2347,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
};
// Connect infill lines at cp and cpo_next_on_contour.
// If the complete arch cannot be taken, then
// If the complete arch cannot be taken, then
// if (take_first)
// take the infill line at cp and an arc from cp towards cp.next_on_contour.
// else
@@ -2626,7 +2641,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
const SupportArcCost &cost_next = *(&cost_prev + 1);
if (cp.contour_not_taken_length_prev > SCALED_EPSILON &&
if (cp.contour_not_taken_length_prev > SCALED_EPSILON &&
(cost_prev.self_loop ?
cost_prev.cost > cap_cost :
cost_prev.cost > cost_veryhigh)) {
@@ -2643,7 +2658,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
polylines_out.emplace_back(std::move(pl));
}
}
if (cp.contour_not_taken_length_next > SCALED_EPSILON &&
if (cp.contour_not_taken_length_next > SCALED_EPSILON &&
(cost_next.self_loop ?
cost_next.cost > cap_cost :
cost_next.cost > cost_veryhigh)) {
+31 -9
View File
@@ -36,6 +36,15 @@ public:
InfillFailedException() : Slic3r::RuntimeError("Infill failed") {}
};
struct LockRegionParam
{
LockRegionParam() {}
std::map<float, ExPolygons> skin_density_params;
std::map<float, ExPolygons> skeleton_density_params;
std::map<Flow, ExPolygons> skin_flow_params;
std::map<Flow, ExPolygons> skeleton_flow_params;
};
struct FillParams
{
bool full_infill() const { return density > 0.9999f; }
@@ -72,6 +81,7 @@ struct FillParams
// For 2D lattice
coordf_t lattice_angle_1 { 0.f };
coordf_t lattice_angle_2 { 0.f };
InfillPattern pattern{ ipRectilinear };
// For 2D Honeycomb
float infill_overhang_angle { 60 };
@@ -85,6 +95,13 @@ struct FillParams
const PrintRegionConfig* config{ nullptr };
bool dont_sort{ false }; // do not sort the lines, just simply connect them
bool can_reverse{true};
float horiz_move{0.0}; //move infill to get cross zag pattern
bool symmetric_infill_y_axis{false};
coord_t symmetric_y_axis{0};
bool locked_zag{false};
float infill_lock_depth{0.0};
float skin_infill_depth{0.0};
};
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
@@ -102,7 +119,7 @@ public:
// in radians, ccw, 0 = East
float angle;
// Orca: enable angle shifting for layer change
bool rotate_angle{ true };
float rotate_angle{ M_PI/180.0 };
// 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.
@@ -135,20 +152,25 @@ public:
static bool use_bridge_flow(const InfillPattern type);
void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; }
BoundingBox extended_object_bounding_box() const;
// Use bridge flow for the fill?
virtual bool use_bridge_flow() const { return false; }
// Do not sort the fill lines to optimize the print head path?
virtual bool no_sort() const { return false; }
virtual bool is_self_crossing() = 0;
// Return true if infill has a consistent pattern between layers.
virtual bool has_consistent_pattern() const { return false; }
// Perform the fill.
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual ThickPolylines fill_surface_arachne(const Surface* surface, const FillParams& params);
virtual void set_lock_region_param(const LockRegionParam &lock_param){};
// BBS: this method is used to fill the ExtrusionEntityCollection.
// It call fill_surface by default
virtual void fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out);
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out);
protected:
Fill() :
@@ -159,7 +181,7 @@ protected:
overlap(0.),
// Initial angle is undefined.
angle(FLT_MAX),
rotate_angle(true),
rotate_angle(M_PI/180.0),
link_max_length(0),
loop_clipping(0),
// The initial bounding box is empty, therefore undefined.
@@ -168,11 +190,11 @@ protected:
// The expolygon may be modified by the method to avoid a copy.
virtual void _fill_surface_single(
const FillParams & /* params */,
const FillParams & /* params */,
unsigned int /* thickness_layers */,
const std::pair<float, Point> & /* direction */,
const std::pair<float, Point> & /* direction */,
ExPolygon /* expolygon */,
Polylines & /* polylines_out */) {};
Polylines & /* polylines_out */) {}
// Used for concentric infill to generate ThickPolylines using Arachne.
virtual void _fill_surface_single(const FillParams& params,
@@ -181,7 +203,7 @@ protected:
ExPolygon expolygon,
ThickPolylines& thick_polylines_out) {}
virtual float _layer_angle(size_t idx) const { return (rotate_angle && (idx & 1)) ? float(M_PI/2.) : 0; }
virtual float _layer_angle(size_t idx) const { return rotate_angle; }
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
+1
View File
@@ -9,6 +9,7 @@ class FillConcentric : public Fill
{
public:
~FillConcentric() override = default;
bool is_self_crossing() override { return false; }
protected:
Fill* clone() const override { return new FillConcentric(*this); };
@@ -10,6 +10,7 @@ class FillConcentricInternal : public Fill
public:
~FillConcentricInternal() override = default;
void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
bool is_self_crossing() override { return false; }
protected:
Fill* clone() const override { return new FillConcentricInternal(*this); };
+1
View File
@@ -14,6 +14,7 @@ class FillCrossHatch : public Fill
public:
Fill *clone() const override { return new FillCrossHatch(*this); };
~FillCrossHatch() override {}
bool is_self_crossing() override { return false; }
protected:
void _fill_surface_single(
+4
View File
@@ -168,6 +168,10 @@ void FillGyroid::_fill_surface_single(
// align bounding box to a multiple of our grid module
bb.merge(align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
// Expand the bounding box to avoid artifacts at the edges
coord_t expand = 10 * (scale_(this->spacing));
bb.offset(expand);
// generate pattern
Polylines polylines = make_gyroid_waves(
scale_(this->z),
+1
View File
@@ -15,6 +15,7 @@ public:
// require bridge flow since most of this pattern hangs in air
bool use_bridge_flow() const override { return false; }
bool is_self_crossing() override { return false; }
// Correction applied to regular infill angle to maximize printing
// speed in default configuration (degrees)
+1
View File
@@ -13,6 +13,7 @@ class FillHoneycomb : public Fill
{
public:
~FillHoneycomb() override {}
bool is_self_crossing() override { return false; }
protected:
Fill* clone() const override { return new FillHoneycomb(*this); };
+1
View File
@@ -20,6 +20,7 @@ class Filler : public Slic3r::Fill
{
public:
~Filler() override = default;
bool is_self_crossing() override { return false; }
Generator *generator { nullptr };
protected:
+1
View File
@@ -14,6 +14,7 @@ class FillLine : public Fill
public:
Fill* clone() const override { return new FillLine(*this); };
~FillLine() override = default;
bool is_self_crossing() override { return false; }
protected:
void _fill_surface_single(
+1
View File
@@ -37,6 +37,7 @@ class FillPlanePath : public Fill
{
public:
~FillPlanePath() override = default;
bool is_self_crossing() override { return false; }
protected:
void _fill_surface_single(
+177 -32
View File
@@ -987,7 +987,6 @@ static std::vector<SegmentedIntersectionLine> slice_region_by_vertical_lines(con
throw;
}
#endif //INFILL_DEBUG_OUTPUT
return segs;
}
@@ -1352,8 +1351,11 @@ static SegmentIntersection& end_of_vertical_run(SegmentedIntersectionLine &il, S
return const_cast<SegmentIntersection&>(end_of_vertical_run(std::as_const(il), std::as_const(start)));
}
static void traverse_graph_generate_polylines(
const ExPolygonWithOffset& poly_with_offset, const FillParams& params, const coord_t link_max_length, std::vector<SegmentedIntersectionLine>& segs, Polylines& polylines_out)
static void traverse_graph_generate_polylines(const ExPolygonWithOffset &poly_with_offset,
const FillParams &params,
std::vector<SegmentedIntersectionLine> &segs,
const bool consistent_pattern,
Polylines &polylines_out)
{
// For each outer only chords, measure their maximum distance to the bow of the outer contour.
// Mark an outer only chord as consumed, if the distance is low.
@@ -1387,34 +1389,28 @@ static void traverse_graph_generate_polylines(
pointLast = polylines_out.back().points.back();
for (;;) {
if (i_intersection == -1) {
// The path has been interrupted. Find a next starting point, closest to the previous extruder position.
coordf_t dist2min = std::numeric_limits<coordf_t>().max();
for (int i_vline2 = 0; i_vline2 < int(segs.size()); ++ i_vline2) {
// The path has been interrupted. Find a next starting point.
for (int i_vline2 = 0; i_vline2 < int(segs.size()); ++i_vline2) {
const SegmentedIntersectionLine &vline = segs[i_vline2];
if (! vline.intersections.empty()) {
if (!vline.intersections.empty()) {
assert(vline.intersections.size() > 1);
// Even number of intersections with the loops.
assert((vline.intersections.size() & 1) == 0);
assert(vline.intersections.front().type == SegmentIntersection::OUTER_LOW);
for (int i = 0; i < int(vline.intersections.size()); ++ i) {
const SegmentIntersection& intrsctn = vline.intersections[i];
// For infill that needs to be consistent between layers (like Zig Zag),
// we are switching between forward and backward passes based on the line index.
const bool forward_pass = !consistent_pattern || (i_vline2 % 2 == 0);
for (int i = 0; i < int(vline.intersections.size()); ++i) {
const int intrsctn_idx = forward_pass ? i : int(vline.intersections.size()) - i - 1;
const SegmentIntersection &intrsctn = vline.intersections[intrsctn_idx];
if (intrsctn.is_outer()) {
assert(intrsctn.is_low() || i > 0);
bool consumed = intrsctn.is_low() ?
intrsctn.consumed_vertical_up :
vline.intersections[i - 1].consumed_vertical_up;
if (! consumed) {
coordf_t dist2 = sqr(coordf_t(pointLast(0) - vline.pos)) + sqr(coordf_t(pointLast(1) - intrsctn.pos()));
if (dist2 < dist2min) {
dist2min = dist2;
i_vline = i_vline2;
i_intersection = i;
//FIXME We are taking the first left point always. Verify, that the caller chains the paths
// by a shortest distance, while reversing the paths if needed.
//if (polylines_out.empty())
// Initial state, take the first line, which is the first from the left.
goto found;
}
assert(intrsctn.is_low() || intrsctn_idx > 0);
const bool consumed = intrsctn.is_low() ? intrsctn.consumed_vertical_up : vline.intersections[intrsctn_idx - 1].consumed_vertical_up;
if (!consumed) {
i_vline = i_vline2;
i_intersection = intrsctn_idx;
goto found;
}
}
}
@@ -1487,9 +1483,13 @@ static void traverse_graph_generate_polylines(
// 1) Find possible connection points on the previous / next vertical line.
int i_prev = it->left_horizontal();
int i_next = it->right_horizontal();
bool intersection_prev_valid = intersection_on_prev_vertical_line_valid(segs, i_vline, i_intersection);
// To ensure pattern consistency between layers for Zig Zag infill, we always
// try to connect to the next vertical line and never to the previous vertical line.
bool intersection_prev_valid = intersection_on_prev_vertical_line_valid(segs, i_vline, i_intersection) && !consistent_pattern;
bool intersection_next_valid = intersection_on_next_vertical_line_valid(segs, i_vline, i_intersection);
bool intersection_horizontal_valid = intersection_prev_valid || intersection_next_valid;
// Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
if (i_prev != -1)
segs[i_vline - 1].intersections[i_prev].consumed_perimeter_right = true;
@@ -2737,6 +2737,17 @@ static void polylines_from_paths(const std::vector<MonotonicRegionLink> &path, c
}
}
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox FillRectilinear::extended_object_bounding_box() const {
BoundingBox out = this->bounding_box;
out.merge(Point(out.min.y(), out.min.x()));
out.merge(Point(out.max.y(), out.max.x()));
// The bounding box is scaled by sqrt(2.) to ensure that the bounding box
// covers any possible rotations.
return out.scaled(sqrt(2.));
}
bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out)
{
// At the end, only the new polylines will be rotated back.
@@ -2749,6 +2760,8 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
// Rotate polygons so that we can work with vertical lines here
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
if (params.locked_zag)
rotate_vector.first += float(M_PI/2.);
rotate_vector.first += angleBase;
assert(params.density > 0.0001f && params.density <= 1.f);
@@ -2766,11 +2779,14 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
return true;
}
BoundingBox bounding_box = poly_with_offset.bounding_box_src();
// For infill that needs to be consistent between layers (like Zig Zag),
// we use bounding box of whole object to match vertical lines between layers.
BoundingBox bounding_box_src = poly_with_offset.bounding_box_src();
BoundingBox bounding_box = this->has_consistent_pattern() ? this->extended_object_bounding_box() : bounding_box_src;
// define flow spacing according to requested density
if (params.full_infill() && !params.dont_adjust) {
line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
line_spacing = this->_adjust_solid_spacing(bounding_box_src.size().x(), line_spacing);
this->spacing = unscale<double>(line_spacing);
} else {
// extend bounding box so that our pattern will be aligned with other layers
@@ -2792,6 +2808,13 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
if (params.full_infill())
x0 += (line_spacing + coord_t(SCALED_EPSILON)) / 2;
int gap_line = params.horiz_move / line_spacing;
if (gap_line % 2 == 0) {
x0 += params.horiz_move - gap_line * line_spacing;
} else {
x0 += params.horiz_move - (gap_line - 1) * line_spacing;
n_vlines += 1;
}
#ifdef SLIC3R_DEBUG
static int iRun = 0;
BoundingBox bbox_svg = poly_with_offset.bounding_box_outer();
@@ -2803,7 +2826,6 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
}
iRun ++;
#endif /* SLIC3R_DEBUG */
std::vector<SegmentedIntersectionLine> segs = slice_region_by_vertical_lines(poly_with_offset, n_vlines, x0, line_spacing);
// Connect by horizontal / vertical links, classify the links based on link_max_length as too long.
connect_segment_intersections_by_contours(poly_with_offset, segs, params, link_max_length);
@@ -2848,8 +2870,9 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
std::vector<MonotonicRegionLink> path = chain_monotonic_regions(regions, poly_with_offset, segs, rng);
polylines_from_paths(path, poly_with_offset, segs, polylines_out);
}
} else
traverse_graph_generate_polylines(poly_with_offset, params, this->link_max_length, segs, polylines_out);
} else {
traverse_graph_generate_polylines(poly_with_offset, params, segs, this->has_consistent_pattern(), polylines_out);
}
#ifdef SLIC3R_DEBUG
{
@@ -2876,6 +2899,11 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
//FIXME rather simplify the paths to avoid very short edges?
//assert(! it->has_duplicate_points());
it->remove_duplicate_points();
//get origin direction infill
if (params.symmetric_infill_y_axis) {
it->symmetric_y(params.symmetric_y_axis);
}
}
#ifdef SLIC3R_DEBUG
@@ -2884,6 +2912,8 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
assert(! polyline.has_duplicate_points());
#endif /* SLIC3R_DEBUG */
return true;
}
@@ -2963,7 +2993,8 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillPar
Polylines FillRectilinear::fill_surface(const Surface *surface, const FillParams &params)
{
Polylines polylines_out;
if (params.full_infill()) {
// 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 (!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 {
@@ -3409,5 +3440,119 @@ void FillMonotonicLineWGapFill::fill_surface_by_lines(const Surface* surface, co
}
}*/
void FillLockedZag::fill_surface_locked_zag (const Surface * surface,
const FillParams & params,
std::vector<std::pair<Polylines, Flow>> &multi_width_polyline)
{
// merge different part exps
// diff skin flow
Polylines skin_lines;
Polylines skeloton_lines;
double offset_threshold = params.skin_infill_depth;
double overlap_threshold = params.infill_lock_depth;
Surface cross_surface = *surface;
Surface zig_surface = *surface;
// inner exps
// inner union exps
ExPolygons zig_expas = offset_ex({surface->expolygon}, -offset_threshold);
ExPolygons cross_expas = diff_ex(surface->expolygon, zig_expas);
bool zig_get = false;
FillParams zig_params = params;
zig_params.horiz_move = 0;
// generate skeleton for diff density
auto generate_for_different_flow = [&multi_width_polyline](const std::map<Flow, ExPolygons> &flow_params, const Polylines &polylines) {
auto it = flow_params.begin();
while (it != flow_params.end()) {
ExPolygons region_exp = union_safety_offset_ex(it->second);
Polylines polys = intersection_pl(polylines, region_exp);
multi_width_polyline.emplace_back(polys, it->first);
it++;
}
};
auto it = this->lock_param.skeleton_density_params.begin();
while (it != this->lock_param.skeleton_density_params.end()) {
ExPolygons region_exp = union_safety_offset_ex(it->second);
ExPolygons exps = intersection_ex(region_exp, zig_expas);
zig_params.density = it->first;
exps = intersection_ex(offset_ex(exps, overlap_threshold), surface->expolygon);
for (ExPolygon &exp : exps) {
zig_surface.expolygon = exp;
Polylines zig_polylines_out = this->fill_surface(&zig_surface, zig_params);
skeloton_lines.insert(skeloton_lines.end(), zig_polylines_out.begin(), zig_polylines_out.end());
}
it++;
}
// set skeleton flow
generate_for_different_flow(this->lock_param.skeleton_flow_params, skeloton_lines);
// skin exps
bool cross_get = false;
FillParams cross_params = params;
cross_params.locked_zag = false;
auto skin_density = this->lock_param.skin_density_params.begin();
while (skin_density != this->lock_param.skin_density_params.end()) {
ExPolygons region_exp = union_safety_offset_ex(skin_density->second);
ExPolygons exps = intersection_ex(region_exp, cross_expas);
cross_params.density = skin_density->first;
for (ExPolygon &exp : exps) {
cross_surface.expolygon = exp;
Polylines cross_polylines_out = this->fill_surface(&cross_surface, cross_params);
skin_lines.insert(skin_lines.end(), cross_polylines_out.begin(), cross_polylines_out.end());
}
skin_density++;
}
generate_for_different_flow(this->lock_param.skin_flow_params, skin_lines);
}
void FillLockedZag::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out)
{
Polylines polylines;
ThickPolylines thick_polylines;
std::vector<std::pair<Polylines, Flow>> multi_width_polyline;
try {
this->fill_surface_locked_zag(surface, params, multi_width_polyline);
}
catch (InfillFailedException&) {}
if (!thick_polylines.empty() || !multi_width_polyline.empty()) {
// Save into layer.
ExtrusionEntityCollection* eec = nullptr;
out.push_back(eec = new ExtrusionEntityCollection());
// Only concentric fills are not sorted.
eec->no_sort = this->no_sort();
size_t idx = eec->entities.size();
{
for (std::pair<Polylines, Flow> &poly_with_flow: multi_width_polyline) {
// calculate actual flow from spacing (which might have been adjusted by the infill
// pattern generator)
double flow_mm3_per_mm = poly_with_flow.second.mm3_per_mm();
double flow_width = poly_with_flow.second.width();
if (params.using_internal_flow) {
// if we used the internal flow we're not doing a solid infill
// so we can safely ignore the slight variation that might have
// been applied to f->spacing
} else {
Flow new_flow = poly_with_flow.second.with_spacing(this->spacing);
flow_mm3_per_mm = new_flow.mm3_per_mm();
flow_width = new_flow.width();
}
extrusion_entities_append_paths(
eec->entities, std::move(poly_with_flow.first),
params.extrusion_role,
flow_mm3_per_mm, float(flow_width), poly_with_flow.second.height());
}
}
if (!params.can_reverse) {
for (size_t i = idx; i < eec->entities.size(); i++)
eec->entities[i]->set_reverse();
}
}
}
} // namespace Slic3r
+46 -3
View File
@@ -16,6 +16,7 @@ public:
Fill* clone() const override { return new FillRectilinear(*this); }
~FillRectilinear() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool is_self_crossing() override { return false; }
protected:
// Fill by single directional lines, interconnect the lines along perimeters.
@@ -28,6 +29,9 @@ protected:
float pattern_shift;
};
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox extended_object_bounding_box() const;
};
class FillAlignedRectilinear : public FillRectilinear
@@ -65,6 +69,7 @@ public:
Fill* clone() const override { return new FillGrid(*this); }
~FillGrid() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool is_self_crossing() override { return true; }
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@@ -89,6 +94,7 @@ public:
Fill* clone() const override { return new FillTriangles(*this); }
~FillTriangles() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool is_self_crossing() override { return true; }
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@@ -101,6 +107,7 @@ public:
Fill* clone() const override { return new FillStars(*this); }
~FillStars() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool is_self_crossing() override { return true; }
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@@ -113,6 +120,7 @@ public:
Fill* clone() const override { return new FillCubic(*this); }
~FillCubic() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool is_self_crossing() override { return true; }
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@@ -170,6 +178,7 @@ public:
public:
~FillMonotonicLineWGapFill() override = default;
void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
bool is_self_crossing() override { return false; }
protected:
Fill* clone() const override { return new FillMonotonicLineWGapFill(*this); };
@@ -179,9 +188,43 @@ private:
void fill_surface_by_lines(const Surface* surface, const FillParams& params, Polylines& polylines_out);
};*/
Points sample_grid_pattern(const ExPolygon& expolygon, coord_t spacing, const BoundingBox& global_bounding_box);
Points sample_grid_pattern(const ExPolygons& expolygons, coord_t spacing, const BoundingBox& global_bounding_box);
Points sample_grid_pattern(const Polygons& polygons, coord_t spacing, const BoundingBox& global_bounding_box);
class FillZigZag : public FillRectilinear
{
public:
Fill* clone() const override { return new FillZigZag(*this); }
~FillZigZag() override = default;
bool has_consistent_pattern() const override { return true; }
};
class FillCrossZag : public FillRectilinear
{
public:
Fill *clone() const override { return new FillCrossZag(*this); }
~FillCrossZag() override = default;
bool has_consistent_pattern() const override { return true; }
};
class FillLockedZag : public FillRectilinear
{
public:
Fill *clone() const override { return new FillLockedZag(*this); }
~FillLockedZag() override = default;
LockRegionParam lock_param;
void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
bool has_consistent_pattern() const override { return true; }
void set_lock_region_param(const LockRegionParam &lock_param) override { this->lock_param = lock_param;};
void fill_surface_locked_zag(const Surface * surface,
const FillParams & params,
std::vector<std::pair<Polylines, Flow>> &multi_width_polyline);
};
Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing, const BoundingBox &global_bounding_box);
Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing, const BoundingBox &global_bounding_box);
Points sample_grid_pattern(const Polygons &polygons, coord_t spacing, const BoundingBox &global_bounding_box);
} // namespace Slic3r
+131 -417
View File
@@ -1,445 +1,159 @@
#include "../ClipperUtils.hpp"
#include "FillTpmsD.hpp"
#include <cmath>
#include <algorithm>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <tbb/parallel_for.h>
// From Creality Print
//#include <cstddef>
#include "../ClipperUtils.hpp"
#include "../ShortestPath.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/Fill/FillBase.hpp"
#include "libslic3r/Point.hpp"
#include "libslic3r/Polygon.hpp"
#include "libslic3r/libslic3r.h"
#include "FillTpmsD.hpp"
namespace Slic3r {
using namespace std;
struct myPoint
{
coord_t x, y;
};
class LineSegmentMerger
{
public:
void mergeSegments(const vector<pair<myPoint, myPoint>>& segments, vector<vector<myPoint>>& polylines2)
{
std::unordered_map<int, myPoint> point_id_xy;
std::set<std::pair<int, int>> segment_ids;
std::unordered_map<int64_t, int> map_keyxy_pointid;
auto get_itr = [&](coord_t x, coord_t y) {
for (auto i : {0}) //,-2,2
{
for (auto j : {0}) //,-2,2
{
int64_t combined_key1 = static_cast<int64_t>(x + i) << 32 | static_cast<uint32_t>(y + j);
auto itr1 = map_keyxy_pointid.find(combined_key1);
if (itr1 != map_keyxy_pointid.end()) {
return itr1;
}
}
}
return map_keyxy_pointid.end();
};
int pointid = 0;
for (const auto& segment : segments) {
coord_t x = segment.first.x;
coord_t y = segment.first.y;
auto itr = get_itr(x, y);
int segmentid0 = -1;
if (itr == map_keyxy_pointid.end()) {
int64_t combined_key = static_cast<int64_t>(x) << 32 | static_cast<uint32_t>(y);
segmentid0 = pointid;
point_id_xy[pointid] = segment.first;
map_keyxy_pointid[combined_key] = pointid++;
} else {
segmentid0 = itr->second;
}
int segmentid1 = -1;
x = segment.second.x;
y = segment.second.y;
itr = get_itr(x, y);
if (itr == map_keyxy_pointid.end()) {
int64_t combined_key = static_cast<int64_t>(x) << 32 | static_cast<uint32_t>(y);
segmentid1 = pointid;
point_id_xy[pointid] = segment.second;
map_keyxy_pointid[combined_key] = pointid++;
} else {
segmentid1 = itr->second;
}
if (segmentid0 != segmentid1) {
segment_ids.insert(segmentid0 < segmentid1 ? std::make_pair(segmentid0, segmentid1) :
std::make_pair(segmentid1, segmentid0));
}
}
unordered_map<int, vector<int>> graph;
unordered_set<int> visited;
vector<vector<int>> polylines;
// Build the graph
for (const auto& segment : segment_ids) {
graph[segment.first].push_back(segment.second);
graph[segment.second].push_back(segment.first);
}
vector<int> startnodes;
for (const auto& node : graph) {
if (node.second.size() == 1) {
startnodes.push_back(node.first);
}
}
// Find all connected components
for (const auto& point_first : startnodes) {
if (visited.find(point_first) == visited.end()) {
vector<int> polyline;
dfs(point_first, graph, visited, polyline);
polylines.push_back(std::move(polyline));
}
}
for (const auto& point : graph) {
if (visited.find(point.first) == visited.end()) {
vector<int> polyline;
dfs(point.first, graph, visited, polyline);
polylines.push_back(std::move(polyline));
}
}
for (auto& pl : polylines) {
vector<myPoint> tmpps;
for (auto& pid : pl) {
tmpps.push_back(point_id_xy[pid]);
}
polylines2.push_back(tmpps);
}
}
private:
void dfs(const int& start_node,
std::unordered_map<int, std::vector<int>>& graph,
std::unordered_set<int>& visited,
std::vector<int>& polyline)
{
std::vector<int> stack;
stack.reserve(graph.size());
stack.push_back(start_node);
while (!stack.empty()) {
int node = stack.back();
stack.pop_back();
if (!visited.insert(node).second) {
continue;
}
polyline.push_back(node);
auto& neighbors = graph[node];
for (const auto& neighbor : neighbors) {
if (visited.find(neighbor) == visited.end()) {
stack.push_back(neighbor);
}
}
}
}
};
namespace MarchingSquares {
struct Point
{
double x, y;
};
vector<double> getGridValues(int i, int j, vector<vector<double>>& data)
{
vector<double> values;
values.push_back(data[i][j + 1]);
values.push_back(data[i + 1][j + 1]);
values.push_back(data[i + 1][j]);
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,
std::vector<int> p1ij,
std::vector<int> p2ij,
double v1,
double v2,
double contourValue)
{
Point p1;
p1.x = posxy[p1ij[0]][p1ij[1]].x;
p1.y = posxy[p1ij[0]][p1ij[1]].y;
Point p2;
p2.x = posxy[p2ij[0]][p2ij[1]].x;
p2.y = posxy[p2ij[0]][p2ij[1]].y;
double mu = (contourValue - v1) / (v2 - v1);
Point p;
p.x = p1.x + mu * (p2.x - p1.x);
p.y = p1.y + mu * (p2.y - p1.y);
return p;
static double scaled_floor(double x,double scale){
return std::floor(x/scale)*scale;
}
void process_block(int i,
int j,
vector<vector<double>>& data,
double contourValue,
std::vector<std::vector<MarchingSquares::Point>>& posxy,
vector<Point>& contourPoints)
static Polylines make_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height)
{
vector<double> values = getGridValues(i, j, data);
vector<bool> isNeedContour;
for (double value : values) {
isNeedContour.push_back(needContour(value, contourValue));
}
int index = 0;
if (isNeedContour[0])
index |= 1;
if (isNeedContour[1])
index |= 2;
if (isNeedContour[2])
index |= 4;
if (isNeedContour[3])
index |= 8;
vector<Point> points;
switch (index) {
case 0:
case 15: break;
const double scaleFactor = scale_(line_spacing) / density_adjusted;
case 1:
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
// tolerance in scaled units. clamp the maximum tolerance as there's
// no processing-speed benefit to do so beyond a certain point
const double tolerance = std::min(line_spacing / 2, FillTpmsD::PatternTolerance) / unscale<double>(scaleFactor);
break;
case 14:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
break;
//scale factor for 5% : 8 712 388
// 1z = 10^-6 mm ?
const double z = gridZ / scaleFactor;
Polylines result;
case 2:
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
break;
case 13:
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 3:
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
break;
case 12:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 4:
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 11:
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
break;
case 5:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i + 1, j}, values[3], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 6:
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
break;
case 9:
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
break;
case 7:
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
break;
case 8:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
break;
case 10:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i + 1, j}, values[3], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
}
for (Point& p : points) {
contourPoints.push_back(p);
}
//sin(x)*sin(y)*sin(z)-cos(x)*cos(y)*cos(z)=0
//2*sin(x)*sin(y)*sin(z)-2*cos(x)*cos(y)*cos(z)=0
//(cos(x-y)-cos(x+y))*sin(z)-(cos(x-y)+cos(x+y))*cos(z)=0
//(sin(z)-cos(z))*cos(x-y)-(sin(z)+cos(z))*cos(x+y)=0
double a=sin(z)-cos(z);
double b=sin(z)+cos(z);
//a*cos(x-y)-b*cos(x+y)=0
//u=x-y, v=x+y
double minU=0-height;
double maxU=width-0;
double minV=0+0;
double maxV=width+height;
//a*cos(u)-b*cos(v)=0
//if abs(b)<abs(a), then u=acos(b/a*cos(v)) is a continuous line
//otherwise we swap u and v
const bool swapUV=(std::abs(a)>std::abs(b));
if(swapUV) {
std::swap(a,b);
std::swap(minU,minV);
std::swap(maxU,maxV);
}
std::vector<std::pair<double,double>> wave;
{//fill one wave
const auto v=[&](double u){return acos(a/b*cos(u));};
for(int c=0;c<=4;++c){
const double u=minU+2*M_PI*c/4;
wave.emplace_back(u,v(u));
}
{//refine
int current=0;
while(current+1<int(wave.size())){
const double u1=wave[current].first;
const double u2=wave[current+1].first;
const double middleU=(u1+u2)/2;
const double v1=wave[current].second;
const double v2=wave[current+1].second;
const double middleV=v((u1+u2)/2);
if(std::abs(middleV-(v1+v2)/2)>tolerance)
wave.emplace(wave.begin()+current+1,middleU,middleV);
else
++current;
}
}
for(int c=1;c<int(wave.size()) && wave.back().first<maxU;++c)//we start from 1 because the 0-th one is already duplicated as the last one in a period
wave.emplace_back(wave[c].first+2*M_PI,wave[c].second);
}
for(double vShift=scaled_floor(minV,2*M_PI);vShift<maxV+2*M_PI;vShift+=2*M_PI) {
for(bool forwardRoot:{false,true}) {
result.emplace_back();
for(const auto &pair:wave) {
const double u=pair.first;
double v=pair.second;
v=(forwardRoot?v:-v)+vShift;
const double x=(u+v)/2;
const double y=(v-u)/2*(swapUV?-1:1);
result.back().points.emplace_back(x*scaleFactor,y*scaleFactor);
}
}
}
//todo: select the step better
return result;
}
void drawContour(double contourValue,
int gridSize_w,
int gridSize_h,
vector<vector<double>>& data,
std::vector<std::vector<MarchingSquares::Point>>& posxy,
Polylines& repls)
// FIXME: needed to fix build on Mac on buildserver
constexpr double FillTpmsD::PatternTolerance;
void FillTpmsD::_fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out)
{
vector<Point> contourPoints;
int total_size = (gridSize_h - 1) * (gridSize_w - 1);
vector<vector<Point>> contourPointss;
contourPointss.resize(total_size);
tbb::parallel_for(tbb::blocked_range<size_t>(0, total_size),
[&contourValue, &posxy, &contourPointss, &data, &gridSize_w](const tbb::blocked_range<size_t>& range) {
for (size_t k = range.begin(); k < range.end(); ++k) {
int i = k / (gridSize_w - 1); //
int j = k % (gridSize_w - 1); //
process_block(i, j, data, contourValue, posxy, contourPointss[k]);
}
});
vector<pair<myPoint, myPoint>> segments2;
myPoint p1, p2;
for (int k = 0; k < total_size; k++) {
for (int i = 0; i < contourPointss[k].size() / 2; i++) {
p1.x = scale_(contourPointss[k][i * 2].x);
p1.y = scale_(contourPointss[k][i * 2].y);
p2.x = scale_(contourPointss[k][i * 2 + 1].x);
p2.y = scale_(contourPointss[k][i * 2 + 1].y);
segments2.push_back({p1, p2});
}
}
LineSegmentMerger merger;
vector<vector<myPoint>> result;
merger.mergeSegments(segments2, result);
for (vector<myPoint>& p : result) {
Polyline repltmp;
for (myPoint& pt : p) {
repltmp.points.push_back(Slic3r::Point(pt.x, pt.y));
}
repltmp.simplify(scale_(0.05f));
repls.push_back(repltmp);
}
}
} // namespace MarchingSquares
static float sin_table[360];
static float cos_table[360];
static bool g_is_init = false;
#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);
}
}
static float get_sin(float angle)
{
angle = angle * PIratio;
int index = static_cast<int>(std::fmod(angle, 360) + 360) % 360;
return sin_table[index];
}
static float get_cos(float angle)
{
angle = angle * PIratio;
int index = static_cast<int>(std::fmod(angle, 360) + 360) % 360;
return cos_table[index];
}
FillTpmsD::FillTpmsD()
{
if (!g_is_init) {
initialize_lookup_tables();
g_is_init = true;
}
}
void FillTpmsD::_fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
Polylines& polylines_out)
{
auto infill_angle = float(this->angle - (CorrectionAngle * 2 * M_PI) / 360.);
if (std::abs(infill_angle) >= EPSILON)
auto infill_angle = float(this->angle + (CorrectionAngle * 2*M_PI) / 360.);
if(std::abs(infill_angle) >= EPSILON)
expolygon.rotate(-infill_angle);
float vari_T = 2.98 * spacing / params.density; // Infill density adjustment factor for TPMS-D
BoundingBox bb = expolygon.contour.bounding_box();
// Density adjusted to have a good %of weight.
double density_adjusted = std::max(0., params.density * DensityAdjust);
// Distance between the gyroid waves in scaled coordinates.
coord_t distance = coord_t(scale_(this->spacing) / density_adjusted);
BoundingBox bb = expolygon.contour.bounding_box();
auto cenpos = unscale(bb.center());
auto boxsize = unscale(bb.size());
float xlen = boxsize.x();
float ylen = boxsize.y();
// align bounding box to a multiple of our grid module
bb.merge(align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
float delta = 0.25f;
float myperiod = 2 * PI / vari_T;
float c_z = myperiod * this->z;
float cos_z = get_cos(c_z);
float sin_z = get_sin(c_z);
// generate pattern
Polylines polylines = make_waves(
scale_(this->z),
density_adjusted,
this->spacing,
ceil(bb.size()(0) / distance) + 1.,
ceil(bb.size()(1) / distance) + 1.);
auto scalar_field = [&](float x, float y) {
// TPMS-D
float a_x = myperiod * x;
float b_y = myperiod * y;
float r = get_cos(a_x) * get_cos(b_y) * cos_z - get_sin(a_x) * get_sin(b_y) * sin_z;
return r;
};
// shift the polyline to the grid origin
for (Polyline &pl : polylines)
pl.translate(bb.min);
std::vector<std::vector<MarchingSquares::Point>> posxy;
int i = 0, j = 0;
std::vector<MarchingSquares::Point> allptpos;
for (float y = -(ylen) / 2.0f - 2; y < (ylen) / 2.0f + 2; 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++) {
MarchingSquares::Point pt;
pt.x = cenpos.x() + x;
pt.y = cenpos.y() + y;
colposxy.push_back(pt);
}
posxy.push_back(colposxy);
polylines = intersection_pl(polylines, expolygon);
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());
}
std::vector<std::vector<double>> data(posxy.size(), std::vector<double>(posxy[0].size()));
int width = posxy[0].size();
int height = posxy.size();
int total_size = (height) * (width);
tbb::parallel_for(tbb::blocked_range<size_t>(0, total_size),
[&width, &scalar_field, &data, &posxy](const tbb::blocked_range<size_t>& range) {
for (size_t k = range.begin(); k < range.end(); ++k) {
int i = k / (width);
int j = k % (width);
data[i][j] = scalar_field(posxy[i][j].x, posxy[i][j].y);
}
});
Polylines polylines;
MarchingSquares::drawContour(0, j, i, data, posxy, polylines);
polylines = intersection_pl(polylines, expolygon);
if (!polylines.empty()) {
// connect lines
size_t polylines_out_first_idx = polylines_out.size();
if (params.dont_connect())
append(polylines_out, chain_polylines(polylines));
if (! polylines.empty()) {
// connect lines
size_t polylines_out_first_idx = polylines_out.size();
if (params.dont_connect())
append(polylines_out, chain_polylines(polylines));
else
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
// new paths must be rotated back
// 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);
}
for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it)
it->rotate(infill_angle);
}
}
}
+18 -3
View File
@@ -1,19 +1,25 @@
#ifndef slic3r_FillTpmsD_hpp_
#define slic3r_FillTpmsD_hpp_
#include "../libslic3r.h"
#include <utility>
#include "libslic3r/libslic3r.h"
#include "FillBase.hpp"
#include "libslic3r/ExPolygon.hpp"
#include "libslic3r/Polyline.hpp"
namespace Slic3r {
class Point;
class FillTpmsD : public Fill
{
public:
FillTpmsD();
FillTpmsD() {}
Fill* clone() const override { return new FillTpmsD(*this); }
// require bridge flow since most of this pattern hangs in air
bool use_bridge_flow() const override { return false; }
// Correction applied to regular infill angle to maximize printing
// speed in default configuration (degrees)
@@ -24,8 +30,17 @@ public:
const std::pair<float, Point>& direction,
ExPolygon expolygon,
Polylines& polylines_out) override;
bool is_self_crossing() override { return false; }
// Density adjustment to have a good %of weight.
static constexpr double DensityAdjust = 2.1;
// Gyroid upper resolution tolerance (mm^-2)
static constexpr double PatternTolerance = 0.1;
};
} // namespace Slic3r
#endif // slic3r_FillTpmsD_hpp_
#endif // slic3r_FillTpmsD_hpp_
+7
View File
@@ -82,6 +82,13 @@ public:
bool operator==(const Flow &rhs) const { return m_width == rhs.m_width && m_height == rhs.m_height && m_nozzle_diameter == rhs.m_nozzle_diameter && m_bridge == rhs.m_bridge; }
bool operator!=(const Flow &rhs) const{
return m_width != rhs.m_width || m_height != rhs.m_height || m_nozzle_diameter != rhs.m_nozzle_diameter || m_bridge != rhs.m_bridge;
}
bool operator <(const Flow &rhs) const {
return this->mm3_per_mm() < rhs.mm3_per_mm();
}
Flow with_width (float width) const {
assert(! m_bridge);
return Flow(width, m_height, rounded_rectangle_extrusion_spacing(width, m_height), m_nozzle_diameter, m_bridge);
+7
View File
@@ -507,4 +507,11 @@ BoundingBox get_extents_rotated(const MultiPoint &mp, double angle)
return get_extents_rotated(mp.points, angle);
}
void MultiPoint::symmetric_y(const coord_t &x_axis)
{
for (Point &pt : points) {
pt(0) = 2 * x_axis - pt(0);
}
}
}
+1 -1
View File
@@ -94,7 +94,7 @@ public:
bool intersection(const Line& line, Point* intersection) const;
bool first_intersection(const Line& line, Point* intersection) const;
bool intersections(const Line &line, Points *intersections) const;
void symmetric_y(const coord_t &y_axis);
static Points _douglas_peucker(const Points &points, const double tolerance);
static Points visivalingam(const Points& pts, const double tolerance);
static Points concave_hull_2d(const Points& pts, const double tolerence);
+5 -4
View File
@@ -783,10 +783,10 @@ bool Preset::has_cali_lines(PresetBundle* preset_bundle)
static std::vector<std::string> s_Preset_print_options {
"layer_height", "initial_layer_print_height", "wall_loops", "alternate_extra_wall", "slice_closing_radius", "spiral_mode", "spiral_mode_smooth", "spiral_mode_max_xy_smoothing", "spiral_starting_flow_ratio", "spiral_finishing_flow_ratio", "slicing_mode",
"top_shell_layers", "top_shell_thickness", "bottom_shell_layers", "bottom_shell_thickness",
"top_shell_layers", "top_shell_thickness", "top_surface_density", "bottom_surface_density", "bottom_shell_layers", "bottom_shell_thickness",
"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", "sparse_infill_pattern", "lattice_angle_1", "lattice_angle_2", "infill_overhang_angle", "top_surface_pattern", "bottom_surface_pattern",
"infill_direction", "solid_infill_direction", "rotate_solid_infill_direction", "counterbore_hole_bridging",
"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",
"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",
@@ -806,8 +806,9 @@ static std::vector<std::string> s_Preset_print_options {
"support_top_z_distance", "support_on_build_plate_only","support_critical_regions_only", "bridge_no_support", "thick_bridges", "thick_internal_bridges","dont_filter_internal_bridges","enable_extra_bridge_layer", "max_bridge_length", "print_sequence", "print_order", "support_remove_small_overhang",
"filename_format", "wall_filament", "support_bottom_z_distance",
"sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament","support_interface_not_for_body",
"ooze_prevention", "standby_temperature_delta", "preheat_time","preheat_steps", "interface_shells", "line_width", "initial_layer_line_width",
"inner_wall_line_width", "outer_wall_line_width", "sparse_infill_line_width", "internal_solid_infill_line_width",
"ooze_prevention", "standby_temperature_delta", "preheat_time","preheat_steps", "interface_shells", "line_width", "initial_layer_line_width", "inner_wall_line_width",
"outer_wall_line_width", "sparse_infill_line_width", "internal_solid_infill_line_width",
"skin_infill_line_width","skeleton_infill_line_width",
"top_surface_line_width", "support_line_width", "infill_wall_overlap","top_bottom_infill_wall_overlap", "bridge_flow", "internal_bridge_flow",
"elefant_foot_compensation", "elefant_foot_compensation_layers", "xy_contour_compensation", "xy_hole_compensation", "resolution", "enable_prime_tower",
"prime_tower_width", "prime_tower_brim_width", "prime_volume",
+1 -1
View File
@@ -1387,7 +1387,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
if (!validate_extrusion_width(object->config(), "support_line_width", layer_height, err_msg))
return {err_msg, object, "support_line_width"};
}
for (const char *opt_key : { "inner_wall_line_width", "outer_wall_line_width", "sparse_infill_line_width", "internal_solid_infill_line_width", "top_surface_line_width" })
for (const char *opt_key : { "inner_wall_line_width", "outer_wall_line_width", "sparse_infill_line_width", "internal_solid_infill_line_width", "top_surface_line_width","skin_infill_line_width" ,"skeleton_infill_line_width"})
for (const PrintRegion &region : object->all_regions())
if (!validate_extrusion_width(region.config(), opt_key, layer_height, err_msg))
return {err_msg, object, opt_key};
File diff suppressed because it is too large Load Diff
+13 -3
View File
@@ -60,7 +60,7 @@ enum AuthorizationType {
enum InfillPattern : int {
ipConcentric, ipRectilinear, ipGrid, ip2DLattice, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipTpmsD, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip2DHoneycomb, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal,
ipLightning, ipCrossHatch, ipQuarterCubic,
ipLightning, ipCrossHatch, ipQuarterCubic, ipZigZag, ipCrossZag, ipLockedZag,
ipCount,
};
@@ -952,6 +952,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, bridge_speed))
((ConfigOptionFloatOrPercent, internal_bridge_speed))
((ConfigOptionEnum<EnsureVerticalShellThickness>, ensure_vertical_shell_thickness))
((ConfigOptionPercent, top_surface_density))
((ConfigOptionPercent, bottom_surface_density))
((ConfigOptionEnum<InfillPattern>, top_surface_pattern))
((ConfigOptionEnum<InfillPattern>, bottom_surface_pattern))
((ConfigOptionEnum<InfillPattern>, internal_solid_infill_pattern))
@@ -959,7 +961,10 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, outer_wall_speed))
((ConfigOptionFloat, infill_direction))
((ConfigOptionFloat, solid_infill_direction))
((ConfigOptionBool, rotate_solid_infill_direction))
((ConfigOptionString, solid_infill_rotate_template))
((ConfigOptionBool, symmetric_infill_y_axis))
((ConfigOptionFloat, infill_shift_step))
((ConfigOptionString, sparse_infill_rotate_template))
((ConfigOptionPercent, sparse_infill_density))
((ConfigOptionEnum<InfillPattern>, sparse_infill_pattern))
((ConfigOptionFloat, lattice_angle_1))
@@ -979,7 +984,12 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionPercent, infill_wall_overlap))
((ConfigOptionPercent, top_bottom_infill_wall_overlap))
((ConfigOptionFloat, sparse_infill_speed))
//BBS
((ConfigOptionPercent, skeleton_infill_density))
((ConfigOptionPercent, skin_infill_density))
((ConfigOptionFloat, infill_lock_depth))
((ConfigOptionFloat, skin_infill_depth))
((ConfigOptionFloatOrPercent, skin_infill_line_width))
((ConfigOptionFloatOrPercent, skeleton_infill_line_width))
((ConfigOptionBool, infill_combination))
// Orca:
((ConfigOptionFloatOrPercent, infill_combination_max_layer_height))
+13 -2
View File
@@ -1073,9 +1073,10 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "sparse_infill_filament"
|| opt_key == "solid_infill_filament"
|| opt_key == "sparse_infill_line_width"
|| opt_key == "skin_infill_line_width"
|| opt_key == "skeleton_infill_line_width"
|| opt_key == "infill_direction"
|| opt_key == "solid_infill_direction"
|| opt_key == "rotate_solid_infill_direction"
|| opt_key == "ensure_vertical_shell_thickness"
|| opt_key == "bridge_angle"
|| opt_key == "internal_bridge_angle" // ORCA: Internal bridge angle override
@@ -1091,13 +1092,23 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "infill_anchor"
|| opt_key == "infill_anchor_max"
|| opt_key == "top_surface_line_width"
|| opt_key == "top_surface_density"
|| opt_key == "bottom_surface_density"
|| opt_key == "initial_layer_line_width"
|| opt_key == "small_area_infill_flow_compensation"
|| opt_key == "lattice_angle_1"
|| opt_key == "lattice_angle_2"
|| opt_key == "infill_overhang_angle") {
steps.emplace_back(posInfill);
} else if (opt_key == "sparse_infill_pattern") {
} else if (opt_key == "sparse_infill_pattern"
|| opt_key == "symmetric_infill_y_axis"
|| opt_key == "infill_shift_step"
|| opt_key == "sparse_infill_rotate_template"
|| opt_key == "solid_infill_rotate_template"
|| opt_key == "skeleton_infill_density"
|| opt_key == "skin_infill_density"
|| opt_key == "infill_lock_depth"
|| opt_key == "skin_infill_depth") {
steps.emplace_back(posPrepareInfill);
} else if (opt_key == "sparse_infill_density") {
// One likely wants to reslice only when switching between zero infill to simulate boolean difference (subtracting volumes),
+2 -2
View File
@@ -665,8 +665,8 @@ if (SLIC3R_STATIC)
target_compile_definitions(libslic3r_gui PUBLIC -DwxDEBUG_LEVEL=0)
endif()
if (HAVE_SPNAV)
target_link_libraries(libslic3r_gui spnav)
if (SPNAV_LIB)
target_link_libraries(libslic3r_gui ${SPNAV_LIB})
endif()
if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL AND UNIX AND NOT APPLE)
+3 -3
View File
@@ -49,7 +49,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.min = 0;
def.max = 214700;
def.width = 10; // increase width for large scale printers with 4 digit values
def.sidetext = L("mm");
def.sidetext = "mm"; // milimeters, don't need translation
def.label = get_option_label(param);
def.tooltip = L("Size in X and Y of the rectangular plate.");
key = "rect_size";
@@ -60,7 +60,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.min = -107350;
def.max = 107350;
def.width = 10; // increase width for large scale printers with 4 digit values
def.sidetext = L("mm");
def.sidetext = "mm"; // milimeters, don't need translation
def.label = get_option_label(param);
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
key = "rect_origin";
@@ -69,7 +69,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.type = coFloat;
def.set_default_value(new ConfigOptionFloat(200));
def.width = 10; // match size
def.sidetext = L("mm");
def.sidetext = "mm"; // milimeters, don't need translation
def.label = get_option_label(param);
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
key = "diameter";
@@ -313,7 +313,7 @@ void CaliPresetCustomRangePanel::create_panel(wxWindow* parent)
m_title_texts[i]->Wrap(-1);
m_title_texts[i]->SetFont(::Label::Body_14);
item_sizer->Add(m_title_texts[i], 0, wxALL, 0);
m_value_inputs[i] = new TextInput(parent, wxEmptyString, wxString::FromUTF8("°C"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, 0);
m_value_inputs[i] = new TextInput(parent, wxEmptyString, wxString::FromUTF8("\u2103" /* °C */), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, 0);
m_value_inputs[i]->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
m_value_inputs[i]->GetTextCtrl()->Bind(wxEVT_TEXT, [this, i](wxCommandEvent& event) {
std::string number = m_value_inputs[i]->GetTextCtrl()->GetValue().ToStdString();
@@ -392,7 +392,7 @@ void CaliPresetTipsPanel::create_panel(wxWindow* parent)
auto nozzle_temp_sizer = new wxBoxSizer(wxVERTICAL);
auto nozzle_temp_text = new Label(parent, _L("Nozzle temperature"));
nozzle_temp_text->SetFont(Label::Body_12);
m_nozzle_temp = new TextInput(parent, wxEmptyString, wxString::FromUTF8("°C"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, wxTE_READONLY);
m_nozzle_temp = new TextInput(parent, wxEmptyString, wxString::FromUTF8("\u2103" /* °C */), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, wxTE_READONLY);
m_nozzle_temp->SetBorderWidth(0);
nozzle_temp_sizer->Add(nozzle_temp_text, 0, wxALIGN_LEFT);
nozzle_temp_sizer->Add(m_nozzle_temp, 0, wxEXPAND);
@@ -439,7 +439,7 @@ void CaliPresetTipsPanel::set_params(int nozzle_temp, int bed_temp, float max_vo
m_nozzle_temp->GetTextCtrl()->SetValue(text_nozzle_temp);
std::string bed_temp_text = bed_temp==0 ? "-": std::to_string(bed_temp);
m_bed_temp->SetLabel(wxString::FromUTF8(bed_temp_text + "°C"));
m_bed_temp->SetLabel(wxString::FromUTF8(bed_temp_text + "\u2103" /* °C */));
wxString flow_val_text = wxString::Format("%0.2f", max_volumetric);
m_max_volumetric_speed->GetTextCtrl()->SetValue(flow_val_text);
+45 -2
View File
@@ -472,6 +472,20 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
apply(config, &new_conf);
is_msg_dlg_already_exist = false;
}
// 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"));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
new_conf.set_key_value("infill_lock_depth", new ConfigOptionFloat(skin_depth / 2));
apply(config, &new_conf);
is_msg_dlg_already_exist = false;
}
}
void ConfigManipulation::apply_null_fff_config(DynamicPrintConfig *config, std::vector<std::string> const &keys, std::map<ObjectBase *, ModelConfig *> const &configs)
@@ -526,7 +540,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
bool have_infill = config->option<ConfigOptionPercent>("sparse_infill_density")->value > 0;
// sparse_infill_filament uses the same logic as in Print::extruders()
for (auto el : { "sparse_infill_pattern", "infill_combination",
"minimum_sparse_infill_area", "sparse_infill_filament", "infill_anchor_max"})
"minimum_sparse_infill_area", "sparse_infill_filament", "infill_anchor_max","infill_shift_step","sparse_infill_rotate_template","symmetric_infill_y_axis"})
toggle_line(el, have_infill);
bool have_combined_infill = config->opt_bool("infill_combination") && have_infill;
@@ -539,6 +553,19 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
bool has_infill_anchors = have_infill && config->option<ConfigOptionFloatOrPercent>("infill_anchor_max")->value > 0 && infill_anchor;
toggle_field("infill_anchor", has_infill_anchors);
//cross zag
bool is_cross_zag = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipCrossZag;
bool is_locked_zig = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipLockedZag;
toggle_line("infill_shift_step", is_cross_zag || is_locked_zig);
for (auto el : { "skeleton_infill_density", "skin_infill_density", "infill_lock_depth", "skin_infill_depth","skin_infill_line_width", "skeleton_infill_line_width" })
toggle_line(el, is_locked_zig);
bool is_zig_zag = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipZigZag;
toggle_line("symmetric_infill_y_axis", is_zig_zag || is_cross_zag || is_locked_zig);
bool has_spiral_vase = config->opt_bool("spiral_mode");
toggle_line("spiral_mode_smooth", has_spiral_vase);
toggle_line("spiral_mode_max_xy_smoothing", has_spiral_vase && config->opt_bool("spiral_mode_smooth"));
@@ -552,7 +579,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "infill_direction", "sparse_infill_line_width",
"sparse_infill_speed", "bridge_speed", "internal_bridge_speed", "bridge_angle", "internal_bridge_angle",
"solid_infill_direction", "rotate_solid_infill_direction", "internal_solid_infill_pattern", "solid_infill_filament",
"solid_infill_direction", "solid_infill_rotate_template", "internal_solid_infill_pattern", "solid_infill_filament",
})
toggle_field(el, have_infill || has_solid_infill);
@@ -823,6 +850,22 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "lattice_angle_1", "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);
toggle_line("infill_overhang_angle", config->opt_enum<InfillPattern>("sparse_infill_pattern") == InfillPattern::ip2DHoneycomb);
}
+5 -5
View File
@@ -278,7 +278,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
const auto &variant = model.variants[i];
const auto label = model.technology == ptFFF
? from_u8((boost::format("%1% %2% %3%") % variant.name % _utf8(L("mm")) % _utf8(L("nozzle"))).str())
? from_u8((boost::format("%1% %2% %3%") % variant.name % _utf8("mm") % _utf8(L("nozzle"))).str())
: from_u8(model.name);
if (i == 1) {
@@ -1353,7 +1353,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent)
auto *sizer_nozzle = new wxFlexGridSizer(3, 5, 5);
auto *text_nozzle = new wxStaticText(this, wxID_ANY, _L("Nozzle Diameter:"));
auto *unit_nozzle = new wxStaticText(this, wxID_ANY, _L("mm"));
auto *unit_nozzle = new wxStaticText(this, wxID_ANY, "mm");
sizer_nozzle->AddGrowableCol(0, 1);
sizer_nozzle->Add(text_nozzle, 0, wxALIGN_CENTRE_VERTICAL);
sizer_nozzle->Add(diam_nozzle);
@@ -1367,7 +1367,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent)
auto *sizer_filam = new wxFlexGridSizer(3, 5, 5);
auto *text_filam = new wxStaticText(this, wxID_ANY, _L("Filament Diameter:"));
auto *unit_filam = new wxStaticText(this, wxID_ANY, _L("mm"));
auto *unit_filam = new wxStaticText(this, wxID_ANY, "mm");
sizer_filam->AddGrowableCol(0, 1);
sizer_filam->Add(text_filam, 0, wxALIGN_CENTRE_VERTICAL);
sizer_filam->Add(diam_filam);
@@ -1448,7 +1448,7 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent)
auto *sizer_extr = new wxFlexGridSizer(3, 5, 5);
auto *text_extr = new wxStaticText(this, wxID_ANY, _L("Extrusion Temperature:"));
auto *unit_extr = new wxStaticText(this, wxID_ANY, "°C");
auto *unit_extr = new wxStaticText(this, wxID_ANY, "\u2103" /* °C */);
sizer_extr->AddGrowableCol(0, 1);
sizer_extr->Add(text_extr, 0, wxALIGN_CENTRE_VERTICAL);
sizer_extr->Add(spin_extr);
@@ -1462,7 +1462,7 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent)
auto *sizer_bed = new wxFlexGridSizer(3, 5, 5);
auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature:"));
auto *unit_bed = new wxStaticText(this, wxID_ANY, "°C");
auto *unit_bed = new wxStaticText(this, wxID_ANY, "\u2103" /* °C */);
sizer_bed->AddGrowableCol(0, 1);
sizer_bed->Add(text_bed, 0, wxALIGN_CENTRE_VERTICAL);
sizer_bed->Add(spin_bed);
+5 -5
View File
@@ -1870,7 +1870,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_bed_size_item(wxWindow *parent)
// ORCA use icon on input box to match style with other Point fields
horizontal_sizer->Add(length_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10));
wxBoxSizer *length_input_sizer = new wxBoxSizer(wxVERTICAL);
m_bed_size_x_input = new TextInput(parent, "200", _L("mm"), "inputbox_x", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
m_bed_size_x_input = new TextInput(parent, "200", "mm", "inputbox_x", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
wxTextValidator validator(wxFILTER_DIGITS);
m_bed_size_x_input->GetTextCtrl()->SetValidator(validator);
length_input_sizer->Add(m_bed_size_x_input, 0, wxEXPAND | wxLEFT, FromDIP(5));
@@ -1880,7 +1880,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_bed_size_item(wxWindow *parent)
// ORCA use icon on input box to match style with other Point fields
horizontal_sizer->Add(width_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10));
wxBoxSizer *width_input_sizer = new wxBoxSizer(wxVERTICAL);
m_bed_size_y_input = new TextInput(parent, "200", _L("mm"), "inputbox_y", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
m_bed_size_y_input = new TextInput(parent, "200", "mm", "inputbox_y", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
m_bed_size_y_input->GetTextCtrl()->SetValidator(validator);
width_input_sizer->Add(m_bed_size_y_input, 0, wxEXPAND | wxALL, 0);
horizontal_sizer->Add(width_input_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5));
@@ -1903,7 +1903,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_origin_item(wxWindow *parent)
// ORCA use icon on input box to match style with other Point fields
horizontal_sizer->Add(length_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10));
wxBoxSizer *length_input_sizer = new wxBoxSizer(wxVERTICAL);
m_bed_origin_x_input = new TextInput(parent, "0", _L("mm"), "inputbox_x", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
m_bed_origin_x_input = new TextInput(parent, "0", "mm", "inputbox_x", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
wxTextValidator validator(wxFILTER_DIGITS);
m_bed_origin_x_input->GetTextCtrl()->SetValidator(validator);
length_input_sizer->Add(m_bed_origin_x_input, 0, wxEXPAND | wxLEFT, FromDIP(5)); // Align with other
@@ -1913,7 +1913,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_origin_item(wxWindow *parent)
// ORCA use icon on input box to match style with other Point fields
horizontal_sizer->Add(width_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10));
wxBoxSizer *width_input_sizer = new wxBoxSizer(wxVERTICAL);
m_bed_origin_y_input = new TextInput(parent, "0", _L("mm"), "inputbox_y", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
m_bed_origin_y_input = new TextInput(parent, "0", "mm", "inputbox_y", wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER);
m_bed_origin_y_input->GetTextCtrl()->SetValidator(validator);
width_input_sizer->Add(m_bed_origin_y_input, 0, wxEXPAND | wxALL, 0);
horizontal_sizer->Add(width_input_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5));
@@ -2006,7 +2006,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_max_print_height_item(wxWindow *pa
horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10));
wxBoxSizer *hight_input_sizer = new wxBoxSizer(wxVERTICAL);
m_print_height_input = new TextInput(parent, "200", _L("mm"), wxEmptyString, wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER); // Use same alignment with all other input boxes
m_print_height_input = new TextInput(parent, "200", "mm", wxEmptyString, wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_PROCESS_ENTER); // Use same alignment with all other input boxes
wxTextValidator validator(wxFILTER_DIGITS);
m_print_height_input->GetTextCtrl()->SetValidator(validator);
hight_input_sizer->Add(m_print_height_input, 0, wxEXPAND | wxLEFT, FromDIP(5));
+3 -3
View File
@@ -3316,7 +3316,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only)
if (jj.contains("errno")) {
if (jj["errno"].is_number()) {
if (jj["errno"].get<int>() == -2) {
wxString text = _L("The current chamber temperature or the target chamber temperature exceeds 45\u2103. "
wxString text = _L("The current chamber temperature or the target chamber temperature exceeds 45\u2103. " /* 45°C */
"In order to avoid extruder clogging, low temperature filament (PLA/PETG/TPU) is not allowed to be loaded.");
GUI::wxGetApp().push_notification(text);
}
@@ -3330,11 +3330,11 @@ int MachineObject::parse_json(std::string payload, bool key_field_only)
wxString text;
if (jj["errno"].get<int>() == -2) {
text = _L("Low temperature filament (PLA/PETG/TPU) is loaded in the extruder. "
"In order to avoid extruder clogging, it is not allowed to set the chamber temperature above 45\u2103.");
"In order to avoid extruder clogging, it is not allowed to set the chamber temperature above 45\u2103." /* 45°C */);
}
else if (jj["errno"].get<int>() == -4) {
text = _L("When you set the chamber temperature below 40\u2103, the chamber temperature control will not be activated, "
"and the target chamber temperature will automatically be set to 0\u2103.");
"and the target chamber temperature will automatically be set to 0\u2103." /* 0°C */);
}
if(!text.empty()){
#if __WXOSX__
+3 -3
View File
@@ -127,21 +127,21 @@ void ExtrusionCalibration::create()
wxWindow::GetTextExtent(_L("Bed Temperature")).x),
wxWindow::GetTextExtent(_L("Max volumetric speed")).x),
EXTRUSION_CALIBRATION_INPUT_SIZE.x);
m_nozzle_temp = new TextInput(m_step_1_panel, wxEmptyString, _L("\u2103"), "", wxDefaultPosition, { max_input_width, EXTRUSION_CALIBRATION_INPUT_SIZE.y }, wxTE_READONLY);
m_nozzle_temp = new TextInput(m_step_1_panel, wxEmptyString, "\u2103" /* °C */, "", wxDefaultPosition, { max_input_width, EXTRUSION_CALIBRATION_INPUT_SIZE.y }, wxTE_READONLY);
nozzle_temp_sizer->Add(nozzle_temp_text, 0, wxALIGN_LEFT);
nozzle_temp_sizer->AddSpacer(FromDIP(4));
nozzle_temp_sizer->Add(m_nozzle_temp, 0, wxEXPAND);
auto bed_temp_sizer = new wxBoxSizer(wxVERTICAL);
auto bed_temp_text = new wxStaticText(m_step_1_panel, wxID_ANY, _L("Bed temperature"));
m_bed_temp = new TextInput(m_step_1_panel, wxEmptyString, _L("\u2103"), "", wxDefaultPosition, { max_input_width, EXTRUSION_CALIBRATION_INPUT_SIZE.y }, wxTE_READONLY);
m_bed_temp = new TextInput(m_step_1_panel, wxEmptyString, "\u2103" /* °C */, "", wxDefaultPosition, { max_input_width, EXTRUSION_CALIBRATION_INPUT_SIZE.y }, wxTE_READONLY);
bed_temp_sizer->Add(bed_temp_text, 0, wxALIGN_LEFT);
bed_temp_sizer->AddSpacer(FromDIP(4));
bed_temp_sizer->Add(m_bed_temp, 0, wxEXPAND);
auto max_flow_sizer = new wxBoxSizer(wxVERTICAL);
auto max_flow_text = new wxStaticText(m_step_1_panel, wxID_ANY, _L("Max volumetric speed"));
m_max_flow_ratio = new TextInput(m_step_1_panel, wxEmptyString, _L("mm\u00B3"), "", wxDefaultPosition, { max_input_width, EXTRUSION_CALIBRATION_INPUT_SIZE.y }, wxTE_READONLY);
m_max_flow_ratio = new TextInput(m_step_1_panel, wxEmptyString, "mm³", "", wxDefaultPosition, { max_input_width, EXTRUSION_CALIBRATION_INPUT_SIZE.y }, wxTE_READONLY);
max_flow_sizer->Add(max_flow_text, 0, wxALIGN_LEFT);
max_flow_sizer->AddSpacer(FromDIP(4));
max_flow_sizer->Add(m_max_flow_ratio, 0, wxEXPAND);
+10
View File
@@ -430,6 +430,16 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
str = str_out;
set_value(str, true);
}
} else if (m_opt.opt_key == "sparse_infill_rotate_template" || m_opt.opt_key == "solid_infill_rotate_template") {
if (!ConfigOptionFloats::validate_string(str.utf8_string())) {
show_error(m_parent, format_wxstr(_L("This parameter expects a comma-delimited list of numbers. E.g, \"0,90\".")));
wxString old_value(boost::any_cast<std::string>(m_value));
this->set_value(old_value, true); // Revert to previous value
} else {
// Valid string, so update m_value with the new string from the control.
m_value = into_u8(str);
}
break;
}
m_value = into_u8(str);
+3 -3
View File
@@ -4606,13 +4606,13 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
auto upto_label = [](double z) {
char buf[64];
::sprintf(buf, "%.2f", z);
return _u8L("up to") + " " + std::string(buf) + " " + _u8L("mm");
return _u8L("up to") + " " + std::string(buf) + " " + "mm";
};
auto above_label = [](double z) {
char buf[64];
::sprintf(buf, "%.2f", z);
return _u8L("above") + " " + std::string(buf) + " " + _u8L("mm");
return _u8L("above") + " " + std::string(buf) + " " + "mm";
};
auto fromto_label = [](double z1, double z2) {
@@ -4620,7 +4620,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
::sprintf(buf1, "%.2f", z1);
char buf2[64];
::sprintf(buf2, "%.2f", z2);
return _u8L("from") + " " + std::string(buf1) + " " + _u8L("to") + " " + std::string(buf2) + " " + _u8L("mm");
return _u8L("from") + " " + std::string(buf1) + " " + _u8L("to") + " " + std::string(buf2) + " " + "mm";
};
auto role_time_and_percent = [time_mode](ExtrusionRole role) {
+17 -14
View File
@@ -4104,6 +4104,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
bool any_gizmo_active = m_gizmos.get_current() != nullptr;
bool swapMouseButtons = wxGetApp().app_config->get_bool("swap_mouse_buttons");
if (m_mouse.drag.move_requires_threshold && m_mouse.is_move_start_threshold_position_2D_defined() && m_mouse.is_move_threshold_met(pos)) {
m_mouse.drag.move_requires_threshold = false;
@@ -4305,7 +4306,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true;
}
}
else if (evt.Dragging() || is_camera_rotate(evt) || is_camera_pan(evt)) {
else if (evt.Dragging() || is_camera_rotate(evt, swapMouseButtons) || is_camera_pan(evt, swapMouseButtons)) {
m_mouse.dragging = true;
if (m_layers_editing.state != LayersEditing::Unknown && layer_editing_object_idx != -1) {
@@ -4315,10 +4316,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
}
// do not process the dragging if the left mouse was set down in another canvas
else if (is_camera_rotate(evt)) {
else if (is_camera_rotate(evt, swapMouseButtons)) {
// Orca: Sphere rotation for painting view
// if dragging over blank area with left button, rotate
if ((any_gizmo_active || m_hover_volume_idxs.empty()) && m_mouse.is_start_position_3D_defined()) {
// if dragging over blank area with left button or button functions swapped then rotate
if ((any_gizmo_active || swapMouseButtons || m_hover_volume_idxs.empty()) && m_mouse.is_start_position_3D_defined()) {
Camera& camera = wxGetApp().plater()->get_camera();
auto mult_pref = wxGetApp().app_config->get("camera_orbit_mult");
const double mult = mult_pref.empty() ? 1.0 : std::stod(mult_pref);
@@ -4381,15 +4382,17 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
}
}
camera.auto_type(Camera::EType::Perspective);
camera.auto_type(Camera::EType::Perspective);
m_dirty = true;
m_mouse.ignore_right_up = true; // will be reset on button up event even if not right button is pressed
}
m_camera_movement = true;
m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0);
}
else if (is_camera_pan(evt)) {
// If dragging over blank area with right button, pan.
else if (is_camera_pan(evt, swapMouseButtons)) {
// if dragging with right button or if button functions swapped and dragging with left button over blank area then pan
if (m_mouse.is_start_position_2D_defined()) {
// get point in model space at Z = 0
float z = 0.0f;
@@ -4407,7 +4410,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
camera.set_target(camera.get_target() + orig - cur_pos);
m_dirty = true;
m_mouse.ignore_right_up = true;
m_mouse.ignore_right_up = true; // will be reset on button up event even if not right button is pressed
}
m_camera_movement = true;
@@ -4415,10 +4418,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
}
else if ((evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) ||
(m_camera_movement && !is_camera_rotate(evt) && !is_camera_pan(evt))) {
(m_camera_movement && !is_camera_rotate(evt, swapMouseButtons) && !is_camera_pan(evt, swapMouseButtons))) {
m_mouse.position = pos.cast<double>();
if (evt.LeftUp()) {
if (swapMouseButtons ? evt.RightUp() : evt.LeftUp()) {
m_rotation_center(0) = m_rotation_center(1) = m_rotation_center(2) = 0.f;
}
@@ -4603,21 +4606,21 @@ void GLCanvas3D::on_set_focus(wxFocusEvent& evt)
m_is_touchpad_navigation = wxGetApp().app_config->get_bool("camera_navigation_style");
}
bool GLCanvas3D::is_camera_rotate(const wxMouseEvent& evt) const
bool GLCanvas3D::is_camera_rotate(const wxMouseEvent& evt, const bool buttonsSwapped) const
{
if (m_is_touchpad_navigation) {
return evt.Moving() && evt.AltDown() && !evt.ShiftDown();
} else {
return evt.Dragging() && evt.LeftIsDown();
return evt.Dragging() && (buttonsSwapped ? evt.RightIsDown() : evt.LeftIsDown());
}
}
bool GLCanvas3D::is_camera_pan(const wxMouseEvent& evt) const
bool GLCanvas3D::is_camera_pan(const wxMouseEvent& evt, const bool buttonsSwapped) const
{
if (m_is_touchpad_navigation) {
return evt.Moving() && evt.ShiftDown() && !evt.AltDown();
} else {
return evt.Dragging() && (evt.MiddleIsDown() || evt.RightIsDown());
return evt.Dragging() && (evt.MiddleIsDown() || (buttonsSwapped ? evt.LeftIsDown() : evt.RightIsDown()));
}
}
+5 -5
View File
@@ -216,7 +216,7 @@ class GLCanvas3D
};
static const float THICKNESS_BAR_WIDTH;
// Orca: Shrinkage compensation
void set_shrinkage_compensation(const Vec3d &shrinkage_compensation) { m_shrinkage_compensation = shrinkage_compensation; };
@@ -232,7 +232,7 @@ class GLCanvas3D
// Owned by LayersEditing.
SlicingParameters* m_slicing_parameters{ nullptr };
std::vector<double> m_layer_height_profile;
// Orca: Shrinkage compensation to apply when we need to use object_max_z with Z compensation.
Vec3d m_shrinkage_compensation{ Vec3d::Ones() };
@@ -968,8 +968,8 @@ public:
void on_set_focus(wxFocusEvent& evt);
void force_set_focus();
bool is_camera_rotate(const wxMouseEvent& evt) const;
bool is_camera_pan(const wxMouseEvent& evt) const;
bool is_camera_rotate(const wxMouseEvent& evt, const bool buttonsSwapped) const;
bool is_camera_pan(const wxMouseEvent& evt, const bool buttonsSwapped) const;
Size get_canvas_size() const;
Vec2d get_local_mouse_position() const;
@@ -1063,7 +1063,7 @@ public:
bool is_overhang_shown() const { return m_slope.is_GlobalUsed(); }
void show_overhang(bool show) { m_slope.globalUse(show); }
bool is_using_slope() const { return m_slope.is_used(); }
void use_slope(bool use) { m_slope.use(use); }
void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); }
+9 -9
View File
@@ -104,10 +104,10 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::PART_CAT
{
{ L("Quality"), {{"ironing_type", "",8},{"ironing_flow", "",9},{"ironing_spacing", "",10},{"ironing_inset", "", 11},{"bridge_flow", "",11},{"make_overhang_printable", "",11},{"bridge_density", "", 1}
}},
{ L("Strength"), {{"wall_loops", "",1},{"top_shell_layers", L("Top Solid Layers"),1},{"top_shell_thickness", L("Top Minimum Shell Thickness"),1},
{"bottom_shell_layers", L("Bottom Solid Layers"),1}, {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"),1},
{ L("Strength"), {{"wall_loops", "",1},{"top_shell_layers", L("Top Solid Layers"),1},{"top_shell_thickness", L("Top Minimum Shell Thickness"),1},{"top_surface_density", L("Top Surface Density"),1},
{"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},{"lattice_angle_1", "",1},{"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},
{"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"rotate_solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",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},
{"enable_overhang_speed", "",6}, {"overhang_1_4_speed", "",7}, {"overhang_2_4_speed", "",8}, {"overhang_3_4_speed", "",9}, {"overhang_4_4_speed", "",10},
@@ -523,7 +523,7 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty
append_menu_item_add_text(sub_menu, type);
append_menu_item_add_svg(sub_menu, type);
return sub_menu;
}
@@ -619,7 +619,7 @@ static void append_menu_itemm_add_(const wxString& name, GLGizmosManager::EType
} else {
svg->create_volume(volume_type);
}
}
}
};
if (type == ModelVolumeType::MODEL_PART || type == ModelVolumeType::NEGATIVE_VOLUME || type == ModelVolumeType::PARAMETER_MODIFIER ||
@@ -1131,7 +1131,7 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu)
auto can_edit_text = []() {
if (plater() == nullptr)
return false;
return false;
const Selection& selection = plater()->get_selection();
if (selection.volumes_count() != 1)
return false;
@@ -1141,7 +1141,7 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu)
const ModelVolume *volume = get_model_volume(*gl_volume, selection.get_model()->objects);
if (volume == nullptr)
return false;
return volume->is_text();
return volume->is_text();
};
if (menu != &m_text_part_menu) {
@@ -1168,7 +1168,7 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu *menu)
wxString name = _L("Edit SVG");
auto can_edit_svg = []() {
if (plater() == nullptr)
return false;
return false;
const Selection& selection = plater()->get_selection();
if (selection.volumes_count() != 1)
return false;
@@ -1178,7 +1178,7 @@ void MenuFactory::append_menu_item_edit_svg(wxMenu *menu)
const ModelVolume *volume = get_model_volume(*gl_volume, selection.get_model()->objects);
if (volume == nullptr)
return false;
return volume->is_svg();
return volume->is_svg();
};
if (menu != &m_svg_part_menu) {
+22 -12
View File
@@ -8,6 +8,8 @@
#include "GLCanvas3D.hpp"
#include "Plater.hpp"
#include "Widgets/LabeledStaticBox.hpp"
#include <boost/algorithm/string.hpp>
#include "I18N.hpp"
@@ -29,7 +31,9 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
m_og->activate();
m_og->sizer->Clear(true);
m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, wxOSX ? 0 : 5);
m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
if (auto stb = dynamic_cast<LabeledStaticBox*>(m_og->stb))
stb->SetCornerRadius(0);
m_bmp_delete = ScalableBitmap(parent, "delete");
m_bmp_add = ScalableBitmap(parent, "add");
@@ -74,7 +78,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus
};
// Add text
auto head_text = new wxStaticText(m_parent, wxID_ANY, _L("Height Range"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
auto head_text = new wxStaticText(m_og->ctrl_parent(), wxID_ANY, _L("Height Range"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
head_text->SetBackgroundStyle(wxBG_STYLE_PAINT);
head_text->SetFont(wxGetApp().normal_font());
m_grid_sizer->Add(head_text, 0, wxALIGN_CENTER_VERTICAL);
@@ -105,7 +109,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus
m_grid_sizer->Add(editor, 1, wxEXPAND);
auto middle_text = new wxStaticText(m_parent, wxID_ANY, _L("to"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
auto middle_text = new wxStaticText(m_og->ctrl_parent(), wxID_ANY, _L("to"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
middle_text->SetBackgroundStyle(wxBG_STYLE_PAINT);
middle_text->SetFont(wxGetApp().normal_font());
m_grid_sizer->Add(middle_text, 0, wxALIGN_CENTER_VERTICAL);
@@ -135,12 +139,12 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus
m_grid_sizer->Add(editor, 1, wxEXPAND);
auto sizer2 = new wxBoxSizer(wxHORIZONTAL);
auto unit_text = new wxStaticText(m_parent, wxID_ANY, _L("mm"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
auto unit_text = new wxStaticText(m_og->ctrl_parent(), wxID_ANY, "mm", wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
unit_text->SetBackgroundStyle(wxBG_STYLE_PAINT);
unit_text->SetFont(wxGetApp().normal_font());
sizer2->Add(unit_text, 0, wxALIGN_CENTER_VERTICAL);
m_grid_sizer->Add(sizer2);
m_grid_sizer->Add(sizer2, 0, wxALIGN_CENTER_VERTICAL);
// BBS
// Add control for the "Layer height"
@@ -156,7 +160,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus
//auto sizer = new wxBoxSizer(wxHORIZONTAL);
//sizer->Add(editor);
//auto temp = new wxStaticText(m_parent, wxID_ANY, _L("mm"));
//auto temp = new wxStaticText(m_parent, wxID_ANY, "mm");
//temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
//temp->SetFont(wxGetApp().normal_font());
//sizer->Add(temp, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, wxGetApp().em_unit());
@@ -170,12 +174,12 @@ void ObjectLayers::create_layers_list()
{
for (const auto &layer : m_object->layer_config_ranges) {
const t_layer_height_range& range = layer.first;
auto del_btn = new PlusMinusButton(m_parent, m_bmp_delete, range);
auto del_btn = new PlusMinusButton(m_og->ctrl_parent(), m_bmp_delete, range);
del_btn->DisableFocusFromKeyboard();
del_btn->SetBackgroundColour(m_parent->GetBackgroundColour());
del_btn->SetToolTip(_L("Remove height range"));
auto add_btn = new PlusMinusButton(m_parent, m_bmp_add, range);
auto add_btn = new PlusMinusButton(m_og->ctrl_parent(), m_bmp_add, range);
add_btn->DisableFocusFromKeyboard();
add_btn->SetBackgroundColour(m_parent->GetBackgroundColour());
wxString tooltip = wxGetApp().obj_list()->can_add_new_range_after_current(range);
@@ -183,8 +187,10 @@ void ObjectLayers::create_layers_list()
add_btn->Enable(tooltip.IsEmpty());
auto sizer = create_layer(range, del_btn, add_btn);
sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
sizer->Add(add_btn);
auto b_sizer = new wxBoxSizer(wxHORIZONTAL);
b_sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
b_sizer->Add(add_btn);
sizer->Add(b_sizer, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, m_parent->FromDIP(1)); // aligns +/- buttons vertically since we got 1px gap on bottom of icons
del_btn->Bind(wxEVT_BUTTON, [del_btn](wxEvent &) {
wxGetApp().obj_list()->del_layer_range(del_btn->range);
@@ -218,6 +224,8 @@ void ObjectLayers::update_layers_list()
// only call sizer->Clear(true) via CallAfter, otherwise crash happens in Linux when press enter in Height Range
// because an element cannot be destroyed while there are pending events for this element.(https://github.com/wxWidgets/Phoenix/issues/1854)
wxGetApp().CallAfter([this, type, objects_ctrl, range]() {
m_og->ctrl_parent()->Freeze();
// Delete all controls from options group
m_grid_sizer->Clear(true);
@@ -228,8 +236,10 @@ void ObjectLayers::update_layers_list()
else
create_layer(range, nullptr, nullptr);
m_og->ctrl_parent()->Thaw();
m_parent->Layout();
});
});
}
void ObjectLayers::update_scene_from_editor_selection() const
@@ -340,7 +350,7 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
m_valid_value(value),
m_type(type),
m_set_focus_data(set_focus_data_fn),
wxTextCtrl(parent->m_parent, wxID_ANY, value, wxDefaultPosition,
wxTextCtrl(parent->m_og->ctrl_parent(), wxID_ANY, value, wxDefaultPosition,
wxSize(em_unit(parent->m_parent), wxDefaultCoord), wxTE_PROCESS_ENTER
#ifdef _WIN32
| wxBORDER_SIMPLE
+40 -5
View File
@@ -22,6 +22,7 @@
#include "MsgDialog.hpp"
#include "Widgets/ProgressDialog.hpp"
#include "SingleChoiceDialog.hpp"
#include "StepMeshDialog.hpp"
#include <boost/algorithm/string.hpp>
#include <wx/progdlg.h>
@@ -2031,15 +2032,49 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
dlg.Update(static_cast<int>(100.0f * static_cast<float>(i) / static_cast<float>(input_files.size())),
_L("Loading file") + ": " + from_path(boost::filesystem::path(input_file).filename()));
dlg.Fit();
bool is_user_cancel = false;
Model model;
try {
model = Model::read_from_file(input_file, nullptr, nullptr, LoadStrategy::LoadModel);
if (boost::iends_with(input_file, ".stp") ||
boost::iends_with(input_file, ".step")) {
double linear = string_to_double_decimal_point(wxGetApp().app_config->get("linear_defletion"));
if (linear <= 0) linear = 0.003;
double angle = string_to_double_decimal_point(wxGetApp().app_config->get("angle_defletion"));
if (angle <= 0) angle = 0.5;
bool split_compound = wxGetApp().app_config->get_bool("is_split_compound");
model = Model::read_from_step(
input_file, LoadStrategy::LoadModel, nullptr, nullptr,
[this, &is_user_cancel, &linear, &angle, &split_compound](Slic3r::Step& file, double& linear_value,
double& angle_value, bool& is_split) -> int {
if (wxGetApp().app_config->get_bool("enable_step_mesh_setting")) {
StepMeshDialog mesh_dlg(nullptr, file, linear, angle);
if (mesh_dlg.ShowModal() == wxID_OK) {
linear_value = mesh_dlg.get_linear_defletion();
angle_value = mesh_dlg.get_angle_defletion();
is_split = mesh_dlg.get_split_compound_value();
return 1;
}
} else {
linear_value = linear;
angle_value = angle;
is_split = split_compound;
return 1;
}
is_user_cancel = true;
return -1;
},
linear, angle, split_compound);
} else {
model = Model::read_from_file(input_file, nullptr, nullptr, LoadStrategy::LoadModel);
}
}
catch (std::exception&) {
// auto msg = _L("Error!") + " " + input_file + " : " + e.what() + ".";
auto msg = _L("Error!") + " " + _L("Failed to get the model data in the current file.");
show_error(parent, msg);
if (!is_user_cancel) {
// auto msg = _L("Error!") + " " + input_file + " : " + e.what() + ".";
auto msg = _L("Error!") + " " + _L("Failed to get the model data in the current file.");
show_error(parent, msg);
}
return;
}
+3 -3
View File
@@ -2537,19 +2537,19 @@ void NotificationManager::render_notifications(GLCanvas3D &canvas, float overlay
{
sort_notifications();
float bottom_up_last_y = bottom_margin * m_scale;
float bottom_up_last_y = bottom_margin; // ORCA dont scale margins
int i = 0;
for (const auto& notification : m_pop_notifications) {
if (notification->get_data().level == NotificationLevel::ErrorNotificationLevel || notification->get_data().level == NotificationLevel::SeriousWarningNotificationLevel) {
notification->bbl_render_block_notification(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale);
notification->bbl_render_block_notification(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin); // ORCA dont scale margins
if (notification->get_state() != PopNotification::EState::Finished)
bottom_up_last_y = notification->get_top() + GAP_WIDTH;
}
else {
if (notification->get_state() != PopNotification::EState::Hidden && notification->get_state() != PopNotification::EState::Finished) {
i++;
notification->render(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale);
notification->render(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin); // ORCA dont scale margins
if (notification->get_state() != PopNotification::EState::Finished)
bottom_up_last_y = notification->get_top() + GAP_WIDTH;
}
+1 -1
View File
@@ -157,7 +157,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
parent->GetNthChild(i)->SetIdx(i + 1);
}
const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
m_name = _(L("Range")) + label_range + "(" + _("mm") + ")";
m_bmp = create_scaled_bitmap(LayerIcon);
set_icons();
+1 -2
View File
@@ -9617,7 +9617,7 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
speeds.assign({speed});
const auto msg{_L("INFO:") + "\n" +
_L("No speeds provided for calibration. Use default optimal speed ") + std::to_string(long(speed)) + _L("mm/s")};
_L("No speeds provided for calibration. Use default optimal speed ") + std::to_string(long(speed)) + "mm/s"};
get_notification_manager()->push_notification(msg.ToStdString());
} else if (speeds.size() == 1) {
// If we have single value provided, set speed using global configuration.
@@ -9919,7 +9919,6 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
_obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f));
_obj->config.set_key_value("infill_direction", new ConfigOptionFloat(45));
_obj->config.set_key_value("solid_infill_direction", new ConfigOptionFloat(135));
_obj->config.set_key_value("rotate_solid_infill_direction", new ConfigOptionBool(true));
_obj->config.set_key_value("ironing_type", new ConfigOptionEnum<IroningType>(IroningType::NoIroning));
_obj->config.set_key_value("internal_solid_infill_speed", new ConfigOptionFloat(internal_solid_speed));
_obj->config.set_key_value("top_surface_speed", new ConfigOptionFloat(top_surface_speed));
+7 -5
View File
@@ -123,7 +123,7 @@ wxBoxSizer *PreferencesDialog::create_item_combobox(wxString title, wxWindow *pa
auto current_setting = app_config->get(param);
if (!current_setting.empty()) {
auto compare = [current_setting](string possible_setting) { return current_setting == possible_setting; };
auto iterator = find_if(config_name_index.begin(), config_name_index.end(), compare);
auto iterator = find_if(config_name_index.begin(), config_name_index.end(), compare);
current_index = iterator - config_name_index.begin();
}
@@ -536,7 +536,7 @@ wxBoxSizer *PreferencesDialog::create_camera_orbit_mult_input(wxString title, wx
sizer_input->Add(input_title, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3);
sizer_input->Add(input, 0, wxALIGN_CENTER_VERTICAL, 0);
sizer_input->Add(0, 0, 0, wxEXPAND | wxLEFT, 3);
const double min = 0.05;
const double max = 2.0;
@@ -1207,12 +1207,12 @@ wxWindow* PreferencesDialog::create_general_page()
std::vector<wxString> Units = {_L("Metric") + " (mm, g)", _L("Imperial") + " (in, oz)"};
auto item_currency = create_item_combobox(_L("Units"), page, _L("Units"), "use_inches", Units);
auto item_single_instance = create_item_checkbox(_L("Allow only one OrcaSlicer instance"), page,
auto item_single_instance = create_item_checkbox(_L("Allow only one OrcaSlicer instance"), page,
#if __APPLE__
_L("On OSX there is always only one instance of app running by default. However it is allowed to run multiple instances "
"of same app from the command line. In such case this settings will allow only one instance."),
"of same app from the command line. In such case this settings will allow only one instance."),
#else
_L("If this is enabled, when starting OrcaSlicer and another instance of the same OrcaSlicer is already running, that instance will be reactivated instead."),
_L("If this is enabled, when starting OrcaSlicer and another instance of the same OrcaSlicer is already running, that instance will be reactivated instead."),
#endif
50, "single_instance");
@@ -1224,6 +1224,7 @@ wxWindow* PreferencesDialog::create_general_page()
auto item_mouse_zoom_settings = create_item_checkbox(_L("Zoom to mouse position"), page, _L("Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center."), 50, "zoom_to_mouse");
auto item_use_free_camera_settings = create_item_checkbox(_L("Use free camera"), page, _L("If enabled, use free camera. If not enabled, use constrained camera."), 50, "use_free_camera");
auto swap_pan_rotate = create_item_checkbox(_L("Swap pan and rotate mouse buttons"), page, _L("If enabled, swaps the left and right mouse buttons pan and rotate functions."), 50, "swap_mouse_buttons");
auto reverse_mouse_zoom = create_item_checkbox(_L("Reverse mouse zoom"), page, _L("If enabled, reverses the direction of zoom with mouse wheel."), 50, "reverse_mouse_wheel_zoom");
auto camera_orbit_mult = create_camera_orbit_mult_input(_L("Orbit speed multiplier"), page, _L("Multiplies the orbit speed for finer or coarser camera movement."));
@@ -1308,6 +1309,7 @@ wxWindow* PreferencesDialog::create_general_page()
sizer_page->Add(item_single_instance, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_mouse_zoom_settings, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_use_free_camera_settings, 0, wxTOP, FromDIP(3));
sizer_page->Add(swap_pan_rotate, 0, wxTOP, FromDIP(3));
sizer_page->Add(reverse_mouse_zoom, 0, wxTOP, FromDIP(3));
sizer_page->Add(camera_orbit_mult, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_show_splash_screen, 0, wxTOP, FromDIP(3));
+2 -2
View File
@@ -89,10 +89,10 @@ void Chart::draw() {
}
// axis labels:
wxString label = _(L("Time")) + " ("+_(L("s"))+")";
wxString label = _(L("Time")) + " ("+_("s")+")";
dc.GetTextExtent(label,&text_width,&text_height);
dc.DrawText(label,wxPoint(0.5*(m_rect.GetRight()+m_rect.GetLeft())-text_width/2.f, m_rect.GetBottom()+0.6*legend_side));
label = _(L("Volumetric speed")) + " (" + _(L("mm³/s")) + ")";
label = _(L("Volumetric speed")) + " (" + _("mm³/s") + ")";
dc.GetTextExtent(label,&text_width,&text_height);
dc.DrawRotatedText(label,wxPoint(0,0.5*(m_rect.GetBottom()+m_rect.GetTop())+text_width/2.f),90);
}
+90 -37
View File
@@ -811,18 +811,18 @@ void Tab::decorate()
}
}
}
if (!sys_page) {
if (!sys_page) {
is_nonsys_value = true;
sys_icon = m_bmp_non_system;
sys_tt = m_tt_non_system;
if (!modified_page)
if (!modified_page)
color = &m_default_text_clr;
else
else
color = &m_modified_label_clr;
}
if (!modified_page) {
if (!modified_page) {
is_modified_value = false;
icon = &m_bmp_white_bullet;
tt = &m_tt_white_bullet;
@@ -1470,8 +1470,11 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
}
}
if (opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" )
update_wiping_button_visibility();
if (opt_key == "pellet_flow_coefficient")
if (opt_key == "pellet_flow_coefficient")
{
double double_value = Preset::convert_pellet_flow_to_filament_diameter(boost::any_cast<double>(value));
m_config->set_key_value("filament_diameter", new ConfigOptionFloats{double_value});
@@ -1481,6 +1484,44 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
double double_value = Preset::convert_filament_diameter_to_pellet_flow(boost::any_cast<double>(value));
m_config->set_key_value("pellet_flow_coefficient", new ConfigOptionFloats{double_value});
}
if (opt_key == "single_extruder_multi_material" ){
const auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
wxGetApp().sidebar().show_SEMM_buttons(bSEMM);
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
}
if(opt_key == "purge_in_prime_tower")
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
if (opt_key == "enable_prime_tower") {
auto timelapse_type = m_config->option<ConfigOptionEnum<TimelapseType>>("timelapse_type");
bool timelapse_enabled = timelapse_type->value == TimelapseType::tlSmooth;
if (!boost::any_cast<bool>(value) && timelapse_enabled) {
MessageDialog dlg(wxGetApp().plater(), _L("A prime tower is required for smooth timelapse. There may be flaws on the model without prime tower. Are you sure you want to disable prime tower?"),
_L("Warning"), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_NO) {
DynamicPrintConfig new_conf = *m_config;
new_conf.set_key_value("enable_prime_tower", new ConfigOptionBool(true));
m_config_manipulation.apply(m_config, &new_conf);
}
wxGetApp().plater()->update();
}
bool is_precise_z_height = m_config->option<ConfigOptionBool>("precise_z_height")->value;
if (boost::any_cast<bool>(value) && is_precise_z_height) {
MessageDialog dlg(wxGetApp().plater(), _L("Enabling both precise Z height and the prime tower may cause the size of prime tower to increase. Do you still want to enable?"),
_L("Warning"), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_NO) {
DynamicPrintConfig new_conf = *m_config;
new_conf.set_key_value("enable_prime_tower", new ConfigOptionBool(false));
m_config_manipulation.apply(m_config, &new_conf);
}
wxGetApp().plater()->update();
}
update_wiping_button_visibility();
}
if (opt_key == "single_extruder_multi_material" ){
@@ -1591,7 +1632,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
}
}
}
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;
@@ -1659,7 +1700,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
if (opt_key == "filament_long_retractions_when_cut"){
unsigned char activate = boost::any_cast<unsigned char>(value);
if (activate == 1) {
MessageDialog dialog(wxGetApp().plater(),
MessageDialog dialog(wxGetApp().plater(),
_L("Experimental feature: Retracting and cutting off the filament at a greater distance during filament changes to minimize flush. "
"Although it can notably reduce flush, it may also elevate the risk of nozzle clogs or other printing complications. "
"Please use with the latest printer firmware."), "", wxICON_WARNING | wxOK);
@@ -2156,29 +2197,41 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Top/bottom shells"), L"param_shell");
optgroup->append_single_option_line("top_shell_layers");
optgroup->append_single_option_line("top_shell_thickness");
optgroup->append_single_option_line("top_surface_density");
optgroup->append_single_option_line("top_surface_pattern");
optgroup->append_single_option_line("bottom_shell_layers");
optgroup->append_single_option_line("bottom_shell_thickness");
optgroup->append_single_option_line("bottom_surface_density");
optgroup->append_single_option_line("bottom_surface_pattern");
optgroup->append_single_option_line("top_bottom_infill_wall_overlap");
optgroup = page->new_optgroup(L("Infill"), L"param_infill");
optgroup->append_single_option_line("sparse_infill_density", "strength_settings_infill#sparse-infill-density");
optgroup->append_single_option_line("sparse_infill_pattern", "strength_settings_infill#sparse-infill-pattern");
optgroup->append_single_option_line("infill_direction");
optgroup->append_single_option_line("sparse_infill_rotate_template");
optgroup->append_single_option_line("skin_infill_density");
optgroup->append_single_option_line("skeleton_infill_density");
optgroup->append_single_option_line("infill_lock_depth");
optgroup->append_single_option_line("skin_infill_depth");
optgroup->append_single_option_line("skin_infill_line_width", "parameter/line-width");
optgroup->append_single_option_line("skeleton_infill_line_width", "parameter/line-width");
optgroup->append_single_option_line("symmetric_infill_y_axis");
optgroup->append_single_option_line("infill_shift_step");
optgroup->append_single_option_line("lattice_angle_1");
optgroup->append_single_option_line("lattice_angle_2");
optgroup->append_single_option_line("infill_overhang_angle");
optgroup->append_single_option_line("infill_anchor_max");
optgroup->append_single_option_line("infill_anchor");
optgroup->append_single_option_line("internal_solid_infill_pattern");
optgroup->append_single_option_line("solid_infill_direction");
optgroup->append_single_option_line("solid_infill_rotate_template");
optgroup->append_single_option_line("gap_fill_target");
optgroup->append_single_option_line("filter_out_gap_fill");
optgroup->append_single_option_line("infill_wall_overlap");
optgroup = page->new_optgroup(L("Advanced"), L"param_advanced");
optgroup->append_single_option_line("infill_direction");
optgroup->append_single_option_line("solid_infill_direction");
optgroup->append_single_option_line("rotate_solid_infill_direction");
optgroup->append_single_option_line("bridge_angle");
optgroup->append_single_option_line("internal_bridge_angle"); // ORCA: Internal bridge angle override
optgroup->append_single_option_line("minimum_sparse_infill_area");
@@ -2284,7 +2337,7 @@ void TabPrint::build()
//optgroup = page->new_optgroup(L("Options for support material and raft"));
// Support
// Support
optgroup = page->new_optgroup(L("Advanced"), L"param_advanced");
optgroup->append_single_option_line("support_top_z_distance", "support#top-z-distance");
optgroup->append_single_option_line("support_bottom_z_distance", "support#bottom-z-distance");
@@ -2320,7 +2373,7 @@ void TabPrint::build()
optgroup->append_single_option_line("tree_support_adaptive_layer_height");
optgroup->append_single_option_line("tree_support_auto_brim");
optgroup->append_single_option_line("tree_support_brim_width");
page = add_options_page(L("Multimaterial"), "custom-gcode_multi_material"); // ORCA: icon only visible on placeholders
optgroup = page->new_optgroup(L("Prime tower"), L"param_tower");
optgroup->append_single_option_line("enable_prime_tower");
@@ -2419,7 +2472,7 @@ page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only v
option.opt.multiline = true;
// option.opt.height = 5;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Post-processing Scripts"), L"param_gcode", 0);
option = optgroup->get_option("post_process");
option.opt.full_width = true;
@@ -2440,7 +2493,7 @@ page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only v
// create_line_with_widget(optgroup.get(), "compatible_printers", "", [this](wxWindow* parent) {
// return compatible_widget_create(parent, m_compatible_printers);
// });
// option = optgroup->get_option("compatible_printers_condition");
// option.opt.full_width = true;
// optgroup->append_single_option_line(option);
@@ -2849,7 +2902,7 @@ void TabPrintPlate::build()
auto page = add_options_page(L("Plate Settings"), "empty");
auto optgroup = page->new_optgroup("");
optgroup->append_single_option_line("curr_bed_type");
optgroup->append_single_option_line("skirt_start_angle");
optgroup->append_single_option_line("skirt_start_angle");
optgroup->append_single_option_line("print_sequence");
optgroup->append_single_option_line("spiral_mode");
optgroup->append_single_option_line("first_layer_sequence_choice");
@@ -3000,7 +3053,7 @@ void TabPrintPlate::notify_changed(ObjectBase* object)
for (auto item : items) {
if (objects_list->GetModel()->GetItemType(item) == itPlate) {
ObjectDataViewModelNode* node = static_cast<ObjectDataViewModelNode*>(item.GetID());
if (node)
if (node)
node->set_action_icon(!m_all_keys.empty());
}
}
@@ -3008,7 +3061,7 @@ void TabPrintPlate::notify_changed(ObjectBase* object)
void TabPrintPlate::update_custom_dirty()
{
for (auto k : m_null_keys)
for (auto k : m_null_keys)
m_options_list[k] = 0;
for (auto k : m_all_keys) {
if (k == "first_layer_sequence_choice" || k == "other_layers_sequence_choice") {
@@ -3250,9 +3303,9 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
std::vector<std::string> opt_keys = { "filament_retraction_length",
"filament_z_hop",
"filament_z_hop_types",
"filament_z_hop_types",
"filament_retract_lift_above",
"filament_retract_lift_below",
"filament_retract_lift_below",
"filament_retract_lift_enforce",
"filament_retraction_speed",
"filament_deretraction_speed",
@@ -3363,7 +3416,7 @@ void TabFilament::build()
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");
Option option = optgroup->get_option("adaptive_pressure_advance_model");
option.opt.full_width = true;
option.opt.is_code = true;
@@ -3675,7 +3728,7 @@ void TabFilament::toggle_options()
toggle_option(el, has_enable_overhang_bridge_fan);
toggle_option("additional_cooling_fan_speed", cfg.opt_bool("auxiliary_fan"));
// Orca: toggle dont slow down for external perimeters if
bool has_slow_down_for_layer_cooling = m_config->opt_bool("slow_down_for_layer_cooling", 0);
toggle_option("dont_slow_down_outer_wall", has_slow_down_for_layer_cooling);
@@ -3688,7 +3741,7 @@ void TabFilament::toggle_options()
//Orca: Enable the plates that should be visible when multi bed support is enabled or a BBL printer is selected; otherwise, enable only the plate visible for the selected bed type.
DynamicConfig& proj_cfg = m_preset_bundle->project_config;
std::string bed_temp_1st_layer_key = "";
if (proj_cfg.has("curr_bed_type"))
if (proj_cfg.has("curr_bed_type"))
{
bed_temp_1st_layer_key = get_bed_temp_1st_layer_key(proj_cfg.opt_enum<BedType>("curr_bed_type"));
}
@@ -3701,13 +3754,13 @@ void TabFilament::toggle_options()
bed_temp_keys.end() ||
is_BBL_printer || cfg.opt_bool("support_multi_bed_types");
for (const auto& key : bed_temp_keys)
for (const auto& key : bed_temp_keys)
{
toggle_line(key, support_multi_bed_types || bed_temp_1st_layer_key == key);
}
// Orca: adaptive pressure advance and calibration model
// If PA is not enabled, disable adaptive pressure advance and hide the model section
// If adaptive PA is not enabled, hide the adaptive PA model section
@@ -3891,7 +3944,7 @@ void TabPrinter::build_fff()
optgroup->append_single_option_line("use_firmware_retraction");
// optgroup->append_single_option_line("spaghetti_detector");
optgroup->append_single_option_line("time_cost");
optgroup = page->new_optgroup(L("Cooling Fan"), "param_cooling_fan");
Line line = Line{ L("Fan speed-up time"), optgroup->get_option("fan_speedup_time").opt.tooltip };
line.append_option(optgroup->get_option("fan_speedup_time"));
@@ -3954,8 +4007,8 @@ void TabPrinter::build_fff()
option.opt.is_code = true;
option.opt.height = gcode_field_height; // 150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Before layer change G-code"),"param_gcode", 0);
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);
@@ -3977,7 +4030,7 @@ void TabPrinter::build_fff()
option.opt.is_code = true;
option.opt.height = gcode_field_height;//150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Timelapse G-code"), L"param_gcode", 0);
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);
@@ -4172,7 +4225,7 @@ PageShp TabPrinter::build_kinematics_page()
}
auto optgroup = page->new_optgroup(L("Advanced"), "param_advanced");
optgroup->append_single_option_line("emit_machine_limits_to_gcode");
// resonance avoidance ported over from qidi slicer
optgroup = page->new_optgroup(L("Resonance Avoidance"));
optgroup->append_single_option_line("resonance_avoidance");
@@ -4711,7 +4764,7 @@ void TabPrinter::toggle_options()
toggle_option("long_retractions_when_cut", !use_firmware_retraction && m_config->opt_int("enable_long_retraction_when_cut"),i);
toggle_line("retraction_distances_when_cut#0", m_config->opt_bool("long_retractions_when_cut", i));
//toggle_option("retraction_distances_when_cut", m_config->opt_bool("long_retractions_when_cut",i),i);
toggle_option("travel_slope", m_config->opt_enum("z_hop_types", i) != ZHopType::zhtNormal, i);
}
@@ -5123,13 +5176,13 @@ bool Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
try {
//BBS delete preset
Preset &current_preset = m_presets->get_selected_preset();
// Obtain compatible filament and process presets for printers
if (m_preset_bundle && m_presets->get_preset_base(current_preset) == &current_preset && printer_tab && !current_preset.is_system) {
delete_third_printer = true;
for (const Preset &preset : m_preset_bundle->filaments.get_presets()) {
if (preset.is_compatible && !preset.is_default) {
if (preset.inherits() != "")
if (preset.inherits() != "")
filament_presets.push_front(preset);
else
filament_presets.push_back(preset);
@@ -5260,7 +5313,7 @@ bool Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
});
}
}
if (technology_changed)
@@ -5862,7 +5915,7 @@ void Tab::delete_preset()
//wxID_YES != wxMessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal())
wxID_YES == MessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal()))
return;
// if we just delete preset from the physical printer
if (m_presets_choice->is_selected_physical_printer()) {
PhysicalPrinter& printer = physical_printers.get_selected_printer();
@@ -5986,7 +6039,7 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
deps.checkbox->SetValue(state);
deps.btn->Enable(!state);
// All printers have been made compatible with this preset.
if (state)
if (state)
this->load_key_value(deps.key_list, std::vector<std::string> {});
this->get_field(deps.key_condition)->toggle(state);
this->update_changed_ui();
@@ -6145,7 +6198,7 @@ void TabPrinter::cache_extruder_cnt(const DynamicPrintConfig* config/* = nullptr
if (Preset::printer_technology(cached_config) == ptSLA)
return;
// get extruders count
// get extruders count
auto* nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(cached_config.option("nozzle_diameter"));
m_cache_extruder_count = nozzle_diameter->values.size(); //m_extruders_count;
}
+10 -11
View File
@@ -4,12 +4,6 @@
#include "../GUI_Utils.hpp"
#include "Label.hpp"
/*
Fix label overflowing to inner frame
Fix use elypsis if text too long
setmin size
*/
LabeledStaticBox::LabeledStaticBox()
: state_handler(this)
{
@@ -28,7 +22,6 @@ LabeledStaticBox::LabeledStaticBox()
std::make_pair(0xDBDBDB, (int) StateColor::Normal),
std::make_pair(0xDBDBDB, (int) StateColor::Disabled)
);
}
LabeledStaticBox::LabeledStaticBox(
@@ -63,11 +56,10 @@ bool LabeledStaticBox::Create(
m_pos = this->GetPosition();
int tW,tH,descent,externalLeading;
GetTextExtent("Yy", &tW, &tH, &descent, &externalLeading, &m_font);
// empty label sets m_label_height as 0 that causes extra spacing at top
GetTextExtent(m_label.IsEmpty() ? "Orca" : m_label, &tW, &tH, &descent, &externalLeading, &m_font);
m_label_height = tH - externalLeading;
GetTextExtent(m_label, &tW, &tH, &descent, &externalLeading, &m_font);
m_label_width = tW;
m_label_width = tW;
Bind(wxEVT_PAINT,([this](wxPaintEvent e) {
wxPaintDC dc(this);
@@ -178,4 +170,11 @@ void LabeledStaticBox::DrawBorderAndLabel(wxDC& dc)
dc.SetTextForeground(text_color.colorForStates(state_handler.states()));
dc.DrawText(m_label, wxPoint(10 * m_scale, 0));
}
}
void LabeledStaticBox::GetBordersForSizer(int* borderTop, int* borderOther) const {
wxStaticBox::GetBordersForSizer(borderTop, borderOther);
#ifdef __WXOSX__
*borderOther = 5; // Make sure macOS uses the same border padding as other platforms
#endif
}
@@ -63,6 +63,9 @@ protected:
int m_label_width;
float m_scale;
wxPoint m_pos;
void GetBordersForSizer(int *borderTop, int *borderOther) const override;
};
#endif // !slic3r_GUI_LabeledStaticBox_hpp_
+4 -4
View File
@@ -115,10 +115,10 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters)
update_ui(m_chart);
sizer_chart->Add(m_chart, 0, wxALL, 5);
m_widget_time = new SpinInput(this, wxEmptyString, _L("ms") , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 5000 , 3000, 500);
m_widget_volume = new SpinInput(this, wxEmptyString, _L("mm³"), wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 10000, 0 );
m_widget_ramming_line_width_multiplicator = new SpinInput(this, wxEmptyString, _L("%") , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 200 , 100 );
m_widget_ramming_step_multiplicator = new SpinInput(this, wxEmptyString, _L("%") , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 200 , 100 );
m_widget_time = new SpinInput(this, wxEmptyString, "ms" , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 5000 , 3000, 500);
m_widget_volume = new SpinInput(this, wxEmptyString, "mm³", wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 10000, 0 );
m_widget_ramming_line_width_multiplicator = new SpinInput(this, wxEmptyString, "%" , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 200 , 100 );
m_widget_ramming_step_multiplicator = new SpinInput(this, wxEmptyString, "%" , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 200 , 100 );
auto add_title = [this, sizer_param](wxString label){
auto title = new StaticLine(this, 0, label);
+15 -15
View File
@@ -306,7 +306,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
// start temp
auto start_temp_sizer = new wxBoxSizer(wxHORIZONTAL);
auto start_temp_text = new wxStaticText(this, wxID_ANY, start_temp_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStart = new TextInput(this, std::to_string(230), _L("\u2103"), "", wxDefaultPosition, ti_size);
m_tiStart = new TextInput(this, std::to_string(230), "\u2103" /* °C */, "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
start_temp_sizer->Add(start_temp_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
start_temp_sizer->Add(m_tiStart , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -315,7 +315,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
// end temp
auto end_temp_sizer = new wxBoxSizer(wxHORIZONTAL);
auto end_temp_text = new wxStaticText(this, wxID_ANY, end_temp_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiEnd = new TextInput(this, std::to_string(190), _L("\u2103"), "", wxDefaultPosition, ti_size);
m_tiEnd = new TextInput(this, std::to_string(190), "\u2103" /* °C */, "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
end_temp_sizer->Add(end_temp_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
end_temp_sizer->Add(m_tiEnd , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -324,7 +324,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
// temp step
auto temp_step_sizer = new wxBoxSizer(wxHORIZONTAL);
auto temp_step_text = new wxStaticText(this, wxID_ANY, temp_step_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStep = new TextInput(this, wxString::FromDouble(5),_L("\u2103"), "", wxDefaultPosition, ti_size);
m_tiStep = new TextInput(this, wxString::FromDouble(5),"\u2103" /* °C */, "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
m_tiStep->Enable(false);
temp_step_sizer->Add(temp_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -353,7 +353,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
if(!ti->GetTextCtrl()->GetValue().ToULong(&t))
return;
if(t> 350 || t < 170){
MessageDialog msg_dlg(nullptr, wxString::Format(L"Supported range: 170%s - 350%s",_L("\u2103"),_L("\u2103")), wxEmptyString, wxICON_WARNING | wxOK);
MessageDialog msg_dlg(nullptr, wxString::Format(L"Supported range: 170%s - 350%s","\u2103" /* °C */,"\u2103" /* °C */), wxEmptyString, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
if(t > 350)
t = 350;
@@ -479,7 +479,7 @@ MaxVolumetricSpeed_Test_Dlg::MaxVolumetricSpeed_Test_Dlg(wxWindow* parent, wxWin
// start vol
auto start_vol_sizer = new wxBoxSizer(wxHORIZONTAL);
auto start_vol_text = new wxStaticText(this, wxID_ANY, start_vol_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStart = new TextInput(this, std::to_string(5), _L("mm³/s"), "", wxDefaultPosition, ti_size);
m_tiStart = new TextInput(this, std::to_string(5), "mm³/s", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
start_vol_sizer->Add(start_vol_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -489,7 +489,7 @@ MaxVolumetricSpeed_Test_Dlg::MaxVolumetricSpeed_Test_Dlg(wxWindow* parent, wxWin
// end vol
auto end_vol_sizer = new wxBoxSizer(wxHORIZONTAL);
auto end_vol_text = new wxStaticText(this, wxID_ANY, end_vol_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiEnd = new TextInput(this, std::to_string(20), _L("mm³/s"), "", wxDefaultPosition, ti_size);
m_tiEnd = new TextInput(this, std::to_string(20), "mm³/s", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
end_vol_sizer->Add(end_vol_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
end_vol_sizer->Add(m_tiEnd , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -498,7 +498,7 @@ MaxVolumetricSpeed_Test_Dlg::MaxVolumetricSpeed_Test_Dlg(wxWindow* parent, wxWin
// vol step
auto vol_step_sizer = new wxBoxSizer(wxHORIZONTAL);
auto vol_step_text = new wxStaticText(this, wxID_ANY, vol_step_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStep = new TextInput(this, wxString::FromDouble(0.5), _L("mm³/s"), "", wxDefaultPosition, ti_size);
m_tiStep = new TextInput(this, wxString::FromDouble(0.5), "mm³/s", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
vol_step_sizer->Add(vol_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
vol_step_sizer->Add(m_tiStep , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -578,7 +578,7 @@ VFA_Test_Dlg::VFA_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
// start vol
auto start_vol_sizer = new wxBoxSizer(wxHORIZONTAL);
auto start_vol_text = new wxStaticText(this, wxID_ANY, start_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStart = new TextInput(this, std::to_string(40), _L("mm/s"), "", wxDefaultPosition, ti_size);
m_tiStart = new TextInput(this, std::to_string(40), "mm/s", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
start_vol_sizer->Add(start_vol_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -588,7 +588,7 @@ VFA_Test_Dlg::VFA_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
// end vol
auto end_vol_sizer = new wxBoxSizer(wxHORIZONTAL);
auto end_vol_text = new wxStaticText(this, wxID_ANY, end_vol_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiEnd = new TextInput(this, std::to_string(200), _L("mm/s"), "", wxDefaultPosition, ti_size);
m_tiEnd = new TextInput(this, std::to_string(200), "mm/s", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
end_vol_sizer->Add(end_vol_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
end_vol_sizer->Add(m_tiEnd , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -597,7 +597,7 @@ VFA_Test_Dlg::VFA_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
// vol step
auto vol_step_sizer = new wxBoxSizer(wxHORIZONTAL);
auto vol_step_text = new wxStaticText(this, wxID_ANY, vol_step_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStep = new TextInput(this, wxString::FromDouble(10), _L("mm/s"), "", wxDefaultPosition, ti_size);
m_tiStep = new TextInput(this, wxString::FromDouble(10), "mm/s", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
vol_step_sizer->Add(vol_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
vol_step_sizer->Add(m_tiStep , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -680,7 +680,7 @@ Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater
// start length
auto start_length_sizer = new wxBoxSizer(wxHORIZONTAL);
auto start_length_text = new wxStaticText(this, wxID_ANY, start_length_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStart = new TextInput(this, std::to_string(0), _L("mm"), "", wxDefaultPosition, ti_size);
m_tiStart = new TextInput(this, std::to_string(0), "mm", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
start_length_sizer->Add(start_length_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -690,7 +690,7 @@ Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater
// end length
auto end_length_sizer = new wxBoxSizer(wxHORIZONTAL);
auto end_length_text = new wxStaticText(this, wxID_ANY, end_length_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiEnd = new TextInput(this, std::to_string(2), _L("mm"), "", wxDefaultPosition, ti_size);
m_tiEnd = new TextInput(this, std::to_string(2), "mm", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
end_length_sizer->Add(end_length_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
end_length_sizer->Add(m_tiEnd , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -699,7 +699,7 @@ Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater
// length step
auto length_step_sizer = new wxBoxSizer(wxHORIZONTAL);
auto length_step_text = new wxStaticText(this, wxID_ANY, length_step_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiStep = new TextInput(this, wxString::FromDouble(0.1), _L("mm"), "", wxDefaultPosition, ti_size);
m_tiStep = new TextInput(this, wxString::FromDouble(0.1), "mm", "", wxDefaultPosition, ti_size);
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
length_step_sizer->Add(length_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
length_step_sizer->Add(m_tiStep , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -1043,7 +1043,7 @@ Junction_Deviation_Test_Dlg::Junction_Deviation_Test_Dlg(wxWindow* parent, wxWin
// Start junction deviation
auto start_jd_sizer = new wxBoxSizer(wxHORIZONTAL);
auto start_jd_text = new wxStaticText(this, wxID_ANY, start_jd_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiJDStart = new TextInput(this, wxString::Format("%.3f", 0.000), _L("mm"), "", wxDefaultPosition, ti_size);
m_tiJDStart = new TextInput(this, wxString::Format("%.3f", 0.000), "mm", "", wxDefaultPosition, ti_size);
m_tiJDStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
start_jd_sizer->Add(start_jd_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
start_jd_sizer->Add(m_tiJDStart , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
@@ -1052,7 +1052,7 @@ Junction_Deviation_Test_Dlg::Junction_Deviation_Test_Dlg(wxWindow* parent, wxWin
// End junction deviation
auto end_jd_sizer = new wxBoxSizer(wxHORIZONTAL);
auto end_jd_text = new wxStaticText(this, wxID_ANY, end_jd_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
m_tiJDEnd = new TextInput(this, wxString::Format("%.3f", 0.250), _L("mm"), "", wxDefaultPosition, ti_size);
m_tiJDEnd = new TextInput(this, wxString::Format("%.3f", 0.250), "mm", "", wxDefaultPosition, ti_size);
m_tiJDEnd->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
end_jd_sizer->Add(end_jd_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));
end_jd_sizer->Add(m_tiJDEnd , 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(2));